Index: stable/10/sys/conf/files.amd64 =================================================================== --- stable/10/sys/conf/files.amd64 (revision 301343) +++ stable/10/sys/conf/files.amd64 (revision 301344) @@ -1,626 +1,629 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # # linux32_genassym.o optional compat_linux32 \ dependency "$S/amd64/linux32/linux32_genassym.c" \ compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \ no-obj no-implicit-rule \ clean "linux32_genassym.o" # linux32_assym.h optional compat_linux32 \ dependency "$S/kern/genassym.sh linux32_genassym.o" \ compile-with "sh $S/kern/genassym.sh linux32_genassym.o > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "linux32_assym.h" # linux32_locore.o optional compat_linux32 \ dependency "linux32_assym.h $S/amd64/linux32/linux32_locore.s" \ compile-with "${CC} -x assembler-with-cpp -DLOCORE -m32 -shared -s -pipe -I. -I$S -Werror -Wall -fno-common -nostdinc -nostdlib -Wl,-T$S/amd64/linux32/linux32_vdso.lds.s -Wl,-soname=linux32_vdso.so,--eh-frame-hdr,-fPIC,-warn-common ${.IMPSRC} -o ${.TARGET}" \ no-obj no-implicit-rule \ clean "linux32_locore.o" # linux32_vdso.so optional compat_linux32 \ dependency "linux32_locore.o" \ compile-with "${OBJCOPY} --input-target binary --output-target elf64-x86-64-freebsd --binary-architecture i386 linux32_locore.o ${.TARGET}" \ no-implicit-rule \ clean "linux32_vdso.so" # ia32_genassym.o standard \ dependency "$S/compat/ia32/ia32_genassym.c" \ compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \ no-obj no-implicit-rule \ clean "ia32_genassym.o" # ia32_assym.h standard \ dependency "$S/kern/genassym.sh ia32_genassym.o" \ compile-with "env NM='${NM}' sh $S/kern/genassym.sh ia32_genassym.o > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "ia32_assym.h" # font.h optional sc_dflt_font \ compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'static u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'static u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'static u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" # atkbdmap.h optional atkbd_dflt_keymap \ compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${ATKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > atkbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "atkbdmap.h" # ukbdmap.h optional ukbd_dflt_keymap \ compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "ukbdmap.h" # nvenetlib.o optional nve pci \ dependency "$S/contrib/dev/nve/amd64/nvenetlib.o.bz2.uu" \ compile-with "uudecode $S/contrib/dev/nve/amd64/nvenetlib.o.bz2.uu ; bzip2 -df nvenetlib.o.bz2" \ no-implicit-rule # os+%DIKED-nve.h optional nve pci \ dependency "$S/contrib/dev/nve/os.h" \ compile-with "sed -e 's/^.*#include.*phy\.h.*$$//' $S/contrib/dev/nve/os.h > os+%DIKED-nve.h" \ no-implicit-rule no-obj before-depend \ clean "os+%DIKED-nve.h" # hpt27xx_lib.o optional hpt27xx \ dependency "$S/dev/hpt27xx/amd64-elf.hpt27xx_lib.o.uu" \ compile-with "uudecode < $S/dev/hpt27xx/amd64-elf.hpt27xx_lib.o.uu" \ no-implicit-rule # hptmvraid.o optional hptmv \ dependency "$S/dev/hptmv/amd64-elf.raid.o.uu" \ compile-with "uudecode < $S/dev/hptmv/amd64-elf.raid.o.uu" \ no-implicit-rule # hptnr_lib.o optional hptnr \ dependency "$S/dev/hptnr/amd64-elf.hptnr_lib.o.uu" \ compile-with "uudecode < $S/dev/hptnr/amd64-elf.hptnr_lib.o.uu" \ no-implicit-rule # hptrr_lib.o optional hptrr \ dependency "$S/dev/hptrr/amd64-elf.hptrr_lib.o.uu" \ compile-with "uudecode < $S/dev/hptrr/amd64-elf.hptrr_lib.o.uu" \ no-implicit-rule # amd64/acpica/acpi_machdep.c optional acpi acpi_wakecode.o optional acpi \ dependency "$S/amd64/acpica/acpi_wakecode.S assym.s" \ compile-with "${NORMAL_S}" \ no-obj no-implicit-rule before-depend \ clean "acpi_wakecode.o" acpi_wakecode.bin optional acpi \ dependency "acpi_wakecode.o" \ compile-with "${OBJCOPY} -S -O binary acpi_wakecode.o ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "acpi_wakecode.bin" acpi_wakecode.h optional acpi \ dependency "acpi_wakecode.bin" \ compile-with "file2c -sx 'static char wakecode[] = {' '};' < acpi_wakecode.bin > ${.TARGET}" \ no-obj no-implicit-rule before-depend \ clean "acpi_wakecode.h" acpi_wakedata.h optional acpi \ dependency "acpi_wakecode.o" \ compile-with '${NM} -n --defined-only acpi_wakecode.o | while read offset dummy what; do echo "#define $${what} 0x$${offset}"; done > ${.TARGET}' \ no-obj no-implicit-rule before-depend \ clean "acpi_wakedata.h" # amd64/amd64/amd64_mem.c optional mem #amd64/amd64/apic_vector.S standard amd64/amd64/atomic.c standard amd64/amd64/autoconf.c standard amd64/amd64/bios.c standard amd64/amd64/bpf_jit_machdep.c optional bpf_jitter amd64/amd64/cpu_switch.S standard amd64/amd64/db_disasm.c optional ddb amd64/amd64/db_interface.c optional ddb amd64/amd64/db_trace.c optional ddb amd64/amd64/elf_machdep.c standard amd64/amd64/exception.S standard amd64/amd64/fpu.c standard amd64/amd64/gdb_machdep.c optional gdb amd64/amd64/in_cksum.c optional inet | inet6 amd64/amd64/initcpu.c standard amd64/amd64/io.c optional io amd64/amd64/locore.S standard no-obj amd64/amd64/machdep.c standard amd64/amd64/mem.c optional mem amd64/amd64/minidump_machdep.c standard amd64/amd64/mp_machdep.c optional smp amd64/amd64/mp_watchdog.c optional mp_watchdog smp amd64/amd64/mpboot.S optional smp amd64/amd64/pmap.c standard amd64/amd64/prof_machdep.c optional profiling-routine amd64/amd64/ptrace_machdep.c standard amd64/amd64/sigtramp.S standard amd64/amd64/stack_machdep.c optional ddb | stack amd64/amd64/support.S standard amd64/amd64/sys_machdep.c standard amd64/amd64/trap.c standard amd64/amd64/uio_machdep.c standard amd64/amd64/uma_machdep.c standard amd64/amd64/vm_machdep.c standard amd64/pci/pci_cfgreg.c optional pci cddl/contrib/opensolaris/common/atomic/amd64/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" crypto/aesni/aeskeys_amd64.S optional aesni crypto/aesni/aesni.c optional aesni aesni_wrap.o optional aesni \ dependency "$S/crypto/aesni/aesni_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} -mmmx -msse -maes ${.IMPSRC}" \ no-implicit-rule \ clean "aesni_wrap.o" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb crypto/via/padlock.c optional padlock crypto/via/padlock_cipher.c optional padlock crypto/via/padlock_hash.c optional padlock dev/acpica/acpi_if.m standard dev/acpi_support/acpi_wmi_if.m standard dev/agp/agp_amd64.c optional agp dev/agp/agp_i810.c optional agp dev/agp/agp_via.c optional agp dev/amdsbwd/amdsbwd.c optional amdsbwd dev/amdtemp/amdtemp.c optional amdtemp dev/arcmsr/arcmsr.c optional arcmsr pci dev/asmc/asmc.c optional asmc isa dev/atkbdc/atkbd.c optional atkbd atkbdc dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc dev/atkbdc/atkbdc.c optional atkbdc dev/atkbdc/atkbdc_isa.c optional atkbdc isa dev/atkbdc/atkbdc_subr.c optional atkbdc dev/atkbdc/psm.c optional psm atkbdc dev/bxe/bxe.c optional bxe pci dev/bxe/bxe_stats.c optional bxe pci dev/bxe/bxe_debug.c optional bxe pci dev/bxe/ecore_sp.c optional bxe pci dev/bxe/bxe_elink.c optional bxe pci dev/bxe/57710_init_values.c optional bxe pci dev/bxe/57711_init_values.c optional bxe pci dev/bxe/57712_init_values.c optional bxe pci dev/coretemp/coretemp.c optional coretemp dev/cpuctl/cpuctl.c optional cpuctl dev/dpms/dpms.c optional dpms # There are no systems with isa slots, so all ed isa entries should go.. dev/ed/if_ed_3c503.c optional ed isa ed_3c503 dev/ed/if_ed_isa.c optional ed isa dev/ed/if_ed_wd80x3.c optional ed isa dev/ed/if_ed_hpp.c optional ed isa ed_hpp dev/ed/if_ed_sic.c optional ed isa ed_sic dev/fb/fb.c optional fb | vga dev/fb/s3_pci.c optional s3pci dev/fb/vesa.c optional vga vesa dev/fb/vga.c optional vga dev/ichwd/ichwd.c optional ichwd dev/if_ndis/if_ndis.c optional ndis dev/if_ndis/if_ndis_pccard.c optional ndis pccard dev/if_ndis/if_ndis_pci.c optional ndis cardbus | ndis pci dev/if_ndis/if_ndis_usb.c optional ndis usb dev/io/iodev.c optional io dev/ioat/ioat.c optional ioat pci dev/ioat/ioat_test.c optional ioat pci dev/ipmi/ipmi.c optional ipmi dev/ipmi/ipmi_acpi.c optional ipmi acpi dev/ipmi/ipmi_isa.c optional ipmi isa dev/ipmi/ipmi_kcs.c optional ipmi dev/ipmi/ipmi_smic.c optional ipmi dev/ipmi/ipmi_smbus.c optional ipmi smbus dev/ipmi/ipmi_smbios.c optional ipmi dev/ipmi/ipmi_ssif.c optional ipmi smbus dev/ipmi/ipmi_pci.c optional ipmi pci dev/ipmi/ipmi_linux.c optional ipmi compat_linux32 dev/ixl/if_ixl.c optional ixl pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/if_ixlv.c optional ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/ixlvc.c optional ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/ixl_txrx.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_osdep.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_lan_hmc.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_hmc.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_common.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_nvm.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_adminq.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/fdc/fdc.c optional fdc dev/fdc/fdc_acpi.c optional fdc dev/fdc/fdc_isa.c optional fdc isa dev/fdc/fdc_pccard.c optional fdc pccard dev/fdt/fdt_x86.c optional fdt dev/hpt27xx/hpt27xx_os_bsd.c optional hpt27xx dev/hpt27xx/hpt27xx_osm_bsd.c optional hpt27xx dev/hpt27xx/hpt27xx_config.c optional hpt27xx dev/hptmv/entry.c optional hptmv dev/hptmv/mv.c optional hptmv dev/hptmv/gui_lib.c optional hptmv dev/hptmv/hptproc.c optional hptmv dev/hptmv/ioctl.c optional hptmv dev/hptnr/hptnr_os_bsd.c optional hptnr dev/hptnr/hptnr_osm_bsd.c optional hptnr dev/hptnr/hptnr_config.c optional hptnr dev/hptrr/hptrr_os_bsd.c optional hptrr dev/hptrr/hptrr_osm_bsd.c optional hptrr dev/hptrr/hptrr_config.c optional hptrr dev/hwpmc/hwpmc_amd.c optional hwpmc dev/hwpmc/hwpmc_intel.c optional hwpmc dev/hwpmc/hwpmc_core.c optional hwpmc dev/hwpmc/hwpmc_uncore.c optional hwpmc dev/hwpmc/hwpmc_piv.c optional hwpmc dev/hwpmc/hwpmc_tsc.c optional hwpmc dev/hwpmc/hwpmc_x86.c optional hwpmc dev/hyperv/netvsc/hv_net_vsc.c optional hyperv dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c optional hyperv dev/hyperv/netvsc/hv_rndis_filter.c optional hyperv dev/hyperv/stordisengage/hv_ata_pci_disengage.c optional hyperv dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c optional hyperv dev/hyperv/utilities/hv_kvp.c optional hyperv dev/hyperv/utilities/hv_util.c optional hyperv dev/hyperv/vmbus/hv_channel.c optional hyperv dev/hyperv/vmbus/hv_channel_mgmt.c optional hyperv dev/hyperv/vmbus/hv_connection.c optional hyperv dev/hyperv/vmbus/hv_hv.c optional hyperv dev/hyperv/vmbus/hv_et.c optional hyperv dev/hyperv/vmbus/hv_ring_buffer.c optional hyperv dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c optional hyperv dev/kbd/kbd.c optional atkbd | sc | ukbd | vt dev/lindev/full.c optional lindev dev/lindev/lindev.c optional lindev dev/nfe/if_nfe.c optional nfe pci dev/ntb/if_ntb/if_ntb.c optional if_ntb dev/ntb/ntb_hw/ntb_hw.c optional if_ntb ntb_hw dev/nvd/nvd.c optional nvd nvme dev/nve/if_nve.c optional nve pci dev/nvme/nvme.c optional nvme dev/nvme/nvme_ctrlr.c optional nvme dev/nvme/nvme_ctrlr_cmd.c optional nvme dev/nvme/nvme_ns.c optional nvme dev/nvme/nvme_ns_cmd.c optional nvme dev/nvme/nvme_qpair.c optional nvme dev/nvme/nvme_sysctl.c optional nvme dev/nvme/nvme_test.c optional nvme dev/nvme/nvme_util.c optional nvme dev/nvram/nvram.c optional nvram isa dev/random/ivy.c optional rdrand_rng dev/random/nehemiah.c optional padlock_rng dev/qlxge/qls_dbg.c optional qlxge pci dev/qlxge/qls_dump.c optional qlxge pci dev/qlxge/qls_hw.c optional qlxge pci dev/qlxge/qls_ioctl.c optional qlxge pci dev/qlxge/qls_isr.c optional qlxge pci dev/qlxge/qls_os.c optional qlxge pci dev/qlxgb/qla_dbg.c optional qlxgb pci dev/qlxgb/qla_hw.c optional qlxgb pci dev/qlxgb/qla_ioctl.c optional qlxgb pci dev/qlxgb/qla_isr.c optional qlxgb pci dev/qlxgb/qla_misc.c optional qlxgb pci dev/qlxgb/qla_os.c optional qlxgb pci dev/qlxgbe/ql_dbg.c optional qlxgbe pci dev/qlxgbe/ql_hw.c optional qlxgbe pci dev/qlxgbe/ql_ioctl.c optional qlxgbe pci dev/qlxgbe/ql_isr.c optional qlxgbe pci dev/qlxgbe/ql_misc.c optional qlxgbe pci dev/qlxgbe/ql_os.c optional qlxgbe pci dev/qlxgbe/ql_reset.c optional qlxgbe pci +dev/sfxge/common/ef10_ev.c optional sfxge pci +dev/sfxge/common/ef10_filter.c optional sfxge pci +dev/sfxge/common/ef10_intr.c optional sfxge pci +dev/sfxge/common/ef10_mac.c optional sfxge pci +dev/sfxge/common/ef10_mcdi.c optional sfxge pci +dev/sfxge/common/ef10_nic.c optional sfxge pci +dev/sfxge/common/ef10_nvram.c optional sfxge pci +dev/sfxge/common/ef10_phy.c optional sfxge pci +dev/sfxge/common/ef10_rx.c optional sfxge pci +dev/sfxge/common/ef10_tx.c optional sfxge pci +dev/sfxge/common/ef10_vpd.c optional sfxge pci dev/sfxge/common/efx_bootcfg.c optional sfxge pci dev/sfxge/common/efx_crc32.c optional sfxge pci dev/sfxge/common/efx_ev.c optional sfxge pci dev/sfxge/common/efx_filter.c optional sfxge pci dev/sfxge/common/efx_hash.c optional sfxge pci dev/sfxge/common/efx_intr.c optional sfxge pci dev/sfxge/common/efx_lic.c optional sfxge pci dev/sfxge/common/efx_mac.c optional sfxge pci dev/sfxge/common/efx_mcdi.c optional sfxge pci dev/sfxge/common/efx_mon.c optional sfxge pci dev/sfxge/common/efx_nic.c optional sfxge pci dev/sfxge/common/efx_nvram.c optional sfxge pci dev/sfxge/common/efx_phy.c optional sfxge pci dev/sfxge/common/efx_port.c optional sfxge pci dev/sfxge/common/efx_rx.c optional sfxge pci dev/sfxge/common/efx_sram.c optional sfxge pci dev/sfxge/common/efx_tx.c optional sfxge pci dev/sfxge/common/efx_vpd.c optional sfxge pci dev/sfxge/common/efx_wol.c optional sfxge pci -dev/sfxge/common/hunt_ev.c optional sfxge pci -dev/sfxge/common/hunt_filter.c optional sfxge pci -dev/sfxge/common/hunt_intr.c optional sfxge pci -dev/sfxge/common/hunt_mac.c optional sfxge pci -dev/sfxge/common/hunt_mcdi.c optional sfxge pci dev/sfxge/common/hunt_nic.c optional sfxge pci -dev/sfxge/common/hunt_nvram.c optional sfxge pci dev/sfxge/common/hunt_phy.c optional sfxge pci -dev/sfxge/common/hunt_rx.c optional sfxge pci -dev/sfxge/common/hunt_tx.c optional sfxge pci -dev/sfxge/common/hunt_vpd.c optional sfxge pci +dev/sfxge/common/mcdi_mon.c optional sfxge pci dev/sfxge/common/medford_nic.c optional sfxge pci dev/sfxge/common/siena_mac.c optional sfxge pci dev/sfxge/common/siena_mcdi.c optional sfxge pci dev/sfxge/common/siena_nic.c optional sfxge pci dev/sfxge/common/siena_nvram.c optional sfxge pci dev/sfxge/common/siena_phy.c optional sfxge pci dev/sfxge/common/siena_sram.c optional sfxge pci dev/sfxge/common/siena_vpd.c optional sfxge pci dev/sfxge/sfxge.c optional sfxge pci dev/sfxge/sfxge_dma.c optional sfxge pci dev/sfxge/sfxge_ev.c optional sfxge pci dev/sfxge/sfxge_intr.c optional sfxge pci dev/sfxge/sfxge_mcdi.c optional sfxge pci dev/sfxge/sfxge_nvram.c optional sfxge pci dev/sfxge/sfxge_port.c optional sfxge pci dev/sfxge/sfxge_rx.c optional sfxge pci dev/sfxge/sfxge_tx.c optional sfxge pci dev/sio/sio.c optional sio dev/sio/sio_isa.c optional sio isa dev/sio/sio_pccard.c optional sio pccard dev/sio/sio_pci.c optional sio pci dev/sio/sio_puc.c optional sio puc dev/speaker/spkr.c optional speaker dev/syscons/apm/apm_saver.c optional apm_saver apm dev/syscons/scterm-teken.c optional sc dev/syscons/scvesactl.c optional sc vga vesa dev/syscons/scvgarndr.c optional sc vga dev/syscons/scvtb.c optional sc dev/tpm/tpm.c optional tpm dev/tpm/tpm_acpi.c optional tpm acpi dev/tpm/tpm_isa.c optional tpm isa dev/uart/uart_cpu_x86.c optional uart dev/viawd/viawd.c optional viawd dev/vmware/vmxnet3/if_vmx.c optional vmx dev/wbwd/wbwd.c optional wbwd dev/wpi/if_wpi.c optional wpi dev/isci/isci.c optional isci dev/isci/isci_controller.c optional isci dev/isci/isci_domain.c optional isci dev/isci/isci_interrupt.c optional isci dev/isci/isci_io_request.c optional isci dev/isci/isci_logger.c optional isci dev/isci/isci_oem_parameters.c optional isci dev/isci/isci_remote_device.c optional isci dev/isci/isci_sysctl.c optional isci dev/isci/isci_task_request.c optional isci dev/isci/isci_timer.c optional isci dev/isci/scil/sati.c optional isci dev/isci/scil/sati_abort_task_set.c optional isci dev/isci/scil/sati_atapi.c optional isci dev/isci/scil/sati_device.c optional isci dev/isci/scil/sati_inquiry.c optional isci dev/isci/scil/sati_log_sense.c optional isci dev/isci/scil/sati_lun_reset.c optional isci dev/isci/scil/sati_mode_pages.c optional isci dev/isci/scil/sati_mode_select.c optional isci dev/isci/scil/sati_mode_sense.c optional isci dev/isci/scil/sati_mode_sense_10.c optional isci dev/isci/scil/sati_mode_sense_6.c optional isci dev/isci/scil/sati_move.c optional isci dev/isci/scil/sati_passthrough.c optional isci dev/isci/scil/sati_read.c optional isci dev/isci/scil/sati_read_buffer.c optional isci dev/isci/scil/sati_read_capacity.c optional isci dev/isci/scil/sati_reassign_blocks.c optional isci dev/isci/scil/sati_report_luns.c optional isci dev/isci/scil/sati_request_sense.c optional isci dev/isci/scil/sati_start_stop_unit.c optional isci dev/isci/scil/sati_synchronize_cache.c optional isci dev/isci/scil/sati_test_unit_ready.c optional isci dev/isci/scil/sati_unmap.c optional isci dev/isci/scil/sati_util.c optional isci dev/isci/scil/sati_verify.c optional isci dev/isci/scil/sati_write.c optional isci dev/isci/scil/sati_write_and_verify.c optional isci dev/isci/scil/sati_write_buffer.c optional isci dev/isci/scil/sati_write_long.c optional isci dev/isci/scil/sci_abstract_list.c optional isci dev/isci/scil/sci_base_controller.c optional isci dev/isci/scil/sci_base_domain.c optional isci dev/isci/scil/sci_base_iterator.c optional isci dev/isci/scil/sci_base_library.c optional isci dev/isci/scil/sci_base_logger.c optional isci dev/isci/scil/sci_base_memory_descriptor_list.c optional isci dev/isci/scil/sci_base_memory_descriptor_list_decorator.c optional isci dev/isci/scil/sci_base_object.c optional isci dev/isci/scil/sci_base_observer.c optional isci dev/isci/scil/sci_base_phy.c optional isci dev/isci/scil/sci_base_port.c optional isci dev/isci/scil/sci_base_remote_device.c optional isci dev/isci/scil/sci_base_request.c optional isci dev/isci/scil/sci_base_state_machine.c optional isci dev/isci/scil/sci_base_state_machine_logger.c optional isci dev/isci/scil/sci_base_state_machine_observer.c optional isci dev/isci/scil/sci_base_subject.c optional isci dev/isci/scil/sci_util.c optional isci dev/isci/scil/scic_sds_controller.c optional isci dev/isci/scil/scic_sds_library.c optional isci dev/isci/scil/scic_sds_pci.c optional isci dev/isci/scil/scic_sds_phy.c optional isci dev/isci/scil/scic_sds_port.c optional isci dev/isci/scil/scic_sds_port_configuration_agent.c optional isci dev/isci/scil/scic_sds_remote_device.c optional isci dev/isci/scil/scic_sds_remote_node_context.c optional isci dev/isci/scil/scic_sds_remote_node_table.c optional isci dev/isci/scil/scic_sds_request.c optional isci dev/isci/scil/scic_sds_sgpio.c optional isci dev/isci/scil/scic_sds_smp_remote_device.c optional isci dev/isci/scil/scic_sds_smp_request.c optional isci dev/isci/scil/scic_sds_ssp_request.c optional isci dev/isci/scil/scic_sds_stp_packet_request.c optional isci dev/isci/scil/scic_sds_stp_remote_device.c optional isci dev/isci/scil/scic_sds_stp_request.c optional isci dev/isci/scil/scic_sds_unsolicited_frame_control.c optional isci dev/isci/scil/scif_sas_controller.c optional isci dev/isci/scil/scif_sas_controller_state_handlers.c optional isci dev/isci/scil/scif_sas_controller_states.c optional isci dev/isci/scil/scif_sas_domain.c optional isci dev/isci/scil/scif_sas_domain_state_handlers.c optional isci dev/isci/scil/scif_sas_domain_states.c optional isci dev/isci/scil/scif_sas_high_priority_request_queue.c optional isci dev/isci/scil/scif_sas_internal_io_request.c optional isci dev/isci/scil/scif_sas_io_request.c optional isci dev/isci/scil/scif_sas_io_request_state_handlers.c optional isci dev/isci/scil/scif_sas_io_request_states.c optional isci dev/isci/scil/scif_sas_library.c optional isci dev/isci/scil/scif_sas_remote_device.c optional isci dev/isci/scil/scif_sas_remote_device_ready_substate_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_ready_substates.c optional isci dev/isci/scil/scif_sas_remote_device_starting_substate_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_starting_substates.c optional isci dev/isci/scil/scif_sas_remote_device_state_handlers.c optional isci dev/isci/scil/scif_sas_remote_device_states.c optional isci dev/isci/scil/scif_sas_request.c optional isci dev/isci/scil/scif_sas_smp_activity_clear_affiliation.c optional isci dev/isci/scil/scif_sas_smp_io_request.c optional isci dev/isci/scil/scif_sas_smp_phy.c optional isci dev/isci/scil/scif_sas_smp_remote_device.c optional isci dev/isci/scil/scif_sas_stp_io_request.c optional isci dev/isci/scil/scif_sas_stp_remote_device.c optional isci dev/isci/scil/scif_sas_stp_task_request.c optional isci dev/isci/scil/scif_sas_task_request.c optional isci dev/isci/scil/scif_sas_task_request_state_handlers.c optional isci dev/isci/scil/scif_sas_task_request_states.c optional isci dev/isci/scil/scif_sas_timer.c optional isci dev/virtio/virtio.c optional virtio dev/virtio/virtqueue.c optional virtio dev/virtio/virtio_bus_if.m optional virtio dev/virtio/virtio_if.m optional virtio dev/virtio/pci/virtio_pci.c optional virtio_pci dev/virtio/network/if_vtnet.c optional vtnet dev/virtio/block/virtio_blk.c optional virtio_blk dev/virtio/balloon/virtio_balloon.c optional virtio_balloon dev/virtio/scsi/virtio_scsi.c optional virtio_scsi dev/virtio/random/virtio_random.c optional virtio_random dev/virtio/console/virtio_console.c optional virtio_console isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/imgact_binmisc.c optional imagact_binmisc kern/kern_clocksource.c standard kern/link_elf_obj.c standard # # IA32 binary support # #amd64/ia32/ia32_exception.S optional compat_freebsd32 amd64/ia32/ia32_reg.c optional compat_freebsd32 amd64/ia32/ia32_signal.c optional compat_freebsd32 amd64/ia32/ia32_sigtramp.S optional compat_freebsd32 amd64/ia32/ia32_syscall.c optional compat_freebsd32 amd64/ia32/ia32_misc.c optional compat_freebsd32 compat/ia32/ia32_sysvec.c optional compat_freebsd32 compat/linprocfs/linprocfs.c optional linprocfs compat/linsysfs/linsysfs.c optional linsysfs # # Linux/i386 binary support # amd64/linux32/linux32_dummy.c optional compat_linux32 amd64/linux32/linux32_machdep.c optional compat_linux32 amd64/linux32/linux32_support.s optional compat_linux32 \ dependency "linux32_assym.h" amd64/linux32/linux32_sysent.c optional compat_linux32 amd64/linux32/linux32_sysvec.c optional compat_linux32 compat/linux/linux_emul.c optional compat_linux32 compat/linux/linux_file.c optional compat_linux32 compat/linux/linux_fork.c optional compat_linux32 compat/linux/linux_futex.c optional compat_linux32 compat/linux/linux_getcwd.c optional compat_linux32 compat/linux/linux_ioctl.c optional compat_linux32 compat/linux/linux_ipc.c optional compat_linux32 compat/linux/linux_mib.c optional compat_linux32 compat/linux/linux_misc.c optional compat_linux32 compat/linux/linux_signal.c optional compat_linux32 compat/linux/linux_socket.c optional compat_linux32 compat/linux/linux_stats.c optional compat_linux32 compat/linux/linux_sysctl.c optional compat_linux32 compat/linux/linux_time.c optional compat_linux32 compat/linux/linux_timer.c optional compat_linux32 compat/linux/linux_uid16.c optional compat_linux32 compat/linux/linux_util.c optional compat_linux32 compat/linux/linux_vdso.c optional compat_linux32 compat/linux/linux_common.c optional compat_linux32 compat/linux/linux_event.c optional compat_linux32 compat/linux/linux.c optional compat_linux32 dev/amr/amr_linux.c optional compat_linux32 amr dev/mfi/mfi_linux.c optional compat_linux32 mfi # # Windows NDIS driver support # compat/ndis/kern_ndis.c optional ndisapi pci compat/ndis/kern_windrv.c optional ndisapi pci compat/ndis/subr_hal.c optional ndisapi pci compat/ndis/subr_ndis.c optional ndisapi pci compat/ndis/subr_ntoskrnl.c optional ndisapi pci compat/ndis/subr_pe.c optional ndisapi pci compat/ndis/subr_usbd.c optional ndisapi pci compat/ndis/winx64_wrap.S optional ndisapi pci # libkern/memmove.c standard libkern/memset.c standard # # x86 real mode BIOS emulator, required by dpms/vesa # compat/x86bios/x86bios.c optional x86bios | dpms | vesa contrib/x86emu/x86emu.c optional x86bios | dpms | vesa # # bvm console # dev/bvm/bvm_console.c optional bvmconsole dev/bvm/bvm_dbg.c optional bvmdebug # # x86 shared code between IA32, AMD64 and PC98 architectures # x86/acpica/OsdEnvironment.c optional acpi x86/acpica/acpi_apm.c optional acpi x86/acpica/acpi_wakeup.c optional acpi x86/acpica/madt.c optional acpi x86/acpica/srat.c optional acpi x86/bios/smbios.c optional smbios x86/bios/vpd.c optional vpd x86/cpufreq/powernow.c optional cpufreq x86/cpufreq/est.c optional cpufreq x86/cpufreq/hwpstate.c optional cpufreq x86/cpufreq/p4tcc.c optional cpufreq x86/iommu/busdma_dmar.c optional acpi acpi_dmar pci x86/iommu/intel_ctx.c optional acpi acpi_dmar pci x86/iommu/intel_drv.c optional acpi acpi_dmar pci x86/iommu/intel_fault.c optional acpi acpi_dmar pci x86/iommu/intel_gas.c optional acpi acpi_dmar pci x86/iommu/intel_idpgtbl.c optional acpi acpi_dmar pci x86/iommu/intel_qi.c optional acpi acpi_dmar pci x86/iommu/intel_quirks.c optional acpi acpi_dmar pci x86/iommu/intel_utils.c optional acpi acpi_dmar pci x86/isa/atpic.c optional atpic isa x86/isa/atrtc.c standard x86/isa/clock.c standard x86/isa/elcr.c optional atpic isa | mptable x86/isa/isa.c standard x86/isa/isa_dma.c standard x86/isa/nmi.c standard x86/isa/orm.c optional isa x86/pci/pci_bus.c optional pci x86/pci/qpi.c optional pci x86/x86/bus_machdep.c standard x86/x86/busdma_bounce.c standard x86/x86/busdma_machdep.c standard x86/x86/dump_machdep.c standard x86/x86/fdt_machdep.c optional fdt x86/x86/identcpu.c standard x86/x86/intr_machdep.c standard x86/x86/io_apic.c standard x86/x86/legacy.c standard x86/x86/local_apic.c standard x86/x86/mca.c standard x86/x86/mptable.c optional mptable x86/x86/mptable_pci.c optional mptable pci x86/x86/msi.c optional pci x86/x86/nexus.c standard x86/x86/tsc.c standard x86/xen/hvm.c optional xenhvm x86/xen/xen_intr.c optional xen | xenhvm Index: stable/10/sys/dev/sfxge/common/hunt_vpd.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_vpd.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_vpd.c (nonexistent) @@ -1,463 +0,0 @@ -/*- - * Copyright (c) 2009-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_VPD - -#if EFSYS_OPT_HUNTINGTON - -#include "ef10_tlv_layout.h" - - __checkReturn efx_rc_t -ef10_vpd_init( - __in efx_nic_t *enp) -{ - caddr_t svpd; - size_t svpd_size; - uint32_t pci_pf; - uint32_t tag; - efx_rc_t rc; - - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (enp->en_nic_cfg.enc_vpd_is_global) { - tag = TLV_TAG_GLOBAL_STATIC_VPD; - } else { - pci_pf = enp->en_nic_cfg.enc_pf; - tag = TLV_TAG_PF_STATIC_VPD(pci_pf); - } - - /* - * The VPD interface exposes VPD resources from the combined static and - * dynamic VPD storage. As the static VPD configuration should *never* - * change, we can cache it. - */ - svpd = NULL; - svpd_size = 0; - rc = ef10_nvram_partn_read_tlv(enp, - NVRAM_PARTITION_TYPE_STATIC_CONFIG, - tag, &svpd, &svpd_size); - if (rc != 0) { - if (rc == EACCES) { - /* Unprivileged functions cannot access VPD */ - goto out; - } - goto fail1; - } - - if (svpd != NULL && svpd_size > 0) { - if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) - goto fail2; - } - - enp->en_arch.ef10.ena_svpd = svpd; - enp->en_arch.ef10.ena_svpd_length = svpd_size; - -out: - return (0); - -fail2: - EFSYS_PROBE(fail2); - - EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_size( - __in efx_nic_t *enp, - __out size_t *sizep) -{ - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * This function returns the total size the user should allocate - * for all VPD operations. We've already cached the static vpd, - * so we just need to return an upper bound on the dynamic vpd, - * which is the size of the DYNAMIC_CONFIG partition. - */ - if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, - sizep, NULL, NULL, NULL)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_read( - __in efx_nic_t *enp, - __out_bcount(size) caddr_t data, - __in size_t size) -{ - caddr_t dvpd; - size_t dvpd_size; - uint32_t pci_pf; - uint32_t tag; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (enp->en_nic_cfg.enc_vpd_is_global) { - tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; - } else { - pci_pf = enp->en_nic_cfg.enc_pf; - tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); - } - - if ((rc = ef10_nvram_partn_read_tlv(enp, - NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, - tag, &dvpd, &dvpd_size)) != 0) - goto fail1; - - if (dvpd_size > size) { - rc = ENOSPC; - goto fail2; - } - memcpy(data, dvpd, dvpd_size); - - /* Pad data with all-1s, consistent with update operations */ - memset(data + dvpd_size, 0xff, size - dvpd_size); - - EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); - - return (0); - -fail2: - EFSYS_PROBE(fail2); - - EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_verify( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size) -{ - efx_vpd_tag_t stag; - efx_vpd_tag_t dtag; - efx_vpd_keyword_t skey; - efx_vpd_keyword_t dkey; - unsigned int scont; - unsigned int dcont; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * Strictly you could take the view that dynamic vpd is optional. - * Instead, to conform more closely to the read/verify/reinit() - * paradigm, we require dynamic vpd. ef10_vpd_reinit() will - * reinitialize it as required. - */ - if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) - goto fail1; - - /* - * Verify that there is no duplication between the static and - * dynamic cfg sectors. - */ - if (enp->en_arch.ef10.ena_svpd_length == 0) - goto done; - - dcont = 0; - _NOTE(CONSTANTCONDITION) - while (1) { - if ((rc = efx_vpd_hunk_next(data, size, &dtag, - &dkey, NULL, NULL, &dcont)) != 0) - goto fail2; - if (dcont == 0) - break; - - /* - * Skip the RV keyword. It should be present in both the static - * and dynamic cfg sectors. - */ - if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V')) - continue; - - scont = 0; - _NOTE(CONSTANTCONDITION) - while (1) { - if ((rc = efx_vpd_hunk_next( - enp->en_arch.ef10.ena_svpd, - enp->en_arch.ef10.ena_svpd_length, &stag, &skey, - NULL, NULL, &scont)) != 0) - goto fail3; - if (scont == 0) - break; - - if (stag == dtag && skey == dkey) { - rc = EEXIST; - goto fail4; - } - } - } - -done: - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_reinit( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size) -{ - boolean_t wantpid; - efx_rc_t rc; - - /* - * Only create an ID string if the dynamic cfg doesn't have one - */ - if (enp->en_arch.ef10.ena_svpd_length == 0) - wantpid = B_TRUE; - else { - unsigned int offset; - uint8_t length; - - rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, - enp->en_arch.ef10.ena_svpd_length, - EFX_VPD_ID, 0, &offset, &length); - if (rc == 0) - wantpid = B_FALSE; - else if (rc == ENOENT) - wantpid = B_TRUE; - else - goto fail1; - } - - if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_get( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size, - __inout efx_vpd_value_t *evvp) -{ - unsigned int offset; - uint8_t length; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Attempt to satisfy the request from svpd first */ - if (enp->en_arch.ef10.ena_svpd_length > 0) { - if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, - enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, - evvp->evv_keyword, &offset, &length)) == 0) { - evvp->evv_length = length; - memcpy(evvp->evv_value, - enp->en_arch.ef10.ena_svpd + offset, length); - return (0); - } else if (rc != ENOENT) - goto fail1; - } - - /* And then from the provided data buffer */ - if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, - evvp->evv_keyword, &offset, &length)) != 0) - goto fail2; - - evvp->evv_length = length; - memcpy(evvp->evv_value, data + offset, length); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_set( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size, - __in efx_vpd_value_t *evvp) -{ - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* If the provided (tag,keyword) exists in svpd, then it is readonly */ - if (enp->en_arch.ef10.ena_svpd_length > 0) { - unsigned int offset; - uint8_t length; - - if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, - enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, - evvp->evv_keyword, &offset, &length)) == 0) { - rc = EACCES; - goto fail1; - } - } - - if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_vpd_next( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size, - __out efx_vpd_value_t *evvp, - __inout unsigned int *contp) -{ - _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) - - return (ENOTSUP); -} - - __checkReturn efx_rc_t -ef10_vpd_write( - __in efx_nic_t *enp, - __in_bcount(size) caddr_t data, - __in size_t size) -{ - size_t vpd_length; - uint32_t pci_pf; - uint32_t tag; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (enp->en_nic_cfg.enc_vpd_is_global) { - tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; - } else { - pci_pf = enp->en_nic_cfg.enc_pf; - tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); - } - - /* Determine total length of new dynamic VPD */ - if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) - goto fail1; - - /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ - if ((rc = ef10_nvram_partn_write_segment_tlv(enp, - NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, - tag, data, vpd_length, B_TRUE)) != 0) { - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_vpd_fini( - __in efx_nic_t *enp) -{ - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (enp->en_arch.ef10.ena_svpd_length > 0) { - EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length, - enp->en_arch.ef10.ena_svpd); - - enp->en_arch.ef10.ena_svpd = NULL; - enp->en_arch.ef10.ena_svpd_length = 0; - } -} - -#endif /* EFSYS_OPT_HUNTINGTON */ - -#endif /* EFSYS_OPT_VPD */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_vpd.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_mcdi.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_mcdi.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_mcdi.c (nonexistent) @@ -1,303 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD - -#if EFSYS_OPT_MCDI - -#ifndef WITH_MCDI_V2 -#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands." -#endif - - - __checkReturn efx_rc_t -ef10_mcdi_init( - __in efx_nic_t *enp, - __in const efx_mcdi_transport_t *emtp) -{ - efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - efsys_mem_t *esmp = emtp->emt_dma_mem; - efx_dword_t dword; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); - - /* - * All EF10 firmware supports MCDIv2 and MCDIv1. - * Medford BootROM supports MCDIv2 and MCDIv1. - * Huntington BootROM supports MCDIv1 only. - */ - emip->emi_max_version = 2; - - /* A host DMA buffer is required for EF10 MCDI */ - if (esmp == NULL) { - rc = EINVAL; - goto fail1; - } - - /* - * Ensure that the MC doorbell is in a known state before issuing MCDI - * commands. The recovery algorithm requires that the MC command buffer - * must be 256 byte aligned. See bug24769. - */ - if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { - rc = EINVAL; - goto fail2; - } - EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); - EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); - - /* Save initial MC reboot status */ - (void) ef10_mcdi_poll_reboot(enp); - - /* Start a new epoch (allow fresh MCDI requests to succeed) */ - efx_mcdi_new_epoch(enp); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_mcdi_fini( - __in efx_nic_t *enp) -{ - efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - - emip->emi_new_epoch = B_FALSE; -} - - void -ef10_mcdi_send_request( - __in efx_nic_t *enp, - __in void *hdrp, - __in size_t hdr_len, - __in void *sdup, - __in size_t sdu_len) -{ - const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; - efsys_mem_t *esmp = emtp->emt_dma_mem; - efx_dword_t dword; - unsigned int pos; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Write the header */ - for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) { - dword = *(efx_dword_t *)((uint8_t *)hdrp + pos); - EFSYS_MEM_WRITED(esmp, pos, &dword); - } - - /* Write the payload */ - for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { - dword = *(efx_dword_t *)((uint8_t *)sdup + pos); - EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword); - } - - /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ - EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len); - EFSYS_PIO_WRITE_BARRIER(); - - /* Ring the doorbell to post the command DMA address to the MC */ - EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, - EFSYS_MEM_ADDR(esmp) >> 32); - EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); - - EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, - EFSYS_MEM_ADDR(esmp) & 0xffffffff); - EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); -} - - __checkReturn boolean_t -ef10_mcdi_poll_response( - __in efx_nic_t *enp) -{ - const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; - efsys_mem_t *esmp = emtp->emt_dma_mem; - efx_dword_t hdr; - - EFSYS_MEM_READD(esmp, 0, &hdr); - return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); -} - - void -ef10_mcdi_read_response( - __in efx_nic_t *enp, - __out_bcount(length) void *bufferp, - __in size_t offset, - __in size_t length) -{ - const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; - efsys_mem_t *esmp = emtp->emt_dma_mem; - unsigned int pos; - efx_dword_t data; - - for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { - EFSYS_MEM_READD(esmp, offset + pos, &data); - memcpy((uint8_t *)bufferp + pos, &data, - MIN(sizeof (data), length - pos)); - } -} - - efx_rc_t -ef10_mcdi_poll_reboot( - __in efx_nic_t *enp) -{ - efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - efx_dword_t dword; - uint32_t old_status; - uint32_t new_status; - efx_rc_t rc; - - old_status = emip->emi_mc_reboot_status; - - /* Update MC reboot status word */ - EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); - new_status = dword.ed_u32[0]; - - /* MC has rebooted if the value has changed */ - if (new_status != old_status) { - emip->emi_mc_reboot_status = new_status; - - /* - * FIXME: Ignore detected MC REBOOT for now. - * - * The Siena support for checking for MC reboot from status - * flags is broken - see comments in siena_mcdi_poll_reboot(). - * As the generic MCDI code is shared the EF10 reboot - * detection suffers similar problems. - * - * Do not report an error when the boot status changes until - * this can be handled by common code drivers (and reworked to - * support Siena too). - */ - if (B_FALSE) { - rc = EIO; - goto fail1; - } - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mcdi_feature_supported( - __in efx_nic_t *enp, - __in efx_mcdi_feature_id_t id, - __out boolean_t *supportedp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t privilege_mask = encp->enc_privilege_mask; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * Use privilege mask state at MCDI attach. - */ - - switch (id) { - case EFX_MCDI_FEATURE_FW_UPDATE: - /* - * Admin privilege must be used prior to introduction of - * specific flag. - */ - *supportedp = - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); - break; - case EFX_MCDI_FEATURE_LINK_CONTROL: - /* - * Admin privilege used prior to introduction of - * specific flag. - */ - *supportedp = - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); - break; - case EFX_MCDI_FEATURE_MACADDR_CHANGE: - /* - * Admin privilege must be used prior to introduction of - * mac spoofing privilege (at v4.6), which is used up to - * introduction of change mac spoofing privilege (at v4.7) - */ - *supportedp = - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); - break; - case EFX_MCDI_FEATURE_MAC_SPOOFING: - /* - * Admin privilege must be used prior to introduction of - * mac spoofing privilege (at v4.6), which is used up to - * introduction of mac spoofing TX privilege (at v4.7) - */ - *supportedp = - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || - EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); - break; - default: - rc = ENOTSUP; - goto fail1; - break; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -#endif /* EFSYS_OPT_MCDI */ - -#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_mcdi.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_intr.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_intr.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_intr.c (nonexistent) @@ -1,200 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_HUNTINGTON - - __checkReturn efx_rc_t -ef10_intr_init( - __in efx_nic_t *enp, - __in efx_intr_type_t type, - __in efsys_mem_t *esmp) -{ - _NOTE(ARGUNUSED(enp, type, esmp)) - return (0); -} - - - void -ef10_intr_enable( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - - - void -ef10_intr_disable( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - - - void -ef10_intr_disable_unlocked( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - - -static __checkReturn efx_rc_t -efx_mcdi_trigger_interrupt( - __in efx_nic_t *enp, - __in unsigned int level) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_TRIGGER_INTERRUPT_IN_LEN, - MC_CMD_TRIGGER_INTERRUPT_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (level >= enp->en_nic_cfg.enc_intr_limit) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_TRIGGER_INTERRUPT; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_TRIGGER_INTERRUPT_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_TRIGGER_INTERRUPT_OUT_LEN; - - MCDI_IN_SET_DWORD(req, TRIGGER_INTERRUPT_IN_INTR_LEVEL, level); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_intr_trigger( - __in efx_nic_t *enp, - __in unsigned int level) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_rc_t rc; - - if (encp->enc_bug41750_workaround) { - /* - * bug 41750: Test interrupts don't work on Greenport - * bug 50084: Test interrupts don't work on VFs - */ - rc = ENOTSUP; - goto fail1; - } - - if ((rc = efx_mcdi_trigger_interrupt(enp, level)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_intr_status_line( - __in efx_nic_t *enp, - __out boolean_t *fatalp, - __out uint32_t *qmaskp) -{ - efx_dword_t dword; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Read the queue mask and implicitly acknowledge the interrupt. */ - EFX_BAR_READD(enp, ER_DZ_BIU_INT_ISR_REG, &dword, B_FALSE); - *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); - - EFSYS_PROBE1(qmask, uint32_t, *qmaskp); - - *fatalp = B_FALSE; -} - - void -ef10_intr_status_message( - __in efx_nic_t *enp, - __in unsigned int message, - __out boolean_t *fatalp) -{ - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - _NOTE(ARGUNUSED(enp, message)) - - /* EF10 fatal errors are reported via events */ - *fatalp = B_FALSE; -} - - void -ef10_intr_fatal( - __in efx_nic_t *enp) -{ - /* EF10 fatal errors are reported via events */ - _NOTE(ARGUNUSED(enp)) -} - - void -ef10_intr_fini( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_intr.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_rx.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_rx.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_rx.c (nonexistent) @@ -1,826 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_HUNTINGTON - - -static __checkReturn efx_rc_t -efx_mcdi_init_rxq( - __in efx_nic_t *enp, - __in uint32_t size, - __in uint32_t target_evq, - __in uint32_t label, - __in uint32_t instance, - __in efsys_mem_t *esmp, - __in boolean_t disable_scatter) -{ - efx_mcdi_req_t req; - uint8_t payload[ - MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)), - MC_CMD_INIT_RXQ_OUT_LEN)]; - int npages = EFX_RXQ_NBUFS(size); - int i; - efx_qword_t *dma_addr; - uint64_t addr; - efx_rc_t rc; - - EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_INIT_RXQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages); - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance); - MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS, - INIT_RXQ_IN_FLAG_BUFF_MODE, 0, - INIT_RXQ_IN_FLAG_HDR_SPLIT, 0, - INIT_RXQ_IN_FLAG_TIMESTAMP, 0, - INIT_RXQ_IN_CRC_MODE, 0, - INIT_RXQ_IN_FLAG_PREFIX, 1, - INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); - - dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); - addr = EFSYS_MEM_ADDR(esmp); - - for (i = 0; i < npages; i++) { - EFX_POPULATE_QWORD_2(*dma_addr, - EFX_DWORD_1, (uint32_t)(addr >> 32), - EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); - - dma_addr++; - addr += EFX_BUF_SIZE; - } - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_fini_rxq( - __in efx_nic_t *enp, - __in uint32_t instance) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN, - MC_CMD_FINI_RXQ_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FINI_RXQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance); - - efx_mcdi_execute(enp, &req); - - if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -#if EFSYS_OPT_RX_SCALE -static __checkReturn efx_rc_t -efx_mcdi_rss_context_alloc( - __in efx_nic_t *enp, - __in efx_rx_scale_support_t scale_support, - __in uint32_t num_queues, - __out uint32_t *rss_contextp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN, - MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)]; - uint32_t rss_context; - uint32_t context_type; - efx_rc_t rc; - - if (num_queues > EFX_MAXRSS) { - rc = EINVAL; - goto fail1; - } - - switch (scale_support) { - case EFX_RX_SCALE_EXCLUSIVE: - context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE; - break; - case EFX_RX_SCALE_SHARED: - context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED; - break; - default: - rc = EINVAL; - goto fail2; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN; - - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, - EVB_PORT_ID_ASSIGNED); - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type); - /* NUM_QUEUES is only used to validate indirection table offsets */ - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail3; - } - - if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) { - rc = EMSGSIZE; - goto fail4; - } - - rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); - if (rss_context == EF10_RSS_CONTEXT_INVALID) { - rc = ENOENT; - goto fail5; - } - - *rss_contextp = rss_context; - - return (0); - -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE -static efx_rc_t -efx_mcdi_rss_context_free( - __in efx_nic_t *enp, - __in uint32_t rss_context) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN, - MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)]; - efx_rc_t rc; - - if (rss_context == EF10_RSS_CONTEXT_INVALID) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN; - - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE -static efx_rc_t -efx_mcdi_rss_context_set_flags( - __in efx_nic_t *enp, - __in uint32_t rss_context, - __in efx_rx_hash_type_t type) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN, - MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)]; - efx_rc_t rc; - - if (rss_context == EF10_RSS_CONTEXT_INVALID) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN; - - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, - rss_context); - - MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, - RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN, - (type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0, - RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN, - (type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0, - RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN, - (type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0, - RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN, - (type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE -static efx_rc_t -efx_mcdi_rss_context_set_key( - __in efx_nic_t *enp, - __in uint32_t rss_context, - __in_ecount(n) uint8_t *key, - __in size_t n) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN, - MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)]; - efx_rc_t rc; - - if (rss_context == EF10_RSS_CONTEXT_INVALID) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN; - - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID, - rss_context); - - EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); - if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) { - rc = EINVAL; - goto fail2; - } - - memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY), - key, n); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE -static efx_rc_t -efx_mcdi_rss_context_set_table( - __in efx_nic_t *enp, - __in uint32_t rss_context, - __in_ecount(n) unsigned int *table, - __in size_t n) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN, - MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)]; - uint8_t *req_table; - int i, rc; - - if (rss_context == EF10_RSS_CONTEXT_INVALID) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN; - - MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID, - rss_context); - - req_table = - MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE); - - for (i = 0; - i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN; - i++) { - req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0; - } - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - - - __checkReturn efx_rc_t -ef10_rx_init( - __in efx_nic_t *enp) -{ -#if EFSYS_OPT_RX_SCALE - - if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS, - &enp->en_rss_context) == 0) { - /* - * Allocated an exclusive RSS context, which allows both the - * indirection table and key to be modified. - */ - enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE; - enp->en_hash_support = EFX_RX_HASH_AVAILABLE; - } else { - /* - * Failed to allocate an exclusive RSS context. Continue - * operation without support for RSS. The pseudo-header in - * received packets will not contain a Toeplitz hash value. - */ - enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; - enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE; - } - -#endif /* EFSYS_OPT_RX_SCALE */ - - return (0); -} - -#if EFSYS_OPT_RX_SCATTER - __checkReturn efx_rc_t -ef10_rx_scatter_enable( - __in efx_nic_t *enp, - __in unsigned int buf_size) -{ - _NOTE(ARGUNUSED(enp, buf_size)) - return (0); -} -#endif /* EFSYS_OPT_RX_SCATTER */ - -#if EFSYS_OPT_RX_SCALE - __checkReturn efx_rc_t -ef10_rx_scale_mode_set( - __in efx_nic_t *enp, - __in efx_rx_hash_alg_t alg, - __in efx_rx_hash_type_t type, - __in boolean_t insert) -{ - efx_rc_t rc; - - EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ); - EFSYS_ASSERT3U(insert, ==, B_TRUE); - - if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) { - rc = EINVAL; - goto fail1; - } - - if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { - rc = ENOTSUP; - goto fail2; - } - - if ((rc = efx_mcdi_rss_context_set_flags(enp, - enp->en_rss_context, type)) != 0) - goto fail3; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE - __checkReturn efx_rc_t -ef10_rx_scale_key_set( - __in efx_nic_t *enp, - __in_ecount(n) uint8_t *key, - __in size_t n) -{ - efx_rc_t rc; - - if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { - rc = ENOTSUP; - goto fail1; - } - - if ((rc = efx_mcdi_rss_context_set_key(enp, - enp->en_rss_context, key, n)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - -#if EFSYS_OPT_RX_SCALE - __checkReturn efx_rc_t -ef10_rx_scale_tbl_set( - __in efx_nic_t *enp, - __in_ecount(n) unsigned int *table, - __in size_t n) -{ - efx_rc_t rc; - - if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { - rc = ENOTSUP; - goto fail1; - } - - if ((rc = efx_mcdi_rss_context_set_table(enp, - enp->en_rss_context, table, n)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} -#endif /* EFSYS_OPT_RX_SCALE */ - - -/* - * EF10 RX pseudo-header - * --------------------- - * - * Receive packets are prefixed by an (optional) 14 byte pseudo-header: - * - * +00: Toeplitz hash value. - * (32bit little-endian) - * +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag. - * (16bit big-endian) - * +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag. - * (16bit big-endian) - * +08: Packet Length. Zero if the RX datapath was in cut-through mode. - * (16bit little-endian) - * +10: MAC timestamp. Zero if timestamping is not enabled. - * (32bit little-endian) - * - * See "The RX Pseudo-header" in SF-109306-TC. - */ - - __checkReturn efx_rc_t -ef10_rx_prefix_pktlen( - __in efx_nic_t *enp, - __in uint8_t *buffer, - __out uint16_t *lengthp) -{ - /* - * The RX pseudo-header contains the packet length, excluding the - * pseudo-header. If the hardware receive datapath was operating in - * cut-through mode then the length in the RX pseudo-header will be - * zero, and the packet length must be obtained from the DMA length - * reported in the RX event. - */ - *lengthp = buffer[8] | (buffer[9] << 8); - return (0); -} - -#if EFSYS_OPT_RX_SCALE - __checkReturn uint32_t -ef10_rx_prefix_hash( - __in efx_nic_t *enp, - __in efx_rx_hash_alg_t func, - __in uint8_t *buffer) -{ - switch (func) { - case EFX_RX_HASHALG_TOEPLITZ: - return (buffer[0] | - (buffer[1] << 8) | - (buffer[2] << 16) | - (buffer[3] << 24)); - - default: - EFSYS_ASSERT(0); - return (0); - } -} -#endif /* EFSYS_OPT_RX_SCALE */ - - void -ef10_rx_qpost( - __in efx_rxq_t *erp, - __in_ecount(n) efsys_dma_addr_t *addrp, - __in size_t size, - __in unsigned int n, - __in unsigned int completed, - __in unsigned int added) -{ - efx_qword_t qword; - unsigned int i; - unsigned int offset; - unsigned int id; - - /* The client driver must not overfill the queue */ - EFSYS_ASSERT3U(added - completed + n, <=, - EFX_RXQ_LIMIT(erp->er_mask + 1)); - - id = added & (erp->er_mask); - for (i = 0; i < n; i++) { - EFSYS_PROBE4(rx_post, unsigned int, erp->er_index, - unsigned int, id, efsys_dma_addr_t, addrp[i], - size_t, size); - - EFX_POPULATE_QWORD_3(qword, - ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size), - ESF_DZ_RX_KER_BUF_ADDR_DW0, - (uint32_t)(addrp[i] & 0xffffffff), - ESF_DZ_RX_KER_BUF_ADDR_DW1, - (uint32_t)(addrp[i] >> 32)); - - offset = id * sizeof (efx_qword_t); - EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword); - - id = (id + 1) & (erp->er_mask); - } -} - - void -ef10_rx_qpush( - __in efx_rxq_t *erp, - __in unsigned int added, - __inout unsigned int *pushedp) -{ - efx_nic_t *enp = erp->er_enp; - unsigned int pushed = *pushedp; - uint32_t wptr; - efx_dword_t dword; - - /* Hardware has alignment restriction for WPTR */ - wptr = P2ALIGN(added, EF10_RX_WPTR_ALIGN); - if (pushed == wptr) - return; - - *pushedp = wptr; - - /* Push the populated descriptors out */ - wptr &= erp->er_mask; - - EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr); - - /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ - EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1, - wptr, pushed & erp->er_mask); - EFSYS_PIO_WRITE_BARRIER(); - EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG, - erp->er_index, &dword, B_FALSE); -} - - __checkReturn efx_rc_t -ef10_rx_qflush( - __in efx_rxq_t *erp) -{ - efx_nic_t *enp = erp->er_enp; - efx_rc_t rc; - - if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_rx_qenable( - __in efx_rxq_t *erp) -{ - /* FIXME */ - _NOTE(ARGUNUSED(erp)) - /* FIXME */ -} - - __checkReturn efx_rc_t -ef10_rx_qcreate( - __in efx_nic_t *enp, - __in unsigned int index, - __in unsigned int label, - __in efx_rxq_type_t type, - __in efsys_mem_t *esmp, - __in size_t n, - __in uint32_t id, - __in efx_evq_t *eep, - __in efx_rxq_t *erp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_rc_t rc; - boolean_t disable_scatter; - - _NOTE(ARGUNUSED(erp)) - - EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH)); - EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS); - EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit); - - EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS)); - EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS)); - - if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) { - rc = EINVAL; - goto fail1; - } - if (index >= encp->enc_rxq_limit) { - rc = EINVAL; - goto fail2; - } - - /* Scatter can only be disabled if the firmware supports doing so */ - if ((type != EFX_RXQ_TYPE_SCATTER) && - enp->en_nic_cfg.enc_rx_disable_scatter_supported) { - disable_scatter = B_TRUE; - } else { - disable_scatter = B_FALSE; - } - - if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index, - esmp, disable_scatter)) != 0) - goto fail3; - - erp->er_eep = eep; - erp->er_label = label; - - ef10_ev_rxlabel_init(eep, erp, label); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_rx_qdestroy( - __in efx_rxq_t *erp) -{ - efx_nic_t *enp = erp->er_enp; - efx_evq_t *eep = erp->er_eep; - unsigned int label = erp->er_label; - - ef10_ev_rxlabel_fini(eep, label); - - EFSYS_ASSERT(enp->en_rx_qcount != 0); - --enp->en_rx_qcount; - - EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp); -} - - void -ef10_rx_fini( - __in efx_nic_t *enp) -{ -#if EFSYS_OPT_RX_SCALE - if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) { - (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context); - } - enp->en_rss_context = 0; - enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; -#else - _NOTE(ARGUNUSED(enp)) -#endif /* EFSYS_OPT_RX_SCALE */ -} - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_rx.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_tx.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_tx.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_tx.c (nonexistent) @@ -1,710 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_HUNTINGTON - -#if EFSYS_OPT_QSTATS -#define EFX_TX_QSTAT_INCR(_etp, _stat) \ - do { \ - (_etp)->et_stat[_stat]++; \ - _NOTE(CONSTANTCONDITION) \ - } while (B_FALSE) -#else -#define EFX_TX_QSTAT_INCR(_etp, _stat) -#endif - -static __checkReturn efx_rc_t -efx_mcdi_init_txq( - __in efx_nic_t *enp, - __in uint32_t size, - __in uint32_t target_evq, - __in uint32_t label, - __in uint32_t instance, - __in uint16_t flags, - __in efsys_mem_t *esmp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS), - MC_CMD_INIT_TXQ_OUT_LEN)]; - efx_qword_t *dma_addr; - uint64_t addr; - int npages; - int i; - efx_rc_t rc; - - EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >= - EFX_TXQ_NBUFS(EFX_TXQ_MAXNDESCS(&enp->en_nic_cfg))); - - npages = EFX_TXQ_NBUFS(size); - if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_INIT_TXQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages); - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size); - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq); - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label); - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance); - - MCDI_IN_POPULATE_DWORD_7(req, INIT_TXQ_IN_FLAGS, - INIT_TXQ_IN_FLAG_BUFF_MODE, 0, - INIT_TXQ_IN_FLAG_IP_CSUM_DIS, - (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1, - INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, - (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1, - INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0, - INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0, - INIT_TXQ_IN_CRC_MODE, 0, - INIT_TXQ_IN_FLAG_TIMESTAMP, 0); - - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0); - MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); - - dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR); - addr = EFSYS_MEM_ADDR(esmp); - - for (i = 0; i < npages; i++) { - EFX_POPULATE_QWORD_2(*dma_addr, - EFX_DWORD_1, (uint32_t)(addr >> 32), - EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); - - dma_addr++; - addr += EFX_BUF_SIZE; - } - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_fini_txq( - __in efx_nic_t *enp, - __in uint32_t instance) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FINI_TXQ_IN_LEN, - MC_CMD_FINI_TXQ_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FINI_TXQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance); - - efx_mcdi_execute(enp, &req); - - if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_tx_init( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) - return (0); -} - - void -ef10_tx_fini( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - - __checkReturn efx_rc_t -ef10_tx_qcreate( - __in efx_nic_t *enp, - __in unsigned int index, - __in unsigned int label, - __in efsys_mem_t *esmp, - __in size_t n, - __in uint32_t id, - __in uint16_t flags, - __in efx_evq_t *eep, - __in efx_txq_t *etp, - __out unsigned int *addedp) -{ - efx_qword_t desc; - efx_rc_t rc; - - - if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags, - esmp)) != 0) - goto fail1; - - /* - * A previous user of this TX queue may have written a descriptor to the - * TX push collector, but not pushed the doorbell (e.g. after a crash). - * The next doorbell write would then push the stale descriptor. - * - * Ensure the (per network port) TX push collector is cleared by writing - * a no-op TX option descriptor. See bug29981 for details. - */ - *addedp = 1; - EFX_POPULATE_QWORD_4(desc, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM, - ESF_DZ_TX_OPTION_UDP_TCP_CSUM, - (flags & EFX_TXQ_CKSUM_TCPUDP) ? 1 : 0, - ESF_DZ_TX_OPTION_IP_CSUM, - (flags & EFX_TXQ_CKSUM_IPV4) ? 1 : 0); - - EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc); - ef10_tx_qpush(etp, *addedp, 0); - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_tx_qdestroy( - __in efx_txq_t *etp) -{ - /* FIXME */ - _NOTE(ARGUNUSED(etp)) - /* FIXME */ -} - - __checkReturn efx_rc_t -ef10_tx_qpio_enable( - __in efx_txq_t *etp) -{ - efx_nic_t *enp = etp->et_enp; - efx_piobuf_handle_t handle; - efx_rc_t rc; - - if (etp->et_pio_size != 0) { - rc = EALREADY; - goto fail1; - } - - /* Sub-allocate a PIO block from a piobuf */ - if ((rc = ef10_nic_pio_alloc(enp, - &etp->et_pio_bufnum, - &handle, - &etp->et_pio_blknum, - &etp->et_pio_offset, - &etp->et_pio_size)) != 0) { - goto fail2; - } - EFSYS_ASSERT3U(etp->et_pio_size, !=, 0); - - /* Link the piobuf to this TXQ */ - if ((rc = ef10_nic_pio_link(enp, etp->et_index, handle)) != 0) { - goto fail3; - } - - /* - * et_pio_offset is the offset of the sub-allocated block within the - * hardware PIO buffer. It is used as the buffer address in the PIO - * option descriptor. - * - * et_pio_write_offset is the offset of the sub-allocated block from the - * start of the write-combined memory mapping, and is used for writing - * data into the PIO buffer. - */ - etp->et_pio_write_offset = - (etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) + - ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset; - - return (0); - -fail3: - EFSYS_PROBE(fail3); - ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum); - etp->et_pio_size = 0; -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_tx_qpio_disable( - __in efx_txq_t *etp) -{ - efx_nic_t *enp = etp->et_enp; - - if (etp->et_pio_size != 0) { - /* Unlink the piobuf from this TXQ */ - ef10_nic_pio_unlink(enp, etp->et_index); - - /* Free the sub-allocated PIO block */ - ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum); - etp->et_pio_size = 0; - etp->et_pio_write_offset = 0; - } -} - - __checkReturn efx_rc_t -ef10_tx_qpio_write( - __in efx_txq_t *etp, - __in_ecount(length) uint8_t *buffer, - __in size_t length, - __in size_t offset) -{ - efx_nic_t *enp = etp->et_enp; - efsys_bar_t *esbp = enp->en_esbp; - uint32_t write_offset; - uint32_t write_offset_limit; - efx_qword_t *eqp; - efx_rc_t rc; - - EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0); - - if (etp->et_pio_size == 0) { - rc = ENOENT; - goto fail1; - } - if (offset + length > etp->et_pio_size) { - rc = ENOSPC; - goto fail2; - } - - /* - * Writes to PIO buffers must be 64 bit aligned, and multiples of - * 64 bits. - */ - write_offset = etp->et_pio_write_offset + offset; - write_offset_limit = write_offset + length; - eqp = (efx_qword_t *)buffer; - while (write_offset < write_offset_limit) { - EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp); - eqp++; - write_offset += sizeof (efx_qword_t); - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_tx_qpio_post( - __in efx_txq_t *etp, - __in size_t pkt_length, - __in unsigned int completed, - __inout unsigned int *addedp) -{ - efx_qword_t pio_desc; - unsigned int id; - size_t offset; - unsigned int added = *addedp; - efx_rc_t rc; - - - if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) { - rc = ENOSPC; - goto fail1; - } - - if (etp->et_pio_size == 0) { - rc = ENOENT; - goto fail2; - } - - id = added++ & etp->et_mask; - offset = id * sizeof (efx_qword_t); - - EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index, - unsigned int, id, uint32_t, etp->et_pio_offset, - size_t, pkt_length); - - EFX_POPULATE_QWORD_5(pio_desc, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, 1, - ESF_DZ_TX_PIO_CONT, 0, - ESF_DZ_TX_PIO_BYTE_CNT, pkt_length, - ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset); - - EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc); - - EFX_TX_QSTAT_INCR(etp, TX_POST_PIO); - - *addedp = added; - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_tx_qpost( - __in efx_txq_t *etp, - __in_ecount(n) efx_buffer_t *eb, - __in unsigned int n, - __in unsigned int completed, - __inout unsigned int *addedp) -{ - unsigned int added = *addedp; - unsigned int i; - efx_rc_t rc; - - if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { - rc = ENOSPC; - goto fail1; - } - - for (i = 0; i < n; i++) { - efx_buffer_t *ebp = &eb[i]; - efsys_dma_addr_t addr = ebp->eb_addr; - size_t size = ebp->eb_size; - boolean_t eop = ebp->eb_eop; - unsigned int id; - size_t offset; - efx_qword_t qword; - - /* Fragments must not span 4k boundaries. */ - EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= (addr + size)); - - id = added++ & etp->et_mask; - offset = id * sizeof (efx_qword_t); - - EFSYS_PROBE5(tx_post, unsigned int, etp->et_index, - unsigned int, id, efsys_dma_addr_t, addr, - size_t, size, boolean_t, eop); - - EFX_POPULATE_QWORD_5(qword, - ESF_DZ_TX_KER_TYPE, 0, - ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1, - ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size), - ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), - ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); - - EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword); - } - - EFX_TX_QSTAT_INCR(etp, TX_POST); - - *addedp = added; - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * This improves performance by pushing a TX descriptor at the same time as the - * doorbell. The descriptor must be added to the TXQ, so that can be used if the - * hardware decides not to use the pushed descriptor. - */ - void -ef10_tx_qpush( - __in efx_txq_t *etp, - __in unsigned int added, - __in unsigned int pushed) -{ - efx_nic_t *enp = etp->et_enp; - unsigned int wptr; - unsigned int id; - size_t offset; - efx_qword_t desc; - efx_oword_t oword; - - wptr = added & etp->et_mask; - id = pushed & etp->et_mask; - offset = id * sizeof (efx_qword_t); - - EFSYS_MEM_READQ(etp->et_esmp, offset, &desc); - EFX_POPULATE_OWORD_3(oword, - ERF_DZ_TX_DESC_WPTR, wptr, - ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1), - ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0)); - - /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ - EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, id); - EFSYS_PIO_WRITE_BARRIER(); - EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG, etp->et_index, - &oword); -} - - __checkReturn efx_rc_t -ef10_tx_qdesc_post( - __in efx_txq_t *etp, - __in_ecount(n) efx_desc_t *ed, - __in unsigned int n, - __in unsigned int completed, - __inout unsigned int *addedp) -{ - unsigned int added = *addedp; - unsigned int i; - efx_rc_t rc; - - if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { - rc = ENOSPC; - goto fail1; - } - - for (i = 0; i < n; i++) { - efx_desc_t *edp = &ed[i]; - unsigned int id; - size_t offset; - - id = added++ & etp->et_mask; - offset = id * sizeof (efx_desc_t); - - EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq); - } - - EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index, - unsigned int, added, unsigned int, n); - - EFX_TX_QSTAT_INCR(etp, TX_POST); - - *addedp = added; - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_tx_qdesc_dma_create( - __in efx_txq_t *etp, - __in efsys_dma_addr_t addr, - __in size_t size, - __in boolean_t eop, - __out efx_desc_t *edp) -{ - /* Fragments must not span 4k boundaries. */ - EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size); - - EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index, - efsys_dma_addr_t, addr, - size_t, size, boolean_t, eop); - - EFX_POPULATE_QWORD_5(edp->ed_eq, - ESF_DZ_TX_KER_TYPE, 0, - ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1, - ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size), - ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), - ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); -} - - void -hunt_tx_qdesc_tso_create( - __in efx_txq_t *etp, - __in uint16_t ipv4_id, - __in uint32_t tcp_seq, - __in uint8_t tcp_flags, - __out efx_desc_t *edp) -{ - EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index, - uint16_t, ipv4_id, uint32_t, tcp_seq, - uint8_t, tcp_flags); - - EFX_POPULATE_QWORD_5(edp->ed_eq, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, - ESE_DZ_TX_OPTION_DESC_TSO, - ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags, - ESF_DZ_TX_TSO_IP_ID, ipv4_id, - ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq); -} - - void -ef10_tx_qdesc_tso2_create( - __in efx_txq_t *etp, - __in uint16_t ipv4_id, - __in uint32_t tcp_seq, - __in uint16_t tcp_mss, - __out_ecount(count) efx_desc_t *edp, - __in int count) -{ - EFSYS_PROBE4(tx_desc_tso2_create, unsigned int, etp->et_index, - uint16_t, ipv4_id, uint32_t, tcp_seq, - uint16_t, tcp_mss); - - EFSYS_ASSERT(count >= EFX_TX_FATSOV2_OPT_NDESCS); - - EFX_POPULATE_QWORD_5(edp[0].ed_eq, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, - ESE_DZ_TX_OPTION_DESC_TSO, - ESF_DZ_TX_TSO_OPTION_TYPE, - ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A, - ESF_DZ_TX_TSO_IP_ID, ipv4_id, - ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq); - EFX_POPULATE_QWORD_4(edp[1].ed_eq, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, - ESE_DZ_TX_OPTION_DESC_TSO, - ESF_DZ_TX_TSO_OPTION_TYPE, - ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B, - ESF_DZ_TX_TSO_TCP_MSS, tcp_mss); -} - - void -ef10_tx_qdesc_vlantci_create( - __in efx_txq_t *etp, - __in uint16_t tci, - __out efx_desc_t *edp) -{ - EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index, - uint16_t, tci); - - EFX_POPULATE_QWORD_4(edp->ed_eq, - ESF_DZ_TX_DESC_IS_OPT, 1, - ESF_DZ_TX_OPTION_TYPE, - ESE_DZ_TX_OPTION_DESC_VLAN, - ESF_DZ_TX_VLAN_OP, tci ? 1 : 0, - ESF_DZ_TX_VLAN_TAG1, tci); -} - - - __checkReturn efx_rc_t -ef10_tx_qpace( - __in efx_txq_t *etp, - __in unsigned int ns) -{ - efx_rc_t rc; - - /* FIXME */ - _NOTE(ARGUNUSED(etp, ns)) - if (B_FALSE) { - rc = ENOTSUP; - goto fail1; - } - /* FIXME */ - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_tx_qflush( - __in efx_txq_t *etp) -{ - efx_nic_t *enp = etp->et_enp; - efx_rc_t rc; - - if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_tx_qenable( - __in efx_txq_t *etp) -{ - /* FIXME */ - _NOTE(ARGUNUSED(etp)) - /* FIXME */ -} - -#if EFSYS_OPT_QSTATS - void -ef10_tx_qstats_update( - __in efx_txq_t *etp, - __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) -{ - unsigned int id; - - for (id = 0; id < TX_NQSTATS; id++) { - efsys_stat_t *essp = &stat[id]; - - EFSYS_STAT_INCR(essp, etp->et_stat[id]); - etp->et_stat[id] = 0; - } -} - -#endif /* EFSYS_OPT_QSTATS */ - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_tx.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:executable ## -1 +0,0 ## -* \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_filter.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_filter.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_filter.c (nonexistent) @@ -1,1482 +0,0 @@ -/*- - * Copyright (c) 2007-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - -#if EFSYS_OPT_HUNTINGTON - -#if EFSYS_OPT_FILTER - -#define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) - -static efx_filter_spec_t * -ef10_filter_entry_spec( - __in const ef10_filter_table_t *eftp, - __in unsigned int index) -{ - return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & - ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); -} - -static boolean_t -ef10_filter_entry_is_busy( - __in const ef10_filter_table_t *eftp, - __in unsigned int index) -{ - if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) - return (B_TRUE); - else - return (B_FALSE); -} - -static boolean_t -ef10_filter_entry_is_auto_old( - __in const ef10_filter_table_t *eftp, - __in unsigned int index) -{ - if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) - return (B_TRUE); - else - return (B_FALSE); -} - -static void -ef10_filter_set_entry( - __inout ef10_filter_table_t *eftp, - __in unsigned int index, - __in_opt const efx_filter_spec_t *efsp) -{ - EFE_SPEC(eftp, index) = (uintptr_t)efsp; -} - -static void -ef10_filter_set_entry_busy( - __inout ef10_filter_table_t *eftp, - __in unsigned int index) -{ - EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; -} - -static void -ef10_filter_set_entry_not_busy( - __inout ef10_filter_table_t *eftp, - __in unsigned int index) -{ - EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; -} - -static void -ef10_filter_set_entry_auto_old( - __inout ef10_filter_table_t *eftp, - __in unsigned int index) -{ - EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); - EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; -} - -static void -ef10_filter_set_entry_not_auto_old( - __inout ef10_filter_table_t *eftp, - __in unsigned int index) -{ - EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; - EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); -} - - __checkReturn efx_rc_t -ef10_filter_init( - __in efx_nic_t *enp) -{ - efx_rc_t rc; - ef10_filter_table_t *eftp; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - -#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); - EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == - MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); -#undef MATCH_MASK - - EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); - - if (!eftp) { - rc = ENOMEM; - goto fail1; - } - - enp->en_filter.ef_ef10_filter_table = eftp; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_filter_fini( - __in efx_nic_t *enp) -{ - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if (enp->en_filter.ef_ef10_filter_table != NULL) { - EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), - enp->en_filter.ef_ef10_filter_table); - } -} - -static __checkReturn efx_rc_t -efx_mcdi_filter_op_add( - __in efx_nic_t *enp, - __in efx_filter_spec_t *spec, - __in unsigned int filter_op, - __inout ef10_filter_handle_t *handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, - MC_CMD_FILTER_OP_OUT_LEN)]; - uint32_t match_fields = 0; - efx_rc_t rc; - - memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FILTER_OP; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; - - switch (filter_op) { - case MC_CMD_FILTER_OP_IN_OP_REPLACE: - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, - handle->efh_lo); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, - handle->efh_hi); - /* Fall through */ - case MC_CMD_FILTER_OP_IN_OP_INSERT: - case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); - break; - default: - EFSYS_ASSERT(0); - rc = EINVAL; - goto fail1; - } - - if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { - /* - * The LOC_MAC_IG match flag can represent unknown unicast - * or multicast filters - use the MAC address to distinguish - * them. - */ - if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) - match_fields |= 1U << - MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; - else - match_fields |= 1U << - MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; - } - - match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); - - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, - EVB_PORT_ID_ASSIGNED); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, - match_fields); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, - MC_CMD_FILTER_OP_IN_RX_DEST_HOST); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, - spec->efs_dmaq_id); - if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, - spec->efs_rss_context); - } - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, - spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? - MC_CMD_FILTER_OP_IN_RX_MODE_RSS : - MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, - MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); - - if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { - /* - * NOTE: Unlike most MCDI requests, the filter fields - * are presented in network (big endian) byte order. - */ - memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), - spec->efs_rem_mac, EFX_MAC_ADDR_LEN); - memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), - spec->efs_loc_mac, EFX_MAC_ADDR_LEN); - - MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, - __CPU_TO_BE_16(spec->efs_rem_port)); - MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, - __CPU_TO_BE_16(spec->efs_loc_port)); - - MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, - __CPU_TO_BE_16(spec->efs_ether_type)); - - MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, - __CPU_TO_BE_16(spec->efs_inner_vid)); - MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, - __CPU_TO_BE_16(spec->efs_outer_vid)); - - /* IP protocol (in low byte, high byte is zero) */ - MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, - spec->efs_ip_proto); - - EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == - MC_CMD_FILTER_OP_IN_SRC_IP_LEN); - EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == - MC_CMD_FILTER_OP_IN_DST_IP_LEN); - - memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), - &spec->efs_rem_host.eo_byte[0], - MC_CMD_FILTER_OP_IN_SRC_IP_LEN); - memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), - &spec->efs_loc_host.eo_byte[0], - MC_CMD_FILTER_OP_IN_DST_IP_LEN); - } - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); - handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); - -} - -static __checkReturn efx_rc_t -efx_mcdi_filter_op_delete( - __in efx_nic_t *enp, - __in unsigned int filter_op, - __inout ef10_filter_handle_t *handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, - MC_CMD_FILTER_OP_OUT_LEN)]; - efx_rc_t rc; - - memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FILTER_OP; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; - - switch (filter_op) { - case MC_CMD_FILTER_OP_IN_OP_REMOVE: - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, - MC_CMD_FILTER_OP_IN_OP_REMOVE); - break; - case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, - MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); - break; - default: - EFSYS_ASSERT(0); - rc = EINVAL; - goto fail1; - } - - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo); - MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn boolean_t -ef10_filter_equal( - __in const efx_filter_spec_t *left, - __in const efx_filter_spec_t *right) -{ - /* FIXME: Consider rx vs tx filters (look at efs_flags) */ - if (left->efs_match_flags != right->efs_match_flags) - return (B_FALSE); - if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) - return (B_FALSE); - if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) - return (B_FALSE); - if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) - return (B_FALSE); - if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) - return (B_FALSE); - if (left->efs_rem_port != right->efs_rem_port) - return (B_FALSE); - if (left->efs_loc_port != right->efs_loc_port) - return (B_FALSE); - if (left->efs_inner_vid != right->efs_inner_vid) - return (B_FALSE); - if (left->efs_outer_vid != right->efs_outer_vid) - return (B_FALSE); - if (left->efs_ether_type != right->efs_ether_type) - return (B_FALSE); - if (left->efs_ip_proto != right->efs_ip_proto) - return (B_FALSE); - - return (B_TRUE); - -} - -static __checkReturn boolean_t -ef10_filter_same_dest( - __in const efx_filter_spec_t *left, - __in const efx_filter_spec_t *right) -{ - if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && - (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { - if (left->efs_rss_context == right->efs_rss_context) - return (B_TRUE); - } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && - (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { - if (left->efs_dmaq_id == right->efs_dmaq_id) - return (B_TRUE); - } - return (B_FALSE); -} - -static __checkReturn uint32_t -ef10_filter_hash( - __in efx_filter_spec_t *spec) -{ - EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) - == 0); - EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % - sizeof (uint32_t)) == 0); - - /* - * As the area of the efx_filter_spec_t we need to hash is DWORD - * aligned and an exact number of DWORDs in size we can use the - * optimised efx_hash_dwords() rather than efx_hash_bytes() - */ - return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, - (sizeof (efx_filter_spec_t) - - EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / - sizeof (uint32_t), 0)); -} - -/* - * Decide whether a filter should be exclusive or else should allow - * delivery to additional recipients. Currently we decide that - * filters for specific local unicast MAC and IP addresses are - * exclusive. - */ -static __checkReturn boolean_t -ef10_filter_is_exclusive( - __in efx_filter_spec_t *spec) -{ - if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && - !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) - return (B_TRUE); - - if ((spec->efs_match_flags & - (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == - (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { - if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && - ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) - return (B_TRUE); - if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && - (spec->efs_loc_host.eo_u8[0] != 0xff)) - return (B_TRUE); - } - - return (B_FALSE); -} - - __checkReturn efx_rc_t -ef10_filter_restore( - __in efx_nic_t *enp) -{ - int tbl_id; - efx_filter_spec_t *spec; - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - boolean_t restoring; - int state; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { - - EFSYS_LOCK(enp->en_eslp, state); - - spec = ef10_filter_entry_spec(eftp, tbl_id); - if (spec == NULL) { - restoring = B_FALSE; - } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { - /* Ignore busy entries. */ - restoring = B_FALSE; - } else { - ef10_filter_set_entry_busy(eftp, tbl_id); - restoring = B_TRUE; - } - - EFSYS_UNLOCK(enp->en_eslp, state); - - if (restoring == B_FALSE) - continue; - - if (ef10_filter_is_exclusive(spec)) { - rc = efx_mcdi_filter_op_add(enp, spec, - MC_CMD_FILTER_OP_IN_OP_INSERT, - &eftp->eft_entry[tbl_id].efe_handle); - } else { - rc = efx_mcdi_filter_op_add(enp, spec, - MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, - &eftp->eft_entry[tbl_id].efe_handle); - } - - if (rc != 0) - goto fail1; - - EFSYS_LOCK(enp->en_eslp, state); - - ef10_filter_set_entry_not_busy(eftp, tbl_id); - - EFSYS_UNLOCK(enp->en_eslp, state); - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * An arbitrary search limit for the software hash table. As per the linux net - * driver. - */ -#define EF10_FILTER_SEARCH_LIMIT 200 - -static __checkReturn efx_rc_t -ef10_filter_add_internal( - __in efx_nic_t *enp, - __inout efx_filter_spec_t *spec, - __in boolean_t may_replace, - __out_opt uint32_t *filter_id) -{ - efx_rc_t rc; - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t *saved_spec; - uint32_t hash; - unsigned int depth; - int ins_index; - boolean_t replacing = B_FALSE; - unsigned int i; - int state; - boolean_t locked = B_FALSE; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - -#if EFSYS_OPT_RX_SCALE - spec->efs_rss_context = enp->en_rss_context; -#endif - - hash = ef10_filter_hash(spec); - - /* - * FIXME: Add support for inserting filters of different priorities - * and removing lower priority multicast filters (bug 42378) - */ - - /* - * Find any existing filters with the same match tuple or - * else a free slot to insert at. If any of them are busy, - * we have to wait and retry. - */ - for (;;) { - ins_index = -1; - depth = 1; - EFSYS_LOCK(enp->en_eslp, state); - locked = B_TRUE; - - for (;;) { - i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); - saved_spec = ef10_filter_entry_spec(eftp, i); - - if (!saved_spec) { - if (ins_index < 0) { - ins_index = i; - } - } else if (ef10_filter_equal(spec, saved_spec)) { - if (ef10_filter_entry_is_busy(eftp, i)) - break; - if (saved_spec->efs_priority - == EFX_FILTER_PRI_AUTO) { - ins_index = i; - goto found; - } else if (ef10_filter_is_exclusive(spec)) { - if (may_replace) { - ins_index = i; - goto found; - } else { - rc = EEXIST; - goto fail1; - } - } - - /* Leave existing */ - } - - /* - * Once we reach the maximum search depth, use - * the first suitable slot or return EBUSY if - * there was none. - */ - if (depth == EF10_FILTER_SEARCH_LIMIT) { - if (ins_index < 0) { - rc = EBUSY; - goto fail2; - } - goto found; - } - depth++; - } - EFSYS_UNLOCK(enp->en_eslp, state); - locked = B_FALSE; - } - -found: - /* - * Create a software table entry if necessary, and mark it - * busy. We might yet fail to insert, but any attempt to - * insert a conflicting filter while we're waiting for the - * firmware must find the busy entry. - */ - saved_spec = ef10_filter_entry_spec(eftp, ins_index); - if (saved_spec) { - if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { - /* This is a filter we are refreshing */ - ef10_filter_set_entry_not_auto_old(eftp, ins_index); - goto out_unlock; - - } - replacing = B_TRUE; - } else { - EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); - if (!saved_spec) { - rc = ENOMEM; - goto fail3; - } - *saved_spec = *spec; - ef10_filter_set_entry(eftp, ins_index, saved_spec); - } - ef10_filter_set_entry_busy(eftp, ins_index); - - EFSYS_UNLOCK(enp->en_eslp, state); - locked = B_FALSE; - - /* - * On replacing the filter handle may change after after a successful - * replace operation. - */ - if (replacing) { - rc = efx_mcdi_filter_op_add(enp, spec, - MC_CMD_FILTER_OP_IN_OP_REPLACE, - &eftp->eft_entry[ins_index].efe_handle); - } else if (ef10_filter_is_exclusive(spec)) { - rc = efx_mcdi_filter_op_add(enp, spec, - MC_CMD_FILTER_OP_IN_OP_INSERT, - &eftp->eft_entry[ins_index].efe_handle); - } else { - rc = efx_mcdi_filter_op_add(enp, spec, - MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, - &eftp->eft_entry[ins_index].efe_handle); - } - - if (rc != 0) - goto fail4; - - EFSYS_LOCK(enp->en_eslp, state); - locked = B_TRUE; - - if (replacing) { - /* Update the fields that may differ */ - saved_spec->efs_priority = spec->efs_priority; - saved_spec->efs_flags = spec->efs_flags; - saved_spec->efs_rss_context = spec->efs_rss_context; - saved_spec->efs_dmaq_id = spec->efs_dmaq_id; - } - - ef10_filter_set_entry_not_busy(eftp, ins_index); - -out_unlock: - - EFSYS_UNLOCK(enp->en_eslp, state); - locked = B_FALSE; - - if (filter_id) - *filter_id = ins_index; - - return (0); - -fail4: - EFSYS_PROBE(fail4); - - if (!replacing) { - EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); - saved_spec = NULL; - } - ef10_filter_set_entry_not_busy(eftp, ins_index); - ef10_filter_set_entry(eftp, ins_index, NULL); - -fail3: - EFSYS_PROBE(fail3); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - if (locked) - EFSYS_UNLOCK(enp->en_eslp, state); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_filter_add( - __in efx_nic_t *enp, - __inout efx_filter_spec_t *spec, - __in boolean_t may_replace) -{ - efx_rc_t rc; - - rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); - if (rc != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -ef10_filter_delete_internal( - __in efx_nic_t *enp, - __in uint32_t filter_id) -{ - efx_rc_t rc; - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t *spec; - int state; - uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; - - /* - * Find the software table entry and mark it busy. Don't - * remove it yet; any attempt to update while we're waiting - * for the firmware must find the busy entry. - * - * FIXME: What if the busy flag is never cleared? - */ - EFSYS_LOCK(enp->en_eslp, state); - while (ef10_filter_entry_is_busy(table, filter_idx)) { - EFSYS_UNLOCK(enp->en_eslp, state); - EFSYS_SPIN(1); - EFSYS_LOCK(enp->en_eslp, state); - } - if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { - ef10_filter_set_entry_busy(table, filter_idx); - } - EFSYS_UNLOCK(enp->en_eslp, state); - - if (spec == NULL) { - rc = ENOENT; - goto fail1; - } - - /* - * Try to remove the hardware filter. This may fail if the MC has - * rebooted (which frees all hardware filter resources). - */ - if (ef10_filter_is_exclusive(spec)) { - rc = efx_mcdi_filter_op_delete(enp, - MC_CMD_FILTER_OP_IN_OP_REMOVE, - &table->eft_entry[filter_idx].efe_handle); - } else { - rc = efx_mcdi_filter_op_delete(enp, - MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, - &table->eft_entry[filter_idx].efe_handle); - } - - /* Free the software table entry */ - EFSYS_LOCK(enp->en_eslp, state); - ef10_filter_set_entry_not_busy(table, filter_idx); - ef10_filter_set_entry(table, filter_idx, NULL); - EFSYS_UNLOCK(enp->en_eslp, state); - - EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); - - /* Check result of hardware filter removal */ - if (rc != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_filter_delete( - __in efx_nic_t *enp, - __inout efx_filter_spec_t *spec) -{ - efx_rc_t rc; - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t *saved_spec; - unsigned int hash; - unsigned int depth; - unsigned int i; - int state; - boolean_t locked = B_FALSE; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - hash = ef10_filter_hash(spec); - - EFSYS_LOCK(enp->en_eslp, state); - locked = B_TRUE; - - depth = 1; - for (;;) { - i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); - saved_spec = ef10_filter_entry_spec(table, i); - if (saved_spec && ef10_filter_equal(spec, saved_spec) && - ef10_filter_same_dest(spec, saved_spec)) { - break; - } - if (depth == EF10_FILTER_SEARCH_LIMIT) { - rc = ENOENT; - goto fail1; - } - depth++; - } - - EFSYS_UNLOCK(enp->en_eslp, state); - locked = B_FALSE; - - rc = ef10_filter_delete_internal(enp, i); - if (rc != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - if (locked) - EFSYS_UNLOCK(enp->en_eslp, state); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_get_parser_disp_info( - __in efx_nic_t *enp, - __out uint32_t *list, - __out size_t *length) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, - MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; - efx_rc_t rc; - uint32_t i; - boolean_t support_unknown_ucast = B_FALSE; - boolean_t support_unknown_mcast = B_FALSE; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; - - MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, - MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - *length = MCDI_OUT_DWORD(req, - GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); - - if (req.emr_out_length_used < - MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { - rc = EMSGSIZE; - goto fail2; - } - - memcpy(list, - MCDI_OUT2(req, - uint32_t, - GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), - (*length) * sizeof (uint32_t)); - EFX_STATIC_ASSERT(sizeof (uint32_t) == - MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); - - /* - * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change - * the lower priority one to LOC_MAC_IG. - */ - for (i = 0; i < *length; i++) { - if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { - list[i] &= - (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); - support_unknown_ucast = B_TRUE; - } - if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { - list[i] &= - (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); - support_unknown_mcast = B_TRUE; - } - - if (support_unknown_ucast && support_unknown_mcast) { - list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; - break; - } - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_filter_supported_filters( - __in efx_nic_t *enp, - __out uint32_t *list, - __out size_t *length) -{ - efx_rc_t rc; - - if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0)) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -ef10_filter_insert_unicast( - __in efx_nic_t *enp, - __in_ecount(6) uint8_t const *addr, - __in efx_filter_flag_t filter_flags) -{ - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t spec; - efx_rc_t rc; - - /* Insert the filter for the local station address */ - efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, - filter_flags, - eftp->eft_default_rxq); - efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr); - - rc = ef10_filter_add_internal(enp, &spec, B_TRUE, - &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); - if (rc != 0) - goto fail1; - - eftp->eft_unicst_filter_count++; - EFSYS_ASSERT(eftp->eft_unicst_filter_count <= - EFX_EF10_FILTER_UNICAST_FILTERS_MAX); - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - return (rc); -} - -static __checkReturn efx_rc_t -ef10_filter_insert_all_unicast( - __in efx_nic_t *enp, - __in efx_filter_flag_t filter_flags) -{ - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t spec; - efx_rc_t rc; - - /* Insert the unknown unicast filter */ - efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, - filter_flags, - eftp->eft_default_rxq); - efx_filter_spec_set_uc_def(&spec); - rc = ef10_filter_add_internal(enp, &spec, B_TRUE, - &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); - if (rc != 0) - goto fail1; - - eftp->eft_unicst_filter_count++; - EFSYS_ASSERT(eftp->eft_unicst_filter_count <= - EFX_EF10_FILTER_UNICAST_FILTERS_MAX); - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - return (rc); -} - -static __checkReturn efx_rc_t -ef10_filter_insert_multicast_list( - __in efx_nic_t *enp, - __in boolean_t mulcst, - __in boolean_t brdcst, - __in_ecount(6*count) uint8_t const *addrs, - __in uint32_t count, - __in efx_filter_flag_t filter_flags, - __in boolean_t rollback) -{ - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t spec; - uint8_t addr[6]; - uint32_t i; - uint32_t filter_index; - uint32_t filter_count; - efx_rc_t rc; - - if (mulcst == B_FALSE) - count = 0; - - if (count + (brdcst ? 1 : 0) > - EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { - /* Too many MAC addresses */ - rc = EINVAL; - goto fail1; - } - - /* Insert/renew multicast address list filters */ - filter_count = 0; - for (i = 0; i < count; i++) { - efx_filter_spec_init_rx(&spec, - EFX_FILTER_PRI_AUTO, - filter_flags, - eftp->eft_default_rxq); - - efx_filter_spec_set_eth_local(&spec, - EFX_FILTER_SPEC_VID_UNSPEC, - &addrs[i * EFX_MAC_ADDR_LEN]); - - rc = ef10_filter_add_internal(enp, &spec, B_TRUE, - &filter_index); - - if (rc == 0) { - eftp->eft_mulcst_filter_indexes[filter_count] = - filter_index; - filter_count++; - } else if (rollback == B_TRUE) { - /* Only stop upon failure if told to rollback */ - goto rollback; - } - - } - - if (brdcst == B_TRUE) { - /* Insert/renew broadcast address filter */ - efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, - filter_flags, - eftp->eft_default_rxq); - - EFX_MAC_BROADCAST_ADDR_SET(addr); - efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, - addr); - - rc = ef10_filter_add_internal(enp, &spec, B_TRUE, - &filter_index); - - if (rc == 0) { - eftp->eft_mulcst_filter_indexes[filter_count] = - filter_index; - filter_count++; - } else if (rollback == B_TRUE) { - /* Only stop upon failure if told to rollback */ - goto rollback; - } - } - - eftp->eft_mulcst_filter_count = filter_count; - eftp->eft_using_all_mulcst = B_FALSE; - - return (0); - -rollback: - /* Remove any filters we have inserted */ - i = filter_count; - while (i--) { - (void) ef10_filter_delete_internal(enp, - eftp->eft_mulcst_filter_indexes[i]); - } - eftp->eft_mulcst_filter_count = 0; - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -ef10_filter_insert_all_multicast( - __in efx_nic_t *enp, - __in efx_filter_flag_t filter_flags) -{ - ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; - efx_filter_spec_t spec; - efx_rc_t rc; - - /* Insert the unknown multicast filter */ - efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, - filter_flags, - eftp->eft_default_rxq); - efx_filter_spec_set_mc_def(&spec); - - rc = ef10_filter_add_internal(enp, &spec, B_TRUE, - &eftp->eft_mulcst_filter_indexes[0]); - if (rc != 0) - goto fail1; - - eftp->eft_mulcst_filter_count = 1; - eftp->eft_using_all_mulcst = B_TRUE; - - /* - * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. - */ - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static void -ef10_filter_remove_old( - __in efx_nic_t *enp) -{ - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - uint32_t i; - - for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { - if (ef10_filter_entry_is_auto_old(table, i)) { - (void) ef10_filter_delete_internal(enp, i); - } - } -} - - -static __checkReturn efx_rc_t -ef10_filter_get_workarounds( - __in efx_nic_t *enp) -{ - efx_nic_cfg_t *encp = &enp->en_nic_cfg; - uint32_t implemented = 0; - uint32_t enabled = 0; - efx_rc_t rc; - - rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); - if (rc == 0) { - /* Check if chained multicast filter support is enabled */ - if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) - encp->enc_bug26807_workaround = B_TRUE; - else - encp->enc_bug26807_workaround = B_FALSE; - } else if (rc == ENOTSUP) { - /* - * Firmware is too old to support GET_WORKAROUNDS, and support - * for this workaround was implemented later. - */ - encp->enc_bug26807_workaround = B_FALSE; - } else { - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); - -} - - -/* - * Reconfigure all filters. - * If all_unicst and/or all mulcst filters cannot be applied then - * return ENOTSUP (Note the filters for the specified addresses are - * still applied in this case). - */ - __checkReturn efx_rc_t -ef10_filter_reconfigure( - __in efx_nic_t *enp, - __in_ecount(6) uint8_t const *mac_addr, - __in boolean_t all_unicst, - __in boolean_t mulcst, - __in boolean_t all_mulcst, - __in boolean_t brdcst, - __in_ecount(6*count) uint8_t const *addrs, - __in uint32_t count) -{ - efx_nic_cfg_t *encp = &enp->en_nic_cfg; - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - efx_filter_flag_t filter_flags; - unsigned i; - efx_rc_t all_unicst_rc = 0; - efx_rc_t all_mulcst_rc = 0; - efx_rc_t rc; - - if (table->eft_default_rxq == NULL) { - /* - * Filters direct traffic to the default RXQ, and so cannot be - * inserted until it is available. Any currently configured - * filters must be removed (ignore errors in case the MC - * has rebooted, which removes hardware filters). - */ - for (i = 0; i < table->eft_unicst_filter_count; i++) { - (void) ef10_filter_delete_internal(enp, - table->eft_unicst_filter_indexes[i]); - } - table->eft_unicst_filter_count = 0; - - for (i = 0; i < table->eft_mulcst_filter_count; i++) { - (void) ef10_filter_delete_internal(enp, - table->eft_mulcst_filter_indexes[i]); - } - table->eft_mulcst_filter_count = 0; - - return (0); - } - - if (table->eft_using_rss) - filter_flags = EFX_FILTER_FLAG_RX_RSS; - else - filter_flags = 0; - - /* Mark old filters which may need to be removed */ - for (i = 0; i < table->eft_unicst_filter_count; i++) { - ef10_filter_set_entry_auto_old(table, - table->eft_unicst_filter_indexes[i]); - } - for (i = 0; i < table->eft_mulcst_filter_count; i++) { - ef10_filter_set_entry_auto_old(table, - table->eft_mulcst_filter_indexes[i]); - } - - /* - * Insert or renew unicast filters. - * - * Frimware does not perform chaining on unicast filters. As traffic is - * therefore only delivered to the first matching filter, we should - * always insert the specific filter for our MAC address, to try and - * ensure we get that traffic. - * - * (If the filter for our MAC address has already been inserted by - * another function, we won't receive traffic sent to us, even if we - * insert a unicast mismatch filter. To prevent traffic stealing, this - * therefore relies on the privilege model only allowing functions to - * insert filters for their own MAC address unless explicitly given - * additional privileges by the user. This also means that, even on a - * priviliged function, inserting a unicast mismatch filter may not - * catch all traffic in multi PCI function scenarios.) - */ - table->eft_unicst_filter_count = 0; - rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); - if (all_unicst || (rc != 0)) { - all_unicst_rc = ef10_filter_insert_all_unicast(enp, - filter_flags); - if ((rc != 0) && (all_unicst_rc != 0)) - goto fail1; - } - - /* - * WORKAROUND_BUG26807 controls firmware support for chained multicast - * filters, and can only be enabled or disabled when the hardware filter - * table is empty. - * - * Chained multicast filters require support from the datapath firmware, - * and may not be available (e.g. low-latency variants or old Huntington - * firmware). - * - * Firmware will reset (FLR) functions which have inserted filters in - * the hardware filter table when the workaround is enabled/disabled. - * Functions without any hardware filters are not reset. - * - * Re-check if the workaround is enabled after adding unicast hardware - * filters. This ensures that encp->enc_bug26807_workaround matches the - * firmware state, and that later changes to enable/disable the - * workaround will result in this function seeing a reset (FLR). - * - * In common-code drivers, we only support multiple PCI function - * scenarios with firmware that supports multicast chaining, so we can - * assume it is enabled for such cases and hence simplify the filter - * insertion logic. Firmware that does not support multicast chaining - * does not support multiple PCI function configurations either, so - * filter insertion is much simpler and the same strategies can still be - * used. - */ - if ((rc = ef10_filter_get_workarounds(enp)) != 0) - goto fail2; - - if ((table->eft_using_all_mulcst != all_mulcst) && - (encp->enc_bug26807_workaround == B_TRUE)) { - /* - * Multicast filter chaining is enabled, so traffic that matches - * more than one multicast filter will be replicated and - * delivered to multiple recipients. To avoid this duplicate - * delivery, remove old multicast filters before inserting new - * multicast filters. - */ - ef10_filter_remove_old(enp); - } - - /* Insert or renew multicast filters */ - if (all_mulcst == B_TRUE) { - /* - * Insert the all multicast filter. If that fails, try to insert - * all of our multicast filters (but without rollback on - * failure). - */ - all_mulcst_rc = ef10_filter_insert_all_multicast(enp, - filter_flags); - if (all_mulcst_rc != 0) { - rc = ef10_filter_insert_multicast_list(enp, B_TRUE, - brdcst, addrs, count, filter_flags, B_FALSE); - if (rc != 0) - goto fail3; - } - } else { - /* - * Insert filters for multicast addresses. - * If any insertion fails, then rollback and try to insert the - * all multicast filter instead. - * If that also fails, try to insert all of the multicast - * filters (but without rollback on failure). - */ - rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, - addrs, count, filter_flags, B_TRUE); - if (rc != 0) { - if ((table->eft_using_all_mulcst == B_FALSE) && - (encp->enc_bug26807_workaround == B_TRUE)) { - /* - * Multicast filter chaining is on, so remove - * old filters before inserting the multicast - * all filter to avoid duplicate delivery caused - * by packets matching multiple filters. - */ - ef10_filter_remove_old(enp); - } - - rc = ef10_filter_insert_all_multicast(enp, - filter_flags); - if (rc != 0) { - rc = ef10_filter_insert_multicast_list(enp, - mulcst, brdcst, - addrs, count, filter_flags, B_FALSE); - if (rc != 0) - goto fail4; - } - } - } - - /* Remove old filters which were not renewed */ - ef10_filter_remove_old(enp); - - /* report if any optional flags were rejected */ - if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || - ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { - rc = ENOTSUP; - } - - return (rc); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - /* Clear auto old flags */ - for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { - if (ef10_filter_entry_is_auto_old(table, i)) { - ef10_filter_set_entry_not_auto_old(table, i); - } - } - - return (rc); -} - - void -ef10_filter_get_default_rxq( - __in efx_nic_t *enp, - __out efx_rxq_t **erpp, - __out boolean_t *using_rss) -{ - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - - *erpp = table->eft_default_rxq; - *using_rss = table->eft_using_rss; -} - - - void -ef10_filter_default_rxq_set( - __in efx_nic_t *enp, - __in efx_rxq_t *erp, - __in boolean_t using_rss) -{ - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - -#if EFSYS_OPT_RX_SCALE - EFSYS_ASSERT((using_rss == B_FALSE) || - (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); - table->eft_using_rss = using_rss; -#else - EFSYS_ASSERT(using_rss == B_FALSE); - table->eft_using_rss = B_FALSE; -#endif - table->eft_default_rxq = erp; -} - - void -ef10_filter_default_rxq_clear( - __in efx_nic_t *enp) -{ - ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; - - table->eft_default_rxq = NULL; - table->eft_using_rss = B_FALSE; -} - - -#endif /* EFSYS_OPT_FILTER */ - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_filter.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_nvram.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_nvram.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_nvram.c (nonexistent) @@ -1,2333 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - -#if EFSYS_OPT_HUNTINGTON - -#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM - -#include "ef10_tlv_layout.h" - -/* Cursor for TLV partition format */ -typedef struct tlv_cursor_s { - uint32_t *block; /* Base of data block */ - uint32_t *current; /* Cursor position */ - uint32_t *end; /* End tag position */ - uint32_t *limit; /* Last dword of data block */ -} tlv_cursor_t; - -typedef struct nvram_partition_s { - uint16_t type; - uint8_t chip_select; - uint8_t flags; - /* - * The full length of the NVRAM partition. - * This is different from tlv_partition_header.total_length, - * which can be smaller. - */ - uint32_t length; - uint32_t erase_size; - uint32_t *data; - tlv_cursor_t tlv_cursor; -} nvram_partition_t; - - -static __checkReturn efx_rc_t -tlv_validate_state( - __inout tlv_cursor_t *cursor); - - -static void -tlv_init_block( - __out uint32_t *block) -{ - *block = __CPU_TO_LE_32(TLV_TAG_END); -} - -static uint32_t -tlv_tag( - __in tlv_cursor_t *cursor) -{ - uint32_t dword, tag; - - dword = cursor->current[0]; - tag = __LE_TO_CPU_32(dword); - - return (tag); -} - -static size_t -tlv_length( - __in tlv_cursor_t *cursor) -{ - uint32_t dword, length; - - if (tlv_tag(cursor) == TLV_TAG_END) - return (0); - - dword = cursor->current[1]; - length = __LE_TO_CPU_32(dword); - - return ((size_t)length); -} - -static uint8_t * -tlv_value( - __in tlv_cursor_t *cursor) -{ - if (tlv_tag(cursor) == TLV_TAG_END) - return (NULL); - - return ((uint8_t *)(&cursor->current[2])); -} - -static uint8_t * -tlv_item( - __in tlv_cursor_t *cursor) -{ - if (tlv_tag(cursor) == TLV_TAG_END) - return (NULL); - - return ((uint8_t *)cursor->current); -} - -/* - * TLV item DWORD length is tag + length + value (rounded up to DWORD) - * equivalent to tlv_n_words_for_len in mc-comms tlv.c - */ -#define TLV_DWORD_COUNT(length) \ - (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t))) - - -static uint32_t * -tlv_next_item_ptr( - __in tlv_cursor_t *cursor) -{ - uint32_t length; - - length = tlv_length(cursor); - - return (cursor->current + TLV_DWORD_COUNT(length)); -} - -static __checkReturn efx_rc_t -tlv_advance( - __inout tlv_cursor_t *cursor) -{ - efx_rc_t rc; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - if (cursor->current == cursor->end) { - /* No more tags after END tag */ - cursor->current = NULL; - rc = ENOENT; - goto fail2; - } - - /* Advance to next item and validate */ - cursor->current = tlv_next_item_ptr(cursor); - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail3; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static efx_rc_t -tlv_rewind( - __in tlv_cursor_t *cursor) -{ - efx_rc_t rc; - - cursor->current = cursor->block; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static efx_rc_t -tlv_find( - __inout tlv_cursor_t *cursor, - __in uint32_t tag) -{ - efx_rc_t rc; - - rc = tlv_rewind(cursor); - while (rc == 0) { - if (tlv_tag(cursor) == tag) - break; - - rc = tlv_advance(cursor); - } - return (rc); -} - -static __checkReturn efx_rc_t -tlv_validate_state( - __inout tlv_cursor_t *cursor) -{ - efx_rc_t rc; - - /* Check cursor position */ - if (cursor->current < cursor->block) { - rc = EINVAL; - goto fail1; - } - if (cursor->current > cursor->limit) { - rc = EINVAL; - goto fail2; - } - - if (tlv_tag(cursor) != TLV_TAG_END) { - /* Check current item has space for tag and length */ - if (cursor->current > (cursor->limit - 2)) { - cursor->current = NULL; - rc = EFAULT; - goto fail3; - } - - /* Check we have value data for current item and another tag */ - if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) { - cursor->current = NULL; - rc = EFAULT; - goto fail4; - } - } - - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static efx_rc_t -tlv_init_cursor( - __out tlv_cursor_t *cursor, - __in uint32_t *block, - __in uint32_t *limit, - __in uint32_t *current) -{ - cursor->block = block; - cursor->limit = limit; - - cursor->current = current; - cursor->end = NULL; - - return (tlv_validate_state(cursor)); -} - -static __checkReturn efx_rc_t -tlv_init_cursor_from_size( - __out tlv_cursor_t *cursor, - __in_bcount(size) - uint8_t *block, - __in size_t size) -{ - uint32_t *limit; - limit = (uint32_t *)(block + size - sizeof (uint32_t)); - return (tlv_init_cursor(cursor, (uint32_t *)block, - limit, (uint32_t *)block)); -} - -static __checkReturn efx_rc_t -tlv_init_cursor_at_offset( - __out tlv_cursor_t *cursor, - __in_bcount(size) - uint8_t *block, - __in size_t size, - __in size_t offset) -{ - uint32_t *limit; - uint32_t *current; - limit = (uint32_t *)(block + size - sizeof (uint32_t)); - current = (uint32_t *)(block + offset); - return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current)); -} - -static __checkReturn efx_rc_t -tlv_require_end( - __inout tlv_cursor_t *cursor) -{ - uint32_t *pos; - efx_rc_t rc; - - if (cursor->end == NULL) { - pos = cursor->current; - if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0) - goto fail1; - - cursor->end = cursor->current; - cursor->current = pos; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static size_t -tlv_block_length_used( - __inout tlv_cursor_t *cursor) -{ - efx_rc_t rc; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - if ((rc = tlv_require_end(cursor)) != 0) - goto fail2; - - /* Return space used (including the END tag) */ - return (cursor->end + 1 - cursor->block) * sizeof (uint32_t); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (0); -} - -static uint32_t * -tlv_last_segment_end( - __in tlv_cursor_t *cursor) -{ - tlv_cursor_t segment_cursor; - uint32_t *last_segment_end = cursor->block; - uint32_t *segment_start = cursor->block; - - /* - * Go through each segment and check that it has an end tag. If there - * is no end tag then the previous segment was the last valid one, - * so return the pointer to its end tag. - */ - while (1) { - if (tlv_init_cursor(&segment_cursor, segment_start, - cursor->limit, segment_start) != 0) - break; - if (tlv_require_end(&segment_cursor) != 0) - break; - last_segment_end = segment_cursor.end; - segment_start = segment_cursor.end + 1; - } - - return (last_segment_end); -} - - -static uint32_t * -tlv_write( - __in tlv_cursor_t *cursor, - __in uint32_t tag, - __in_bcount(size) uint8_t *data, - __in size_t size) -{ - uint32_t len = size; - uint32_t *ptr; - - ptr = cursor->current; - - *ptr++ = __CPU_TO_LE_32(tag); - *ptr++ = __CPU_TO_LE_32(len); - - if (len > 0) { - ptr[(len - 1) / sizeof (uint32_t)] = 0; - memcpy(ptr, data, len); - ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr); - } - - return (ptr); -} - -static __checkReturn efx_rc_t -tlv_insert( - __inout tlv_cursor_t *cursor, - __in uint32_t tag, - __in_bcount(size) - uint8_t *data, - __in size_t size) -{ - unsigned int delta; - uint32_t *last_segment_end; - efx_rc_t rc; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - if ((rc = tlv_require_end(cursor)) != 0) - goto fail2; - - if (tag == TLV_TAG_END) { - rc = EINVAL; - goto fail3; - } - - last_segment_end = tlv_last_segment_end(cursor); - - delta = TLV_DWORD_COUNT(size); - if (last_segment_end + 1 + delta > cursor->limit) { - rc = ENOSPC; - goto fail4; - } - - /* Move data up: new space at cursor->current */ - memmove(cursor->current + delta, cursor->current, - (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); - - /* Adjust the end pointer */ - cursor->end += delta; - - /* Write new TLV item */ - tlv_write(cursor, tag, data, size); - - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -tlv_delete( - __inout tlv_cursor_t *cursor) -{ - unsigned int delta; - uint32_t *last_segment_end; - efx_rc_t rc; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - if (tlv_tag(cursor) == TLV_TAG_END) { - rc = EINVAL; - goto fail2; - } - - delta = TLV_DWORD_COUNT(tlv_length(cursor)); - - if ((rc = tlv_require_end(cursor)) != 0) - goto fail3; - - last_segment_end = tlv_last_segment_end(cursor); - - /* Shuffle things down, destroying the item at cursor->current */ - memmove(cursor->current, cursor->current + delta, - (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); - /* Zero the new space at the end of the TLV chain */ - memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t)); - /* Adjust the end pointer */ - cursor->end -= delta; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -tlv_modify( - __inout tlv_cursor_t *cursor, - __in uint32_t tag, - __in_bcount(size) - uint8_t *data, - __in size_t size) -{ - uint32_t *pos; - unsigned int old_ndwords; - unsigned int new_ndwords; - unsigned int delta; - uint32_t *last_segment_end; - efx_rc_t rc; - - if ((rc = tlv_validate_state(cursor)) != 0) - goto fail1; - - if (tlv_tag(cursor) == TLV_TAG_END) { - rc = EINVAL; - goto fail2; - } - if (tlv_tag(cursor) != tag) { - rc = EINVAL; - goto fail3; - } - - old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor)); - new_ndwords = TLV_DWORD_COUNT(size); - - if ((rc = tlv_require_end(cursor)) != 0) - goto fail4; - - last_segment_end = tlv_last_segment_end(cursor); - - if (new_ndwords > old_ndwords) { - /* Expand space used for TLV item */ - delta = new_ndwords - old_ndwords; - pos = cursor->current + old_ndwords; - - if (last_segment_end + 1 + delta > cursor->limit) { - rc = ENOSPC; - goto fail5; - } - - /* Move up: new space at (cursor->current + old_ndwords) */ - memmove(pos + delta, pos, - (last_segment_end + 1 - pos) * sizeof (uint32_t)); - - /* Adjust the end pointer */ - cursor->end += delta; - - } else if (new_ndwords < old_ndwords) { - /* Shrink space used for TLV item */ - delta = old_ndwords - new_ndwords; - pos = cursor->current + new_ndwords; - - /* Move down: remove words at (cursor->current + new_ndwords) */ - memmove(pos, pos + delta, - (last_segment_end + 1 - pos) * sizeof (uint32_t)); - - /* Zero the new space at the end of the TLV chain */ - memset(last_segment_end + 1 - delta, 0, - delta * sizeof (uint32_t)); - - /* Adjust the end pointer */ - cursor->end -= delta; - } - - /* Write new data */ - tlv_write(cursor, tag, data, size); - - return (0); - -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static uint32_t checksum_tlv_partition( - __in nvram_partition_t *partition) -{ - tlv_cursor_t *cursor; - uint32_t *ptr; - uint32_t *end; - uint32_t csum; - size_t len; - - cursor = &partition->tlv_cursor; - len = tlv_block_length_used(cursor); - EFSYS_ASSERT3U((len & 3), ==, 0); - - csum = 0; - ptr = partition->data; - end = &ptr[len >> 2]; - - while (ptr < end) - csum += __LE_TO_CPU_32(*ptr++); - - return (csum); -} - -static __checkReturn efx_rc_t -tlv_update_partition_len_and_cks( - __in tlv_cursor_t *cursor) -{ - efx_rc_t rc; - nvram_partition_t partition; - struct tlv_partition_header *header; - struct tlv_partition_trailer *trailer; - size_t new_len; - - /* - * We just modified the partition, so the total length may not be - * valid. Don't use tlv_find(), which performs some sanity checks - * that may fail here. - */ - partition.data = cursor->block; - memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor)); - header = (struct tlv_partition_header *)partition.data; - /* Sanity check. */ - if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) { - rc = EFAULT; - goto fail1; - } - new_len = tlv_block_length_used(&partition.tlv_cursor); - if (new_len == 0) { - rc = EFAULT; - goto fail2; - } - header->total_length = __CPU_TO_LE_32(new_len); - /* Ensure the modified partition always has a new generation count. */ - header->generation = __CPU_TO_LE_32( - __LE_TO_CPU_32(header->generation) + 1); - - trailer = (struct tlv_partition_trailer *)((uint8_t *)header + - new_len - sizeof (*trailer) - sizeof (uint32_t)); - trailer->generation = header->generation; - trailer->checksum = __CPU_TO_LE_32( - __LE_TO_CPU_32(trailer->checksum) - - checksum_tlv_partition(&partition)); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* Validate buffer contents (before writing to flash) */ - __checkReturn efx_rc_t -ef10_nvram_buffer_validate( - __in efx_nic_t *enp, - __in uint32_t partn, - __in_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size) -{ - tlv_cursor_t cursor; - struct tlv_partition_header *header; - struct tlv_partition_trailer *trailer; - size_t total_length; - uint32_t cksum; - int pos; - efx_rc_t rc; - - EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); - - if ((partn_data == NULL) || (partn_size == 0)) { - rc = EINVAL; - goto fail1; - } - - /* The partition header must be the first item (at offset zero) */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, - partn_size)) != 0) { - rc = EFAULT; - goto fail2; - } - if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail3; - } - header = (struct tlv_partition_header *)tlv_item(&cursor); - - /* Check TLV partition length (includes the END tag) */ - total_length = __LE_TO_CPU_32(header->total_length); - if (total_length > partn_size) { - rc = EFBIG; - goto fail4; - } - - /* Check partition ends with PARTITION_TRAILER and END tags */ - if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { - rc = EINVAL; - goto fail5; - } - trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); - - if ((rc = tlv_advance(&cursor)) != 0) { - rc = EINVAL; - goto fail6; - } - if (tlv_tag(&cursor) != TLV_TAG_END) { - rc = EINVAL; - goto fail7; - } - - /* Check generation counts are consistent */ - if (trailer->generation != header->generation) { - rc = EINVAL; - goto fail8; - } - - /* Verify partition checksum */ - cksum = 0; - for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(partn_data + pos)); - } - if (cksum != 0) { - rc = EINVAL; - goto fail9; - } - - return (0); - -fail9: - EFSYS_PROBE(fail9); -fail8: - EFSYS_PROBE(fail8); -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - - __checkReturn efx_rc_t -ef10_nvram_buffer_create( - __in efx_nic_t *enp, - __in uint16_t partn_type, - __in_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size) -{ - uint32_t *buf = (uint32_t *)partn_data; - efx_rc_t rc; - tlv_cursor_t cursor; - struct tlv_partition_header header; - struct tlv_partition_trailer trailer; - - unsigned min_buf_size = sizeof (struct tlv_partition_header) + - sizeof (struct tlv_partition_trailer); - if (partn_size < min_buf_size) { - rc = EINVAL; - goto fail1; - } - - memset(buf, 0xff, partn_size); - - tlv_init_block(buf); - if ((rc = tlv_init_cursor(&cursor, buf, - (uint32_t *)((uint8_t *)buf + partn_size), - buf)) != 0) { - goto fail2; - } - - header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); - header.length = __CPU_TO_LE_32(sizeof (header) - 8); - header.type_id = __CPU_TO_LE_16(partn_type); - header.preset = 0; - header.generation = __CPU_TO_LE_32(1); - header.total_length = 0; /* This will be fixed below. */ - if ((rc = tlv_insert( - &cursor, TLV_TAG_PARTITION_HEADER, - (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) - goto fail3; - if ((rc = tlv_advance(&cursor)) != 0) - goto fail4; - - trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); - trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); - trailer.generation = header.generation; - trailer.checksum = 0; /* This will be fixed below. */ - if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, - (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) - goto fail5; - - if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) - goto fail6; - - /* Check that the partition is valid. */ - if ((rc = ef10_nvram_buffer_validate(enp, partn_type, - partn_data, partn_size)) != 0) - goto fail7; - - return (0); - -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static uint32_t -byte_offset( - __in uint32_t *position, - __in uint32_t *base) -{ - return (uint32_t)((uint8_t *)position - (uint8_t *)base); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_find_item_start( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __out uint32_t *startp) -{ - // Read past partition header to find start address of the first key - tlv_cursor_t cursor; - efx_rc_t rc; - - /* A PARTITION_HEADER tag must be the first item (at offset zero) */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, - buffer_size)) != 0) { - rc = EFAULT; - goto fail1; - } - if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail2; - } - - if ((rc = tlv_advance(&cursor)) != 0) { - rc = EINVAL; - goto fail3; - } - *startp = byte_offset(cursor.current, cursor.block); - - if ((rc = tlv_require_end(&cursor)) != 0) - goto fail4; - - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_find_end( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __in uint32_t offset, - __out uint32_t *endp) -{ - // Read to end of partition - tlv_cursor_t cursor; - efx_rc_t rc; - - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, - buffer_size)) != 0) { - rc = EFAULT; - goto fail1; - } - - if ((rc = tlv_require_end(&cursor)) != 0) - goto fail2; - - *endp = byte_offset(tlv_last_segment_end(&cursor)+1, cursor.block); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn __success(return != B_FALSE) boolean_t -ef10_nvram_buffer_find_item( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __in uint32_t offset, - __out uint32_t *startp, - __out uint32_t *lengthp) -{ - // Find TLV at offset and return key start and length - tlv_cursor_t cursor; - uint8_t *key; - uint32_t tag; - - if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, - buffer_size, offset) != 0) { - return (B_FALSE); - } - - while ((key = tlv_item(&cursor)) != NULL) { - tag = tlv_tag(&cursor); - if (tag == TLV_TAG_PARTITION_HEADER || - tag == TLV_TAG_PARTITION_TRAILER) { - if (tlv_advance(&cursor) != 0) { - break; - } - continue; - } - *startp = byte_offset(cursor.current, cursor.block); - *lengthp = byte_offset(tlv_next_item_ptr(&cursor), - cursor.current); - return (B_TRUE); - } - - return (B_FALSE); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_get_item( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __in uint32_t offset, - __in uint32_t length, - __out_bcount_part(item_max_size, *lengthp) - caddr_t itemp, - __in size_t item_max_size, - __out uint32_t *lengthp) -{ - efx_rc_t rc; - tlv_cursor_t cursor; - uint32_t item_length; - - if (item_max_size < length) { - rc = ENOSPC; - goto fail1; - } - - if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, - buffer_size, offset)) != 0) { - goto fail2; - } - - item_length = tlv_length(&cursor); - if (length < item_length) { - rc = ENOSPC; - goto fail3; - } - memcpy(itemp, tlv_value(&cursor), item_length); - - *lengthp = item_length; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_insert_item( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __in uint32_t offset, - __in_bcount(length) caddr_t keyp, - __in uint32_t length, - __out uint32_t *lengthp) -{ - efx_rc_t rc; - tlv_cursor_t cursor; - - if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, - buffer_size, offset)) != 0) { - goto fail1; - } - - rc = tlv_insert(&cursor, TLV_TAG_LICENSE, keyp, length); - - if (rc != 0) { - goto fail2; - } - - *lengthp = byte_offset(tlv_next_item_ptr(&cursor), - cursor.current); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_delete_item( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size, - __in uint32_t offset, - __in uint32_t length, - __in uint32_t end) -{ - efx_rc_t rc; - tlv_cursor_t cursor; - - if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, - buffer_size, offset)) != 0) { - goto fail1; - } - - if ((rc = tlv_delete(&cursor)) != 0) - goto fail2; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_buffer_finish( - __in_bcount(buffer_size) - caddr_t bufferp, - __in size_t buffer_size) -{ - efx_rc_t rc; - tlv_cursor_t cursor; - - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, - buffer_size)) != 0) { - rc = EFAULT; - goto fail1; - } - - if ((rc = tlv_require_end(&cursor)) != 0) - goto fail2; - - if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) - goto fail3; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - -/* - * Read and validate a segment from a partition. A segment is a complete - * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may - * be multiple segments in a partition, so seg_offset allows segments - * beyond the first to be read. - */ -static __checkReturn efx_rc_t -ef10_nvram_read_tlv_segment( - __in efx_nic_t *enp, - __in uint32_t partn, - __in size_t seg_offset, - __in_bcount(max_seg_size) caddr_t seg_data, - __in size_t max_seg_size) -{ - tlv_cursor_t cursor; - struct tlv_partition_header *header; - struct tlv_partition_trailer *trailer; - size_t total_length; - uint32_t cksum; - int pos; - efx_rc_t rc; - - EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); - - if ((seg_data == NULL) || (max_seg_size == 0)) { - rc = EINVAL; - goto fail1; - } - - /* Read initial chunk of the segment, starting at offset */ - if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, - EF10_NVRAM_CHUNK, - MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { - goto fail2; - } - - /* A PARTITION_HEADER tag must be the first item at the given offset */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, - max_seg_size)) != 0) { - rc = EFAULT; - goto fail3; - } - if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail4; - } - header = (struct tlv_partition_header *)tlv_item(&cursor); - - /* Check TLV segment length (includes the END tag) */ - total_length = __LE_TO_CPU_32(header->total_length); - if (total_length > max_seg_size) { - rc = EFBIG; - goto fail5; - } - - /* Read the remaining segment content */ - if (total_length > EF10_NVRAM_CHUNK) { - if ((rc = ef10_nvram_partn_read_mode(enp, partn, - seg_offset + EF10_NVRAM_CHUNK, - seg_data + EF10_NVRAM_CHUNK, - total_length - EF10_NVRAM_CHUNK, - MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) - goto fail6; - } - - /* Check segment ends with PARTITION_TRAILER and END tags */ - if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { - rc = EINVAL; - goto fail7; - } - trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); - - if ((rc = tlv_advance(&cursor)) != 0) { - rc = EINVAL; - goto fail8; - } - if (tlv_tag(&cursor) != TLV_TAG_END) { - rc = EINVAL; - goto fail9; - } - - /* Check data read from segment is consistent */ - if (trailer->generation != header->generation) { - /* - * The partition data may have been modified between successive - * MCDI NVRAM_READ requests by the MC or another PCI function. - * - * The caller must retry to obtain consistent partition data. - */ - rc = EAGAIN; - goto fail10; - } - - /* Verify segment checksum */ - cksum = 0; - for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(seg_data + pos)); - } - if (cksum != 0) { - rc = EINVAL; - goto fail11; - } - - return (0); - -fail11: - EFSYS_PROBE(fail11); -fail10: - EFSYS_PROBE(fail10); -fail9: - EFSYS_PROBE(fail9); -fail8: - EFSYS_PROBE(fail8); -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * Read a single TLV item from a host memory - * buffer containing a TLV formatted segment. - */ - __checkReturn efx_rc_t -ef10_nvram_buf_read_tlv( - __in efx_nic_t *enp, - __in_bcount(max_seg_size) caddr_t seg_data, - __in size_t max_seg_size, - __in uint32_t tag, - __deref_out_bcount_opt(*sizep) caddr_t *datap, - __out size_t *sizep) -{ - tlv_cursor_t cursor; - caddr_t data; - size_t length; - caddr_t value; - efx_rc_t rc; - - if ((seg_data == NULL) || (max_seg_size == 0)) { - rc = EINVAL; - goto fail1; - } - - /* Find requested TLV tag in segment data */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, - max_seg_size)) != 0) { - rc = EFAULT; - goto fail2; - } - if ((rc = tlv_find(&cursor, tag)) != 0) { - rc = ENOENT; - goto fail3; - } - value = (caddr_t)tlv_value(&cursor); - length = tlv_length(&cursor); - - if (length == 0) - data = NULL; - else { - /* Copy out data from TLV item */ - EFSYS_KMEM_ALLOC(enp->en_esip, length, data); - if (data == NULL) { - rc = ENOMEM; - goto fail4; - } - memcpy(data, value, length); - } - - *datap = data; - *sizep = length; - - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* Read a single TLV item from the first segment in a TLV formatted partition */ - __checkReturn efx_rc_t -ef10_nvram_partn_read_tlv( - __in efx_nic_t *enp, - __in uint32_t partn, - __in uint32_t tag, - __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, - __out size_t *seg_sizep) -{ - caddr_t seg_data = NULL; - size_t partn_size = 0; - size_t length; - caddr_t data; - int retry; - efx_rc_t rc; - - /* Allocate sufficient memory for the entire partition */ - if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) - goto fail1; - - if (partn_size == 0) { - rc = ENOENT; - goto fail2; - } - - EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); - if (seg_data == NULL) { - rc = ENOMEM; - goto fail3; - } - - /* - * Read the first segment in a TLV partition. Retry until consistent - * segment contents are returned. Inconsistent data may be read if: - * a) the segment contents are invalid - * b) the MC has rebooted while we were reading the partition - * c) the partition has been modified while we were reading it - * Limit retry attempts to ensure forward progress. - */ - retry = 10; - do { - rc = ef10_nvram_read_tlv_segment(enp, partn, 0, - seg_data, partn_size); - } while ((rc == EAGAIN) && (--retry > 0)); - - if (rc != 0) { - /* Failed to obtain consistent segment data */ - goto fail4; - } - - if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, - tag, &data, &length)) != 0) - goto fail5; - - EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); - - *seg_datap = data; - *seg_sizep = length; - - return (0); - -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); - - EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* Compute the size of a segment. */ - static __checkReturn efx_rc_t -ef10_nvram_buf_segment_size( - __in caddr_t seg_data, - __in size_t max_seg_size, - __out size_t *seg_sizep) -{ - efx_rc_t rc; - tlv_cursor_t cursor; - struct tlv_partition_header *header; - uint32_t cksum; - int pos; - uint32_t *end_tag_position; - uint32_t segment_length; - - /* A PARTITION_HEADER tag must be the first item at the given offset */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, - max_seg_size)) != 0) { - rc = EFAULT; - goto fail1; - } - if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail2; - } - header = (struct tlv_partition_header *)tlv_item(&cursor); - - /* Check TLV segment length (includes the END tag) */ - *seg_sizep = __LE_TO_CPU_32(header->total_length); - if (*seg_sizep > max_seg_size) { - rc = EFBIG; - goto fail3; - } - - /* Check segment ends with PARTITION_TRAILER and END tags */ - if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { - rc = EINVAL; - goto fail4; - } - - if ((rc = tlv_advance(&cursor)) != 0) { - rc = EINVAL; - goto fail5; - } - if (tlv_tag(&cursor) != TLV_TAG_END) { - rc = EINVAL; - goto fail6; - } - end_tag_position = cursor.current; - - /* Verify segment checksum */ - cksum = 0; - for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(seg_data + pos)); - } - if (cksum != 0) { - rc = EINVAL; - goto fail7; - } - - /* - * Calculate total length from HEADER to END tags and compare to - * max_seg_size and the total_length field in the HEADER tag. - */ - segment_length = tlv_block_length_used(&cursor); - - if (segment_length > max_seg_size) { - rc = EINVAL; - goto fail8; - } - - if (segment_length != *seg_sizep) { - rc = EINVAL; - goto fail9; - } - - /* Skip over the first HEADER tag. */ - rc = tlv_rewind(&cursor); - rc = tlv_advance(&cursor); - - while (rc == 0) { - if (tlv_tag(&cursor) == TLV_TAG_END) { - /* Check that the END tag is the one found earlier. */ - if (cursor.current != end_tag_position) - goto fail10; - break; - } - /* Check for duplicate HEADER tags before the END tag. */ - if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail11; - } - - rc = tlv_advance(&cursor); - } - if (rc != 0) - goto fail12; - - return (0); - -fail12: - EFSYS_PROBE(fail12); -fail11: - EFSYS_PROBE(fail11); -fail10: - EFSYS_PROBE(fail10); -fail9: - EFSYS_PROBE(fail9); -fail8: - EFSYS_PROBE(fail8); -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * Add or update a single TLV item in a host memory buffer containing a TLV - * formatted segment. Historically partitions consisted of only one segment. - */ - __checkReturn efx_rc_t -ef10_nvram_buf_write_tlv( - __inout_bcount(max_seg_size) caddr_t seg_data, - __in size_t max_seg_size, - __in uint32_t tag, - __in_bcount(tag_size) caddr_t tag_data, - __in size_t tag_size, - __out size_t *total_lengthp) -{ - tlv_cursor_t cursor; - struct tlv_partition_header *header; - struct tlv_partition_trailer *trailer; - uint32_t generation; - uint32_t cksum; - int pos; - efx_rc_t rc; - - /* A PARTITION_HEADER tag must be the first item (at offset zero) */ - if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, - max_seg_size)) != 0) { - rc = EFAULT; - goto fail1; - } - if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { - rc = EINVAL; - goto fail2; - } - header = (struct tlv_partition_header *)tlv_item(&cursor); - - /* Update the TLV chain to contain the new data */ - if ((rc = tlv_find(&cursor, tag)) == 0) { - /* Modify existing TLV item */ - if ((rc = tlv_modify(&cursor, tag, - (uint8_t *)tag_data, tag_size)) != 0) - goto fail3; - } else { - /* Insert a new TLV item before the PARTITION_TRAILER */ - rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); - if (rc != 0) { - rc = EINVAL; - goto fail4; - } - if ((rc = tlv_insert(&cursor, tag, - (uint8_t *)tag_data, tag_size)) != 0) { - rc = EINVAL; - goto fail5; - } - } - - /* Find the trailer tag */ - if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { - rc = EINVAL; - goto fail6; - } - trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); - - /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ - *total_lengthp = tlv_block_length_used(&cursor); - if (*total_lengthp > max_seg_size) { - rc = ENOSPC; - goto fail7; - } - generation = __LE_TO_CPU_32(header->generation) + 1; - - header->total_length = __CPU_TO_LE_32(*total_lengthp); - header->generation = __CPU_TO_LE_32(generation); - trailer->generation = __CPU_TO_LE_32(generation); - - /* Recompute PARTITION_TRAILER checksum */ - trailer->checksum = 0; - cksum = 0; - for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(seg_data + pos)); - } - trailer->checksum = ~cksum + 1; - - return (0); - -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * Add or update a single TLV item in the first segment of a TLV formatted - * dynamic config partition. The first segment is the current active - * configuration. - */ - __checkReturn efx_rc_t -ef10_nvram_partn_write_tlv( - __in efx_nic_t *enp, - __in uint32_t partn, - __in uint32_t tag, - __in_bcount(size) caddr_t data, - __in size_t size) -{ - return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, - size, B_FALSE); -} - -/* - * Read a segment from nvram at the given offset into a buffer (segment_data) - * and optionally write a new tag to it. - */ - static __checkReturn efx_rc_t -ef10_nvram_segment_write_tlv( - __in efx_nic_t *enp, - __in uint32_t partn, - __in uint32_t tag, - __in_bcount(size) caddr_t data, - __in size_t size, - __inout caddr_t *seg_datap, - __inout size_t *partn_offsetp, - __inout size_t *src_remain_lenp, - __inout size_t *dest_remain_lenp, - __in boolean_t write) -{ - efx_rc_t rc; - efx_rc_t status; - size_t original_segment_size; - size_t modified_segment_size; - - /* - * Read the segment from NVRAM into the segment_data buffer and validate - * it, returning if it does not validate. This is not a failure unless - * this is the first segment in a partition. In this case the caller - * must propogate the error. - */ - status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, - *seg_datap, *src_remain_lenp); - if (status != 0) - return (EINVAL); - - status = ef10_nvram_buf_segment_size(*seg_datap, - *src_remain_lenp, &original_segment_size); - if (status != 0) - return (EINVAL); - - if (write) { - /* Update the contents of the segment in the buffer */ - if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, - *dest_remain_lenp, tag, data, size, - &modified_segment_size)) != 0) - goto fail1; - *dest_remain_lenp -= modified_segment_size; - *seg_datap += modified_segment_size; - } else { - /* - * We won't modify this segment, but still need to update the - * remaining lengths and pointers. - */ - *dest_remain_lenp -= original_segment_size; - *seg_datap += original_segment_size; - } - - *partn_offsetp += original_segment_size; - *src_remain_lenp -= original_segment_size; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * Add or update a single TLV item in either the first segment or in all - * segments in a TLV formatted dynamic config partition. Dynamic config - * partitions on boards that support RFID are divided into a number of segments, - * each formatted like a partition, with header, trailer and end tags. The first - * segment is the current active configuration. - * - * The segments are initialised by manftest and each contain a different - * configuration e.g. firmware variant. The firmware can be instructed - * via RFID to copy a segment to replace the first segment, hence changing the - * active configuration. This allows ops to change the configuration of a board - * prior to shipment using RFID. - * - * Changes to the dynamic config may need to be written to all segments (e.g. - * firmware versions) or just the first segment (changes to the active - * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". - * If only the first segment is written the code still needs to be aware of the - * possible presence of subsequent segments as writing to a segment may cause - * its size to increase, which would overwrite the subsequent segments and - * invalidate them. - */ - __checkReturn efx_rc_t -ef10_nvram_partn_write_segment_tlv( - __in efx_nic_t *enp, - __in uint32_t partn, - __in uint32_t tag, - __in_bcount(size) caddr_t data, - __in size_t size, - __in boolean_t all_segments) -{ - size_t partn_size = 0; - caddr_t partn_data; - size_t total_length = 0; - efx_rc_t rc; - size_t current_offset = 0; - size_t remaining_original_length; - size_t remaining_modified_length; - caddr_t segment_data; - - EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); - - /* Allocate sufficient memory for the entire partition */ - if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) - goto fail1; - - EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); - if (partn_data == NULL) { - rc = ENOMEM; - goto fail2; - } - - remaining_original_length = partn_size; - remaining_modified_length = partn_size; - segment_data = partn_data; - - /* Lock the partition */ - if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) - goto fail3; - - /* Iterate over each (potential) segment to update it. */ - do { - boolean_t write = all_segments || current_offset == 0; - - rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, - &segment_data, ¤t_offset, &remaining_original_length, - &remaining_modified_length, write); - if (rc != 0) { - if (current_offset == 0) { - /* - * If no data has been read then the first - * segment is invalid, which is an error. - */ - goto fail4; - } - break; - } - } while (current_offset < partn_size); - - total_length = segment_data - partn_data; - - /* - * We've run out of space. This should actually be dealt with by - * ef10_nvram_buf_write_tlv returning ENOSPC. - */ - if (total_length > partn_size) { - rc = ENOSPC; - goto fail5; - } - - /* Erase the whole partition in NVRAM */ - if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) - goto fail6; - - /* Write new partition contents from the buffer to NVRAM */ - if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, - total_length)) != 0) - goto fail7; - - /* Unlock the partition */ - ef10_nvram_partn_unlock(enp, partn); - - EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); - - return (0); - -fail7: - EFSYS_PROBE(fail7); -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); - - ef10_nvram_partn_unlock(enp, partn); -fail3: - EFSYS_PROBE(fail3); - - EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * Get the size of a NVRAM partition. This is the total size allocated in nvram, - * not the data used by the segments in the partition. - */ - __checkReturn efx_rc_t -ef10_nvram_partn_size( - __in efx_nic_t *enp, - __in uint32_t partn, - __out size_t *sizep) -{ - efx_rc_t rc; - - if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, - NULL, NULL, NULL)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_lock( - __in efx_nic_t *enp, - __in uint32_t partn) -{ - efx_rc_t rc; - - if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_read_mode( - __in efx_nic_t *enp, - __in uint32_t partn, - __in unsigned int offset, - __out_bcount(size) caddr_t data, - __in size_t size, - __in uint32_t mode) -{ - size_t chunk; - efx_rc_t rc; - - while (size > 0) { - chunk = MIN(size, EF10_NVRAM_CHUNK); - - if ((rc = efx_mcdi_nvram_read(enp, partn, offset, - data, chunk, mode)) != 0) { - goto fail1; - } - - size -= chunk; - data += chunk; - offset += chunk; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_read( - __in efx_nic_t *enp, - __in uint32_t partn, - __in unsigned int offset, - __out_bcount(size) caddr_t data, - __in size_t size) -{ - /* - * Read requests which come in through the EFX API expect to - * read the current, active partition. - */ - return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, - MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_erase( - __in efx_nic_t *enp, - __in uint32_t partn, - __in unsigned int offset, - __in size_t size) -{ - efx_rc_t rc; - uint32_t erase_size; - - if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, - &erase_size, NULL)) != 0) - goto fail1; - - if (erase_size == 0) { - if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) - goto fail2; - } else { - if (size % erase_size != 0) { - rc = EINVAL; - goto fail3; - } - while (size > 0) { - if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, - erase_size)) != 0) - goto fail4; - offset += erase_size; - size -= erase_size; - } - } - - return (0); - -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_write( - __in efx_nic_t *enp, - __in uint32_t partn, - __in unsigned int offset, - __out_bcount(size) caddr_t data, - __in size_t size) -{ - size_t chunk; - uint32_t write_size; - efx_rc_t rc; - - if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, - NULL, &write_size)) != 0) - goto fail1; - - if (write_size != 0) { - /* - * Check that the size is a multiple of the write chunk size if - * the write chunk size is available. - */ - if (size % write_size != 0) { - rc = EINVAL; - goto fail2; - } - } else { - write_size = EF10_NVRAM_CHUNK; - } - - while (size > 0) { - chunk = MIN(size, write_size); - - if ((rc = efx_mcdi_nvram_write(enp, partn, offset, - data, chunk)) != 0) { - goto fail3; - } - - size -= chunk; - data += chunk; - offset += chunk; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_nvram_partn_unlock( - __in efx_nic_t *enp, - __in uint32_t partn) -{ - boolean_t reboot; - efx_rc_t rc; - - reboot = B_FALSE; - if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) - goto fail1; - - return; - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_set_version( - __in efx_nic_t *enp, - __in uint32_t partn, - __in_ecount(4) uint16_t version[4]) -{ - struct tlv_partition_version partn_version; - size_t size; - efx_rc_t rc; - - /* Add or modify partition version TLV item */ - partn_version.version_w = __CPU_TO_LE_16(version[0]); - partn_version.version_x = __CPU_TO_LE_16(version[1]); - partn_version.version_y = __CPU_TO_LE_16(version[2]); - partn_version.version_z = __CPU_TO_LE_16(version[3]); - - size = sizeof (partn_version) - (2 * sizeof (uint32_t)); - - /* Write the version number to all segments in the partition */ - if ((rc = ef10_nvram_partn_write_segment_tlv(enp, - NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, - TLV_TAG_PARTITION_VERSION(partn), - (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ - -#if EFSYS_OPT_NVRAM - -typedef struct ef10_parttbl_entry_s { - unsigned int partn; - unsigned int port; - efx_nvram_type_t nvtype; -} ef10_parttbl_entry_t; - -/* Translate EFX NVRAM types to firmware partition types */ -static ef10_parttbl_entry_t hunt_parttbl[] = { - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} -}; - -static ef10_parttbl_entry_t medford_parttbl[] = { - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, - {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, - {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, - {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} -}; - -static __checkReturn efx_rc_t -ef10_parttbl_get( - __in efx_nic_t *enp, - __out ef10_parttbl_entry_t **parttblp, - __out size_t *parttbl_rowsp) -{ - switch (enp->en_family) { - case EFX_FAMILY_HUNTINGTON: - *parttblp = hunt_parttbl; - *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); - break; - - case EFX_FAMILY_MEDFORD: - *parttblp = medford_parttbl; - *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); - break; - - default: - EFSYS_ASSERT(B_FALSE); - return (EINVAL); - } - return (0); -} - - __checkReturn efx_rc_t -ef10_nvram_type_to_partn( - __in efx_nic_t *enp, - __in efx_nvram_type_t type, - __out uint32_t *partnp) -{ - efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - ef10_parttbl_entry_t *parttbl = NULL; - size_t parttbl_rows = 0; - unsigned int i; - - EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); - EFSYS_ASSERT(partnp != NULL); - - if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { - for (i = 0; i < parttbl_rows; i++) { - ef10_parttbl_entry_t *entry = &parttbl[i]; - - if (entry->nvtype == type && - entry->port == emip->emi_port) { - *partnp = entry->partn; - return (0); - } - } - } - - return (ENOTSUP); -} - -#if EFSYS_OPT_DIAG - -static __checkReturn efx_rc_t -ef10_nvram_partn_to_type( - __in efx_nic_t *enp, - __in uint32_t partn, - __out efx_nvram_type_t *typep) -{ - efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - ef10_parttbl_entry_t *parttbl = NULL; - size_t parttbl_rows = 0; - unsigned int i; - - EFSYS_ASSERT(typep != NULL); - - if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { - for (i = 0; i < parttbl_rows; i++) { - ef10_parttbl_entry_t *entry = &parttbl[i]; - - if (entry->partn == partn && - entry->port == emip->emi_port) { - *typep = entry->nvtype; - return (0); - } - } - } - - return (ENOTSUP); -} - - __checkReturn efx_rc_t -ef10_nvram_test( - __in efx_nic_t *enp) -{ - efx_nvram_type_t type; - unsigned int npartns = 0; - uint32_t *partns = NULL; - size_t size; - unsigned int i; - efx_rc_t rc; - - /* Read available partitions from NVRAM partition map */ - size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); - EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); - if (partns == NULL) { - rc = ENOMEM; - goto fail1; - } - - if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, - &npartns)) != 0) { - goto fail2; - } - - for (i = 0; i < npartns; i++) { - /* Check if the partition is supported for this port */ - if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) - continue; - - if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) - goto fail3; - } - - EFSYS_KMEM_FREE(enp->en_esip, size, partns); - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); - EFSYS_KMEM_FREE(enp->en_esip, size, partns); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - return (rc); -} - -#endif /* EFSYS_OPT_DIAG */ - - __checkReturn efx_rc_t -ef10_nvram_partn_get_version( - __in efx_nic_t *enp, - __in uint32_t partn, - __out uint32_t *subtypep, - __out_ecount(4) uint16_t version[4]) -{ - efx_rc_t rc; - - /* FIXME: get highest partn version from all ports */ - /* FIXME: return partn description if available */ - - if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, - version, NULL, 0)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nvram_partn_rw_start( - __in efx_nic_t *enp, - __in uint32_t partn, - __out size_t *chunk_sizep) -{ - efx_rc_t rc; - - if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) - goto fail1; - - if (chunk_sizep != NULL) - *chunk_sizep = EF10_NVRAM_CHUNK; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_nvram_partn_rw_finish( - __in efx_nic_t *enp, - __in uint32_t partn) -{ - ef10_nvram_partn_unlock(enp, partn); -} - -#endif /* EFSYS_OPT_NVRAM */ - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_nvram.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_ev.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_ev.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_ev.c (nonexistent) @@ -1,988 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" -#if EFSYS_OPT_MON_STATS -#include "mcdi_mon.h" -#endif - -#if EFSYS_OPT_HUNTINGTON - -#if EFSYS_OPT_QSTATS -#define EFX_EV_QSTAT_INCR(_eep, _stat) \ - do { \ - (_eep)->ee_stat[_stat]++; \ - _NOTE(CONSTANTCONDITION) \ - } while (B_FALSE) -#else -#define EFX_EV_QSTAT_INCR(_eep, _stat) -#endif - - -static __checkReturn boolean_t -ef10_ev_rx( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg); - -static __checkReturn boolean_t -ef10_ev_tx( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg); - -static __checkReturn boolean_t -ef10_ev_driver( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg); - -static __checkReturn boolean_t -ef10_ev_drv_gen( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg); - -static __checkReturn boolean_t -ef10_ev_mcdi( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg); - - -static __checkReturn efx_rc_t -efx_mcdi_init_evq( - __in efx_nic_t *enp, - __in unsigned int instance, - __in efsys_mem_t *esmp, - __in size_t nevs, - __in uint32_t irq, - __out_opt uint32_t *irqp) -{ - efx_mcdi_req_t req; - uint8_t payload[ - MAX(MC_CMD_INIT_EVQ_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)), - MC_CMD_INIT_EVQ_OUT_LEN)]; - efx_qword_t *dma_addr; - uint64_t addr; - int npages; - int i; - int supports_rx_batching; - efx_rc_t rc; - - npages = EFX_EVQ_NBUFS(nevs); - if (MC_CMD_INIT_EVQ_IN_LEN(npages) > MC_CMD_INIT_EVQ_IN_LENMAX) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_INIT_EVQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages); - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs); - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance); - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq); - - /* - * On Huntington RX and TX event batching can only be requested - * together (even if the datapath firmware doesn't actually support RX - * batching). - * Cut through is incompatible with RX batching and so enabling cut - * through disables RX batching (but it does not affect TX batching). - * - * So always enable RX and TX event batching, and enable cut through - * if RX event batching isn't supported (i.e. on low latency firmware). - */ - supports_rx_batching = enp->en_nic_cfg.enc_rx_batching_enabled ? 1 : 0; - MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS, - INIT_EVQ_IN_FLAG_INTERRUPTING, 1, - INIT_EVQ_IN_FLAG_RPTR_DOS, 0, - INIT_EVQ_IN_FLAG_INT_ARMD, 0, - INIT_EVQ_IN_FLAG_CUT_THRU, !supports_rx_batching, - INIT_EVQ_IN_FLAG_RX_MERGE, 1, - INIT_EVQ_IN_FLAG_TX_MERGE, 1); - - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE, - MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS); - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0); - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0); - - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE, - MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS); - MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0); - - dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_IN_DMA_ADDR); - addr = EFSYS_MEM_ADDR(esmp); - - for (i = 0; i < npages; i++) { - EFX_POPULATE_QWORD_2(*dma_addr, - EFX_DWORD_1, (uint32_t)(addr >> 32), - EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); - - dma_addr++; - addr += EFX_BUF_SIZE; - } - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - if (irqp != NULL) - *irqp = MCDI_OUT_DWORD(req, INIT_EVQ_OUT_IRQ); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_fini_evq( - __in efx_nic_t *enp, - __in uint32_t instance) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FINI_EVQ_IN_LEN, - MC_CMD_FINI_EVQ_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FINI_EVQ; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN; - - MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - - __checkReturn efx_rc_t -ef10_ev_init( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) - return (0); -} - - void -ef10_ev_fini( - __in efx_nic_t *enp) -{ - _NOTE(ARGUNUSED(enp)) -} - - __checkReturn efx_rc_t -ef10_ev_qcreate( - __in efx_nic_t *enp, - __in unsigned int index, - __in efsys_mem_t *esmp, - __in size_t n, - __in uint32_t id, - __in efx_evq_t *eep) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t irq; - efx_rc_t rc; - - _NOTE(ARGUNUSED(id)) /* buftbl id managed by MC */ - EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS)); - EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS)); - - if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) { - rc = EINVAL; - goto fail1; - } - - if (index >= encp->enc_evq_limit) { - rc = EINVAL; - goto fail2; - } - - /* Set up the handler table */ - eep->ee_rx = ef10_ev_rx; - eep->ee_tx = ef10_ev_tx; - eep->ee_driver = ef10_ev_driver; - eep->ee_drv_gen = ef10_ev_drv_gen; - eep->ee_mcdi = ef10_ev_mcdi; - - /* - * Set up the event queue - * NOTE: ignore the returned IRQ param as firmware does not set it. - */ - irq = index; /* INIT_EVQ expects function-relative vector number */ - if ((rc = efx_mcdi_init_evq(enp, index, esmp, n, irq, NULL)) != 0) - goto fail3; - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_ev_qdestroy( - __in efx_evq_t *eep) -{ - efx_nic_t *enp = eep->ee_enp; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) efx_mcdi_fini_evq(eep->ee_enp, eep->ee_index); -} - - __checkReturn efx_rc_t -ef10_ev_qprime( - __in efx_evq_t *eep, - __in unsigned int count) -{ - efx_nic_t *enp = eep->ee_enp; - uint32_t rptr; - efx_dword_t dword; - - rptr = count & eep->ee_mask; - - if (enp->en_nic_cfg.enc_bug35388_workaround) { - EFX_STATIC_ASSERT(EFX_EVQ_MINNEVS > - (1 << ERF_DD_EVQ_IND_RPTR_WIDTH)); - EFX_STATIC_ASSERT(EFX_EVQ_MAXNEVS < - (1 << 2 * ERF_DD_EVQ_IND_RPTR_WIDTH)); - - EFX_POPULATE_DWORD_2(dword, - ERF_DD_EVQ_IND_RPTR_FLAGS, - EFE_DD_EVQ_IND_RPTR_FLAGS_HIGH, - ERF_DD_EVQ_IND_RPTR, - (rptr >> ERF_DD_EVQ_IND_RPTR_WIDTH)); - EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index, - &dword, B_FALSE); - - EFX_POPULATE_DWORD_2(dword, - ERF_DD_EVQ_IND_RPTR_FLAGS, - EFE_DD_EVQ_IND_RPTR_FLAGS_LOW, - ERF_DD_EVQ_IND_RPTR, - rptr & ((1 << ERF_DD_EVQ_IND_RPTR_WIDTH) - 1)); - EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index, - &dword, B_FALSE); - } else { - EFX_POPULATE_DWORD_1(dword, ERF_DZ_EVQ_RPTR, rptr); - EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_RPTR_REG, eep->ee_index, - &dword, B_FALSE); - } - - return (0); -} - -static __checkReturn efx_rc_t -efx_mcdi_driver_event( - __in efx_nic_t *enp, - __in uint32_t evq, - __in efx_qword_t data) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_DRIVER_EVENT_IN_LEN, - MC_CMD_DRIVER_EVENT_OUT_LEN)]; - efx_rc_t rc; - - req.emr_cmd = MC_CMD_DRIVER_EVENT; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_DRIVER_EVENT_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_DRIVER_EVENT_OUT_LEN; - - MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_EVQ, evq); - - MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_LO, - EFX_QWORD_FIELD(data, EFX_DWORD_0)); - MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_HI, - EFX_QWORD_FIELD(data, EFX_DWORD_1)); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_ev_qpost( - __in efx_evq_t *eep, - __in uint16_t data) -{ - efx_nic_t *enp = eep->ee_enp; - efx_qword_t event; - - EFX_POPULATE_QWORD_3(event, - ESF_DZ_DRV_CODE, ESE_DZ_EV_CODE_DRV_GEN_EV, - ESF_DZ_DRV_SUB_CODE, 0, - ESF_DZ_DRV_SUB_DATA_DW0, (uint32_t)data); - - (void) efx_mcdi_driver_event(enp, eep->ee_index, event); -} - - __checkReturn efx_rc_t -ef10_ev_qmoderate( - __in efx_evq_t *eep, - __in unsigned int us) -{ - efx_nic_t *enp = eep->ee_enp; - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_dword_t dword; - uint32_t timer_val, mode; - efx_rc_t rc; - - if (us > encp->enc_evq_timer_max_us) { - rc = EINVAL; - goto fail1; - } - - /* If the value is zero then disable the timer */ - if (us == 0) { - timer_val = 0; - mode = FFE_CZ_TIMER_MODE_DIS; - } else { - /* Calculate the timer value in quanta */ - timer_val = us * 1000 / encp->enc_evq_timer_quantum_ns; - - /* Moderation value is base 0 so we need to deduct 1 */ - if (timer_val > 0) - timer_val--; - - mode = FFE_CZ_TIMER_MODE_INT_HLDOFF; - } - - if (encp->enc_bug35388_workaround) { - EFX_POPULATE_DWORD_3(dword, - ERF_DD_EVQ_IND_TIMER_FLAGS, - EFE_DD_EVQ_IND_TIMER_FLAGS, - ERF_DD_EVQ_IND_TIMER_MODE, mode, - ERF_DD_EVQ_IND_TIMER_VAL, timer_val); - EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, - eep->ee_index, &dword, 0); - } else { - EFX_POPULATE_DWORD_2(dword, - ERF_DZ_TC_TIMER_MODE, mode, - ERF_DZ_TC_TIMER_VAL, timer_val); - EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_TMR_REG, - eep->ee_index, &dword, 0); - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -#if EFSYS_OPT_QSTATS - void -ef10_ev_qstats_update( - __in efx_evq_t *eep, - __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) -{ - unsigned int id; - - for (id = 0; id < EV_NQSTATS; id++) { - efsys_stat_t *essp = &stat[id]; - - EFSYS_STAT_INCR(essp, eep->ee_stat[id]); - eep->ee_stat[id] = 0; - } -} -#endif /* EFSYS_OPT_QSTATS */ - - -static __checkReturn boolean_t -ef10_ev_rx( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg) -{ - efx_nic_t *enp = eep->ee_enp; - uint32_t size; - uint32_t label; - uint32_t mac_class; - uint32_t eth_tag_class; - uint32_t l3_class; - uint32_t l4_class; - uint32_t next_read_lbits; - uint16_t flags; - boolean_t cont; - boolean_t should_abort; - efx_evq_rxq_state_t *eersp; - unsigned int desc_count; - unsigned int last_used_id; - - EFX_EV_QSTAT_INCR(eep, EV_RX); - - /* Discard events after RXQ/TXQ errors */ - if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR)) - return (B_FALSE); - - /* Basic packet information */ - size = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_BYTES); - next_read_lbits = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DSC_PTR_LBITS); - label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL); - eth_tag_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ETH_TAG_CLASS); - mac_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_MAC_CLASS); - l3_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L3_CLASS); - l4_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L4_CLASS); - cont = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_CONT); - - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DROP_EVENT) != 0) { - /* Drop this event */ - return (B_FALSE); - } - flags = 0; - - if (cont != 0) { - /* - * This may be part of a scattered frame, or it may be a - * truncated frame if scatter is disabled on this RXQ. - * Overlength frames can be received if e.g. a VF is configured - * for 1500 MTU but connected to a port set to 9000 MTU - * (see bug56567). - * FIXME: There is not yet any driver that supports scatter on - * Huntington. Scatter support is required for OSX. - */ - flags |= EFX_PKT_CONT; - } - - if (mac_class == ESE_DZ_MAC_CLASS_UCAST) - flags |= EFX_PKT_UNICAST; - - /* Increment the count of descriptors read */ - eersp = &eep->ee_rxq_state[label]; - desc_count = (next_read_lbits - eersp->eers_rx_read_ptr) & - EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); - eersp->eers_rx_read_ptr += desc_count; - - /* - * FIXME: add error checking to make sure this a batched event. - * This could also be an aborted scatter, see Bug36629. - */ - if (desc_count > 1) { - EFX_EV_QSTAT_INCR(eep, EV_RX_BATCH); - flags |= EFX_PKT_PREFIX_LEN; - } - - /* Calculate the index of the the last descriptor consumed */ - last_used_id = (eersp->eers_rx_read_ptr - 1) & eersp->eers_rx_mask; - - /* Check for errors that invalidate checksum and L3/L4 fields */ - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECC_ERR) != 0) { - /* RX frame truncated (error flag is misnamed) */ - EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC); - flags |= EFX_DISCARD; - goto deliver; - } - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECRC_ERR) != 0) { - /* Bad Ethernet frame CRC */ - EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR); - flags |= EFX_DISCARD; - goto deliver; - } - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_PARSE_INCOMPLETE)) { - /* - * Hardware parse failed, due to malformed headers - * or headers that are too long for the parser. - * Headers and checksums must be validated by the host. - */ - // TODO: EFX_EV_QSTAT_INCR(eep, EV_RX_PARSE_INCOMPLETE); - goto deliver; - } - - if ((eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN1) || - (eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN2)) { - flags |= EFX_PKT_VLAN_TAGGED; - } - - switch (l3_class) { - case ESE_DZ_L3_CLASS_IP4: - case ESE_DZ_L3_CLASS_IP4_FRAG: - flags |= EFX_PKT_IPV4; - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_IPCKSUM_ERR)) { - EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR); - } else { - flags |= EFX_CKSUM_IPV4; - } - - if (l4_class == ESE_DZ_L4_CLASS_TCP) { - EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4); - flags |= EFX_PKT_TCP; - } else if (l4_class == ESE_DZ_L4_CLASS_UDP) { - EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4); - flags |= EFX_PKT_UDP; - } else { - EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4); - } - break; - - case ESE_DZ_L3_CLASS_IP6: - case ESE_DZ_L3_CLASS_IP6_FRAG: - flags |= EFX_PKT_IPV6; - - if (l4_class == ESE_DZ_L4_CLASS_TCP) { - EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6); - flags |= EFX_PKT_TCP; - } else if (l4_class == ESE_DZ_L4_CLASS_UDP) { - EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6); - flags |= EFX_PKT_UDP; - } else { - EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6); - } - break; - - default: - EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP); - break; - } - - if (flags & (EFX_PKT_TCP | EFX_PKT_UDP)) { - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_TCPUDP_CKSUM_ERR)) { - EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR); - } else { - flags |= EFX_CKSUM_TCPUDP; - } - } - -deliver: - /* If we're not discarding the packet then it is ok */ - if (~flags & EFX_DISCARD) - EFX_EV_QSTAT_INCR(eep, EV_RX_OK); - - EFSYS_ASSERT(eecp->eec_rx != NULL); - should_abort = eecp->eec_rx(arg, label, last_used_id, size, flags); - - return (should_abort); -} - -static __checkReturn boolean_t -ef10_ev_tx( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg) -{ - efx_nic_t *enp = eep->ee_enp; - uint32_t id; - uint32_t label; - boolean_t should_abort; - - EFX_EV_QSTAT_INCR(eep, EV_TX); - - /* Discard events after RXQ/TXQ errors */ - if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR)) - return (B_FALSE); - - if (EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DROP_EVENT) != 0) { - /* Drop this event */ - return (B_FALSE); - } - - /* Per-packet TX completion (was per-descriptor for Falcon/Siena) */ - id = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DESCR_INDX); - label = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_QLABEL); - - EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id); - - EFSYS_ASSERT(eecp->eec_tx != NULL); - should_abort = eecp->eec_tx(arg, label, id); - - return (should_abort); -} - -static __checkReturn boolean_t -ef10_ev_driver( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg) -{ - unsigned int code; - boolean_t should_abort; - - EFX_EV_QSTAT_INCR(eep, EV_DRIVER); - should_abort = B_FALSE; - - code = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_CODE); - switch (code) { - case ESE_DZ_DRV_TIMER_EV: { - uint32_t id; - - id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_TMR_ID); - - EFSYS_ASSERT(eecp->eec_timer != NULL); - should_abort = eecp->eec_timer(arg, id); - break; - } - - case ESE_DZ_DRV_WAKE_UP_EV: { - uint32_t id; - - id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_EVQ_ID); - - EFSYS_ASSERT(eecp->eec_wake_up != NULL); - should_abort = eecp->eec_wake_up(arg, id); - break; - } - - case ESE_DZ_DRV_START_UP_EV: - EFSYS_ASSERT(eecp->eec_initialized != NULL); - should_abort = eecp->eec_initialized(arg); - break; - - default: - EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); - break; - } - - return (should_abort); -} - -static __checkReturn boolean_t -ef10_ev_drv_gen( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg) -{ - uint32_t data; - boolean_t should_abort; - - EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN); - should_abort = B_FALSE; - - data = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_DATA_DW0); - if (data >= ((uint32_t)1 << 16)) { - EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); - - return (B_TRUE); - } - - EFSYS_ASSERT(eecp->eec_software != NULL); - should_abort = eecp->eec_software(arg, (uint16_t)data); - - return (should_abort); -} - -static __checkReturn boolean_t -ef10_ev_mcdi( - __in efx_evq_t *eep, - __in efx_qword_t *eqp, - __in const efx_ev_callbacks_t *eecp, - __in_opt void *arg) -{ - efx_nic_t *enp = eep->ee_enp; - unsigned code; - boolean_t should_abort = B_FALSE; - - EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE); - - code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE); - switch (code) { - case MCDI_EVENT_CODE_BADSSERT: - efx_mcdi_ev_death(enp, EINTR); - break; - - case MCDI_EVENT_CODE_CMDDONE: - efx_mcdi_ev_cpl(enp, - MCDI_EV_FIELD(eqp, CMDDONE_SEQ), - MCDI_EV_FIELD(eqp, CMDDONE_DATALEN), - MCDI_EV_FIELD(eqp, CMDDONE_ERRNO)); - break; - -#if EFSYS_OPT_MCDI_PROXY_AUTH - case MCDI_EVENT_CODE_PROXY_RESPONSE: - /* - * This event notifies a function that an authorization request - * has been processed. If the request was authorized then the - * function can now re-send the original MCDI request. - * See SF-113652-SW "SR-IOV Proxied Network Access Control". - */ - efx_mcdi_ev_proxy_response(enp, - MCDI_EV_FIELD(eqp, PROXY_RESPONSE_HANDLE), - MCDI_EV_FIELD(eqp, PROXY_RESPONSE_RC)); - break; -#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ - - case MCDI_EVENT_CODE_LINKCHANGE: { - efx_link_mode_t link_mode; - - ef10_phy_link_ev(enp, eqp, &link_mode); - should_abort = eecp->eec_link_change(arg, link_mode); - break; - } - - case MCDI_EVENT_CODE_SENSOREVT: { -#if EFSYS_OPT_MON_STATS - efx_mon_stat_t id; - efx_mon_stat_value_t value; - efx_rc_t rc; - - /* Decode monitor stat for MCDI sensor (if supported) */ - if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0) { - /* Report monitor stat change */ - should_abort = eecp->eec_monitor(arg, id, value); - } else if (rc == ENOTSUP) { - should_abort = eecp->eec_exception(arg, - EFX_EXCEPTION_UNKNOWN_SENSOREVT, - MCDI_EV_FIELD(eqp, DATA)); - } else { - EFSYS_ASSERT(rc == ENODEV); /* Wrong port */ - } -#endif - break; - } - - case MCDI_EVENT_CODE_SCHEDERR: - /* Informational only */ - break; - - case MCDI_EVENT_CODE_REBOOT: - /* Falcon/Siena only (should not been seen with Huntington). */ - efx_mcdi_ev_death(enp, EIO); - break; - - case MCDI_EVENT_CODE_MC_REBOOT: - /* MC_REBOOT event is used for Huntington (EF10) and later. */ - efx_mcdi_ev_death(enp, EIO); - break; - - case MCDI_EVENT_CODE_MAC_STATS_DMA: -#if EFSYS_OPT_MAC_STATS - if (eecp->eec_mac_stats != NULL) { - eecp->eec_mac_stats(arg, - MCDI_EV_FIELD(eqp, MAC_STATS_DMA_GENERATION)); - } -#endif - break; - - case MCDI_EVENT_CODE_FWALERT: { - uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON); - - if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS) - should_abort = eecp->eec_exception(arg, - EFX_EXCEPTION_FWALERT_SRAM, - MCDI_EV_FIELD(eqp, FWALERT_DATA)); - else - should_abort = eecp->eec_exception(arg, - EFX_EXCEPTION_UNKNOWN_FWALERT, - MCDI_EV_FIELD(eqp, DATA)); - break; - } - - case MCDI_EVENT_CODE_TX_ERR: { - /* - * After a TXQ error is detected, firmware sends a TX_ERR event. - * This may be followed by TX completions (which we discard), - * and then finally by a TX_FLUSH event. Firmware destroys the - * TXQ automatically after sending the TX_FLUSH event. - */ - enp->en_reset_flags |= EFX_RESET_TXQ_ERR; - - EFSYS_PROBE1(tx_descq_err, uint32_t, MCDI_EV_FIELD(eqp, DATA)); - - /* Inform the driver that a reset is required. */ - eecp->eec_exception(arg, EFX_EXCEPTION_TX_ERROR, - MCDI_EV_FIELD(eqp, TX_ERR_DATA)); - break; - } - - case MCDI_EVENT_CODE_TX_FLUSH: { - uint32_t txq_index = MCDI_EV_FIELD(eqp, TX_FLUSH_TXQ); - - /* - * EF10 firmware sends two TX_FLUSH events: one to the txq's - * event queue, and one to evq 0 (with TX_FLUSH_TO_DRIVER set). - * We want to wait for all completions, so ignore the events - * with TX_FLUSH_TO_DRIVER. - */ - if (MCDI_EV_FIELD(eqp, TX_FLUSH_TO_DRIVER) != 0) { - should_abort = B_FALSE; - break; - } - - EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE); - - EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index); - - EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL); - should_abort = eecp->eec_txq_flush_done(arg, txq_index); - break; - } - - case MCDI_EVENT_CODE_RX_ERR: { - /* - * After an RXQ error is detected, firmware sends an RX_ERR - * event. This may be followed by RX events (which we discard), - * and then finally by an RX_FLUSH event. Firmware destroys the - * RXQ automatically after sending the RX_FLUSH event. - */ - enp->en_reset_flags |= EFX_RESET_RXQ_ERR; - - EFSYS_PROBE1(rx_descq_err, uint32_t, MCDI_EV_FIELD(eqp, DATA)); - - /* Inform the driver that a reset is required. */ - eecp->eec_exception(arg, EFX_EXCEPTION_RX_ERROR, - MCDI_EV_FIELD(eqp, RX_ERR_DATA)); - break; - } - - case MCDI_EVENT_CODE_RX_FLUSH: { - uint32_t rxq_index = MCDI_EV_FIELD(eqp, RX_FLUSH_RXQ); - - /* - * EF10 firmware sends two RX_FLUSH events: one to the rxq's - * event queue, and one to evq 0 (with RX_FLUSH_TO_DRIVER set). - * We want to wait for all completions, so ignore the events - * with RX_FLUSH_TO_DRIVER. - */ - if (MCDI_EV_FIELD(eqp, RX_FLUSH_TO_DRIVER) != 0) { - should_abort = B_FALSE; - break; - } - - EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE); - - EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index); - - EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL); - should_abort = eecp->eec_rxq_flush_done(arg, rxq_index); - break; - } - - default: - EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), - uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); - break; - } - - return (should_abort); -} - - void -ef10_ev_rxlabel_init( - __in efx_evq_t *eep, - __in efx_rxq_t *erp, - __in unsigned int label) -{ - efx_evq_rxq_state_t *eersp; - - EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state)); - eersp = &eep->ee_rxq_state[label]; - - EFSYS_ASSERT3U(eersp->eers_rx_mask, ==, 0); - - eersp->eers_rx_read_ptr = 0; - eersp->eers_rx_mask = erp->er_mask; -} - - void -ef10_ev_rxlabel_fini( - __in efx_evq_t *eep, - __in unsigned int label) -{ - efx_evq_rxq_state_t *eersp; - - EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state)); - eersp = &eep->ee_rxq_state[label]; - - EFSYS_ASSERT3U(eersp->eers_rx_mask, !=, 0); - - eersp->eers_rx_read_ptr = 0; - eersp->eers_rx_mask = 0; -} - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_ev.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/hunt_mac.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_mac.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_mac.c (nonexistent) @@ -1,752 +0,0 @@ -/*- - * Copyright (c) 2012-2015 Solarflare Communications 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: - * - * 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 OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are - * those of the authors and should not be interpreted as representing official - * policies, either expressed or implied, of the FreeBSD Project. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "efx.h" -#include "efx_impl.h" - - -#if EFSYS_OPT_HUNTINGTON - - __checkReturn efx_rc_t -ef10_mac_poll( - __in efx_nic_t *enp, - __out efx_link_mode_t *link_modep) -{ - efx_port_t *epp = &(enp->en_port); - ef10_link_state_t els; - efx_rc_t rc; - - if ((rc = ef10_phy_get_link(enp, &els)) != 0) - goto fail1; - - epp->ep_adv_cap_mask = els.els_adv_cap_mask; - epp->ep_fcntl = els.els_fcntl; - - *link_modep = els.els_link_mode; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - *link_modep = EFX_LINK_UNKNOWN; - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mac_up( - __in efx_nic_t *enp, - __out boolean_t *mac_upp) -{ - ef10_link_state_t els; - efx_rc_t rc; - - /* - * Because EF10 doesn't *require* polling, we can't rely on - * ef10_mac_poll() being executed to populate epp->ep_mac_up. - */ - if ((rc = ef10_phy_get_link(enp, &els)) != 0) - goto fail1; - - *mac_upp = els.els_mac_up; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* - * EF10 adapters use MC_CMD_VADAPTOR_SET_MAC to set the - * MAC address; the address field in MC_CMD_SET_MAC has no - * effect. - * MC_CMD_VADAPTOR_SET_MAC requires mac-spoofing privilege and - * the port to have no filters or queues active. - */ -static __checkReturn efx_rc_t -efx_mcdi_vadapter_set_mac( - __in efx_nic_t *enp) -{ - efx_port_t *epp = &(enp->en_port); - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VADAPTOR_SET_MAC_IN_LEN, - MC_CMD_VADAPTOR_SET_MAC_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VADAPTOR_SET_MAC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VADAPTOR_SET_MAC_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VADAPTOR_SET_MAC_OUT_LEN; - - MCDI_IN_SET_DWORD(req, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, - enp->en_vport_id); - EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, VADAPTOR_SET_MAC_IN_MACADDR), - epp->ep_mac_addr); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mac_addr_set( - __in efx_nic_t *enp) -{ - efx_rc_t rc; - - if ((rc = efx_mcdi_vadapter_set_mac(enp)) != 0) { - if (rc != ENOTSUP) - goto fail1; - - /* - * Fallback for older Huntington firmware without Vadapter - * support. - */ - if ((rc = ef10_mac_reconfigure(enp)) != 0) - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_mtu_set( - __in efx_nic_t *enp, - __in uint32_t mtu) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_SET_MAC_EXT_IN_LEN, - MC_CMD_SET_MAC_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_MAC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_MAC_EXT_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; - - /* Only configure the MTU in this call to MC_CMD_SET_MAC */ - MCDI_IN_SET_DWORD(req, SET_MAC_EXT_IN_MTU, mtu); - MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_EXT_IN_CONTROL, - SET_MAC_EXT_IN_CFG_MTU, 1); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mac_pdu_set( - __in efx_nic_t *enp) -{ - efx_port_t *epp = &(enp->en_port); - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_rc_t rc; - - if (encp->enc_enhanced_set_mac_supported) { - if ((rc = efx_mcdi_mtu_set(enp, epp->ep_mac_pdu)) != 0) - goto fail1; - } else { - /* - * Fallback for older Huntington firmware, which always - * configure all of the parameters to MC_CMD_SET_MAC. This isn't - * suitable for setting the MTU on unpriviliged functions. - */ - if ((rc = ef10_mac_reconfigure(enp)) != 0) - goto fail2; - } - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -__checkReturn efx_rc_t -ef10_mac_reconfigure( - __in efx_nic_t *enp) -{ - efx_port_t *epp = &(enp->en_port); - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN, - MC_CMD_SET_MAC_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_MAC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_MAC_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; - - MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu); - MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0); - EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR), - epp->ep_mac_addr); - - /* - * Note: The Huntington MAC does not support REJECT_BRDCST. - * The REJECT_UNCST flag will also prevent multicast traffic - * from reaching the filters. As Huntington filters drop any - * traffic that does not match a filter it is ok to leave the - * MAC running in promiscuous mode. See bug41141. - * - * FIXME: Does REJECT_UNCST behave the same way on Medford? - */ - MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT, - SET_MAC_IN_REJECT_UNCST, 0, - SET_MAC_IN_REJECT_BRDCST, 0); - - /* - * Flow control, whether it is auto-negotiated or not, - * is set via the PHY advertised capabilities. When set to - * automatic the MAC will use the PHY settings to determine - * the flow control settings. - */ - MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, MC_CMD_FCNTL_AUTO); - - /* Do not include the Ethernet frame checksum in RX packets */ - MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_IN_FLAGS, - SET_MAC_IN_FLAG_INCLUDE_FCS, 0); - - efx_mcdi_execute_quiet(enp, &req); - - if (req.emr_rc != 0) { - /* - * Unprivileged functions cannot control link state, - * but still need to configure filters. - */ - if (req.emr_rc != EACCES) { - rc = req.emr_rc; - goto fail1; - } - } - - /* - * Apply the filters for the MAC configuration. - * If the NIC isn't ready to accept filters this may - * return success without setting anything. - */ - rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, - epp->ep_all_unicst, epp->ep_mulcst, - epp->ep_all_mulcst, epp->ep_brdcst, - epp->ep_mulcst_addr_list, - epp->ep_mulcst_addr_count); - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mac_multicast_list_set( - __in efx_nic_t *enp) -{ - efx_port_t *epp = &(enp->en_port); - const efx_mac_ops_t *emop = epp->ep_emop; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - if ((rc = emop->emo_reconfigure(enp)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_mac_filter_default_rxq_set( - __in efx_nic_t *enp, - __in efx_rxq_t *erp, - __in boolean_t using_rss) -{ - efx_port_t *epp = &(enp->en_port); - efx_rxq_t *old_rxq; - boolean_t old_using_rss; - efx_rc_t rc; - - ef10_filter_get_default_rxq(enp, &old_rxq, &old_using_rss); - - ef10_filter_default_rxq_set(enp, erp, using_rss); - - rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, - epp->ep_all_unicst, epp->ep_mulcst, - epp->ep_all_mulcst, epp->ep_brdcst, - epp->ep_mulcst_addr_list, - epp->ep_mulcst_addr_count); - - if (rc != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - ef10_filter_default_rxq_set(enp, old_rxq, old_using_rss); - - return (rc); -} - - void -ef10_mac_filter_default_rxq_clear( - __in efx_nic_t *enp) -{ - efx_port_t *epp = &(enp->en_port); - - ef10_filter_default_rxq_clear(enp); - - efx_filter_reconfigure(enp, epp->ep_mac_addr, - epp->ep_all_unicst, epp->ep_mulcst, - epp->ep_all_mulcst, epp->ep_brdcst, - epp->ep_mulcst_addr_list, - epp->ep_mulcst_addr_count); -} - - -#if EFSYS_OPT_LOOPBACK - - __checkReturn efx_rc_t -ef10_mac_loopback_set( - __in efx_nic_t *enp, - __in efx_link_mode_t link_mode, - __in efx_loopback_type_t loopback_type) -{ - efx_port_t *epp = &(enp->en_port); - const efx_phy_ops_t *epop = epp->ep_epop; - efx_loopback_type_t old_loopback_type; - efx_link_mode_t old_loopback_link_mode; - efx_rc_t rc; - - /* The PHY object handles this on EF10 */ - old_loopback_type = epp->ep_loopback_type; - old_loopback_link_mode = epp->ep_loopback_link_mode; - epp->ep_loopback_type = loopback_type; - epp->ep_loopback_link_mode = link_mode; - - if ((rc = epop->epo_reconfigure(enp)) != 0) - goto fail1; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - epp->ep_loopback_type = old_loopback_type; - epp->ep_loopback_link_mode = old_loopback_link_mode; - - return (rc); -} - -#endif /* EFSYS_OPT_LOOPBACK */ - -#if EFSYS_OPT_MAC_STATS - -#define EF10_MAC_STAT_READ(_esmp, _field, _eqp) \ - EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp) - - - __checkReturn efx_rc_t -ef10_mac_stats_update( - __in efx_nic_t *enp, - __in efsys_mem_t *esmp, - __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat, - __inout_opt uint32_t *generationp) -{ - efx_qword_t value; - efx_qword_t generation_start; - efx_qword_t generation_end; - - _NOTE(ARGUNUSED(enp)) - - /* Read END first so we don't race with the MC */ - EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END, - &generation_end); - EFSYS_MEM_READ_BARRIER(); - - /* TX */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_CONTROL_PKTS, &value); - EFSYS_STAT_SUBR_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PAUSE_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PAUSE_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_UNICAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_UNICST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTICAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULTICST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BROADCAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_BRDCST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BYTES, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_OCTETS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_128_TO_255_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_128_TO_255_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_256_TO_511_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_256_TO_511_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_512_TO_1023_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_512_TO_1023_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_1024_TO_15XX_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_1024_TO_15XX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_GTJUMBO_PKTS, &value); - EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BAD_FCS_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_SGL_COL_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULT_COL_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_COL_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LATE_COLLISION_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LATE_COL_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_DEFERRED_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_DEF_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value); - - /* RX */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNICAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_UNICST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MULTICAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MULTICST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BROADCAST_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_BRDCST_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PAUSE_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PAUSE_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNDERSIZE_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_64_PKTS, &value); - EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_65_TO_127_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_65_TO_127_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_128_TO_255_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_128_TO_255_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_256_TO_511_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_256_TO_511_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_512_TO_1023_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_512_TO_1023_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_1024_TO_15XX_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_1024_TO_15XX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_GTJUMBO_PKTS, &value); - EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BAD_FCS_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FCS_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_OVERFLOW_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_DROP_EVENTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_FALSE_CARRIER_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FALSE_CARRIER_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_SYMBOL_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_ALIGN_ERROR_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_ALIGN_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_INTERNAL_ERRORS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_JABBER_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_JABBER_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_CHAR_ERR, &value); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_CHAR_ERR]), - &(value.eq_dword[0])); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_CHAR_ERR]), - &(value.eq_dword[1])); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_CHAR_ERR, &value); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_CHAR_ERR]), - &(value.eq_dword[0])); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_CHAR_ERR]), - &(value.eq_dword[1])); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_DISP_ERR, &value); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_DISP_ERR]), - &(value.eq_dword[0])); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_DISP_ERR]), - &(value.eq_dword[1])); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_DISP_ERR, &value); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_DISP_ERR]), - &(value.eq_dword[0])); - EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_DISP_ERR]), - &(value.eq_dword[1])); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MATCH_FAULT, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MATCH_FAULT]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value); - - /* Packet memory (EF10 only) */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_BB_OVERFLOW, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_BB_OVERFLOW]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_BB_OVERFLOW, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_BB_OVERFLOW]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_VFIFO_FULL, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_VFIFO_FULL]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_VFIFO_FULL, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_VFIFO_FULL]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_QBB, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_QBB]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_QBB, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_QBB]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_MAPPING, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_MAPPING]), &value); - - /* RX datapath */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_Q_DISABLED_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_Q_DISABLED_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_DI_DROPPED_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_DI_DROPPED_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_STREAMING_PKTS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_STREAMING_PKTS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_FETCH]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_WAIT_CONDITIONS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_WAIT]), &value); - - - /* VADAPTER RX */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_BYTES, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_BYTES]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_OVERFLOW, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_OVERFLOW]), &value); - - /* VADAPTER TX */ - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_PACKETS, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_PACKETS]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_BYTES, - &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES]), - &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_PACKETS, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_PACKETS]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_BYTES, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_BYTES]), &value); - - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_OVERFLOW, &value); - EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_OVERFLOW]), &value); - - - EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); - EFSYS_MEM_READ_BARRIER(); - EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START, - &generation_start); - - /* Check that we didn't read the stats in the middle of a DMA */ - /* Not a good enough check ? */ - if (memcmp(&generation_start, &generation_end, - sizeof (generation_start))) - return (EAGAIN); - - if (generationp) - *generationp = EFX_QWORD_FIELD(generation_start, EFX_DWORD_0); - - return (0); -} - -#endif /* EFSYS_OPT_MAC_STATS */ - -#endif /* EFSYS_OPT_HUNTINGTON */ Property changes on: stable/10/sys/dev/sfxge/common/hunt_mac.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_ev.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_ev.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_ev.c (revision 301344) @@ -0,0 +1,988 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" +#if EFSYS_OPT_MON_STATS +#include "mcdi_mon.h" +#endif + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#if EFSYS_OPT_QSTATS +#define EFX_EV_QSTAT_INCR(_eep, _stat) \ + do { \ + (_eep)->ee_stat[_stat]++; \ + _NOTE(CONSTANTCONDITION) \ + } while (B_FALSE) +#else +#define EFX_EV_QSTAT_INCR(_eep, _stat) +#endif + + +static __checkReturn boolean_t +ef10_ev_rx( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg); + +static __checkReturn boolean_t +ef10_ev_tx( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg); + +static __checkReturn boolean_t +ef10_ev_driver( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg); + +static __checkReturn boolean_t +ef10_ev_drv_gen( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg); + +static __checkReturn boolean_t +ef10_ev_mcdi( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg); + + +static __checkReturn efx_rc_t +efx_mcdi_init_evq( + __in efx_nic_t *enp, + __in unsigned int instance, + __in efsys_mem_t *esmp, + __in size_t nevs, + __in uint32_t irq, + __out_opt uint32_t *irqp) +{ + efx_mcdi_req_t req; + uint8_t payload[ + MAX(MC_CMD_INIT_EVQ_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)), + MC_CMD_INIT_EVQ_OUT_LEN)]; + efx_qword_t *dma_addr; + uint64_t addr; + int npages; + int i; + int supports_rx_batching; + efx_rc_t rc; + + npages = EFX_EVQ_NBUFS(nevs); + if (MC_CMD_INIT_EVQ_IN_LEN(npages) > MC_CMD_INIT_EVQ_IN_LENMAX) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_INIT_EVQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages); + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs); + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance); + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq); + + /* + * On Huntington RX and TX event batching can only be requested + * together (even if the datapath firmware doesn't actually support RX + * batching). + * Cut through is incompatible with RX batching and so enabling cut + * through disables RX batching (but it does not affect TX batching). + * + * So always enable RX and TX event batching, and enable cut through + * if RX event batching isn't supported (i.e. on low latency firmware). + */ + supports_rx_batching = enp->en_nic_cfg.enc_rx_batching_enabled ? 1 : 0; + MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS, + INIT_EVQ_IN_FLAG_INTERRUPTING, 1, + INIT_EVQ_IN_FLAG_RPTR_DOS, 0, + INIT_EVQ_IN_FLAG_INT_ARMD, 0, + INIT_EVQ_IN_FLAG_CUT_THRU, !supports_rx_batching, + INIT_EVQ_IN_FLAG_RX_MERGE, 1, + INIT_EVQ_IN_FLAG_TX_MERGE, 1); + + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE, + MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS); + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0); + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0); + + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE, + MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS); + MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0); + + dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_IN_DMA_ADDR); + addr = EFSYS_MEM_ADDR(esmp); + + for (i = 0; i < npages; i++) { + EFX_POPULATE_QWORD_2(*dma_addr, + EFX_DWORD_1, (uint32_t)(addr >> 32), + EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); + + dma_addr++; + addr += EFX_BUF_SIZE; + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + if (irqp != NULL) + *irqp = MCDI_OUT_DWORD(req, INIT_EVQ_OUT_IRQ); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_fini_evq( + __in efx_nic_t *enp, + __in uint32_t instance) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FINI_EVQ_IN_LEN, + MC_CMD_FINI_EVQ_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FINI_EVQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + + __checkReturn efx_rc_t +ef10_ev_init( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) + return (0); +} + + void +ef10_ev_fini( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + + __checkReturn efx_rc_t +ef10_ev_qcreate( + __in efx_nic_t *enp, + __in unsigned int index, + __in efsys_mem_t *esmp, + __in size_t n, + __in uint32_t id, + __in efx_evq_t *eep) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t irq; + efx_rc_t rc; + + _NOTE(ARGUNUSED(id)) /* buftbl id managed by MC */ + EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS)); + EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS)); + + if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) { + rc = EINVAL; + goto fail1; + } + + if (index >= encp->enc_evq_limit) { + rc = EINVAL; + goto fail2; + } + + /* Set up the handler table */ + eep->ee_rx = ef10_ev_rx; + eep->ee_tx = ef10_ev_tx; + eep->ee_driver = ef10_ev_driver; + eep->ee_drv_gen = ef10_ev_drv_gen; + eep->ee_mcdi = ef10_ev_mcdi; + + /* + * Set up the event queue + * NOTE: ignore the returned IRQ param as firmware does not set it. + */ + irq = index; /* INIT_EVQ expects function-relative vector number */ + if ((rc = efx_mcdi_init_evq(enp, index, esmp, n, irq, NULL)) != 0) + goto fail3; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_ev_qdestroy( + __in efx_evq_t *eep) +{ + efx_nic_t *enp = eep->ee_enp; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) efx_mcdi_fini_evq(eep->ee_enp, eep->ee_index); +} + + __checkReturn efx_rc_t +ef10_ev_qprime( + __in efx_evq_t *eep, + __in unsigned int count) +{ + efx_nic_t *enp = eep->ee_enp; + uint32_t rptr; + efx_dword_t dword; + + rptr = count & eep->ee_mask; + + if (enp->en_nic_cfg.enc_bug35388_workaround) { + EFX_STATIC_ASSERT(EFX_EVQ_MINNEVS > + (1 << ERF_DD_EVQ_IND_RPTR_WIDTH)); + EFX_STATIC_ASSERT(EFX_EVQ_MAXNEVS < + (1 << 2 * ERF_DD_EVQ_IND_RPTR_WIDTH)); + + EFX_POPULATE_DWORD_2(dword, + ERF_DD_EVQ_IND_RPTR_FLAGS, + EFE_DD_EVQ_IND_RPTR_FLAGS_HIGH, + ERF_DD_EVQ_IND_RPTR, + (rptr >> ERF_DD_EVQ_IND_RPTR_WIDTH)); + EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index, + &dword, B_FALSE); + + EFX_POPULATE_DWORD_2(dword, + ERF_DD_EVQ_IND_RPTR_FLAGS, + EFE_DD_EVQ_IND_RPTR_FLAGS_LOW, + ERF_DD_EVQ_IND_RPTR, + rptr & ((1 << ERF_DD_EVQ_IND_RPTR_WIDTH) - 1)); + EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, eep->ee_index, + &dword, B_FALSE); + } else { + EFX_POPULATE_DWORD_1(dword, ERF_DZ_EVQ_RPTR, rptr); + EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_RPTR_REG, eep->ee_index, + &dword, B_FALSE); + } + + return (0); +} + +static __checkReturn efx_rc_t +efx_mcdi_driver_event( + __in efx_nic_t *enp, + __in uint32_t evq, + __in efx_qword_t data) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_DRIVER_EVENT_IN_LEN, + MC_CMD_DRIVER_EVENT_OUT_LEN)]; + efx_rc_t rc; + + req.emr_cmd = MC_CMD_DRIVER_EVENT; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_DRIVER_EVENT_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_DRIVER_EVENT_OUT_LEN; + + MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_EVQ, evq); + + MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_LO, + EFX_QWORD_FIELD(data, EFX_DWORD_0)); + MCDI_IN_SET_DWORD(req, DRIVER_EVENT_IN_DATA_HI, + EFX_QWORD_FIELD(data, EFX_DWORD_1)); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_ev_qpost( + __in efx_evq_t *eep, + __in uint16_t data) +{ + efx_nic_t *enp = eep->ee_enp; + efx_qword_t event; + + EFX_POPULATE_QWORD_3(event, + ESF_DZ_DRV_CODE, ESE_DZ_EV_CODE_DRV_GEN_EV, + ESF_DZ_DRV_SUB_CODE, 0, + ESF_DZ_DRV_SUB_DATA_DW0, (uint32_t)data); + + (void) efx_mcdi_driver_event(enp, eep->ee_index, event); +} + + __checkReturn efx_rc_t +ef10_ev_qmoderate( + __in efx_evq_t *eep, + __in unsigned int us) +{ + efx_nic_t *enp = eep->ee_enp; + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_dword_t dword; + uint32_t timer_val, mode; + efx_rc_t rc; + + if (us > encp->enc_evq_timer_max_us) { + rc = EINVAL; + goto fail1; + } + + /* If the value is zero then disable the timer */ + if (us == 0) { + timer_val = 0; + mode = FFE_CZ_TIMER_MODE_DIS; + } else { + /* Calculate the timer value in quanta */ + timer_val = us * 1000 / encp->enc_evq_timer_quantum_ns; + + /* Moderation value is base 0 so we need to deduct 1 */ + if (timer_val > 0) + timer_val--; + + mode = FFE_CZ_TIMER_MODE_INT_HLDOFF; + } + + if (encp->enc_bug35388_workaround) { + EFX_POPULATE_DWORD_3(dword, + ERF_DD_EVQ_IND_TIMER_FLAGS, + EFE_DD_EVQ_IND_TIMER_FLAGS, + ERF_DD_EVQ_IND_TIMER_MODE, mode, + ERF_DD_EVQ_IND_TIMER_VAL, timer_val); + EFX_BAR_TBL_WRITED(enp, ER_DD_EVQ_INDIRECT, + eep->ee_index, &dword, 0); + } else { + EFX_POPULATE_DWORD_2(dword, + ERF_DZ_TC_TIMER_MODE, mode, + ERF_DZ_TC_TIMER_VAL, timer_val); + EFX_BAR_TBL_WRITED(enp, ER_DZ_EVQ_TMR_REG, + eep->ee_index, &dword, 0); + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +#if EFSYS_OPT_QSTATS + void +ef10_ev_qstats_update( + __in efx_evq_t *eep, + __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) +{ + unsigned int id; + + for (id = 0; id < EV_NQSTATS; id++) { + efsys_stat_t *essp = &stat[id]; + + EFSYS_STAT_INCR(essp, eep->ee_stat[id]); + eep->ee_stat[id] = 0; + } +} +#endif /* EFSYS_OPT_QSTATS */ + + +static __checkReturn boolean_t +ef10_ev_rx( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + efx_nic_t *enp = eep->ee_enp; + uint32_t size; + uint32_t label; + uint32_t mac_class; + uint32_t eth_tag_class; + uint32_t l3_class; + uint32_t l4_class; + uint32_t next_read_lbits; + uint16_t flags; + boolean_t cont; + boolean_t should_abort; + efx_evq_rxq_state_t *eersp; + unsigned int desc_count; + unsigned int last_used_id; + + EFX_EV_QSTAT_INCR(eep, EV_RX); + + /* Discard events after RXQ/TXQ errors */ + if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR)) + return (B_FALSE); + + /* Basic packet information */ + size = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_BYTES); + next_read_lbits = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DSC_PTR_LBITS); + label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL); + eth_tag_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ETH_TAG_CLASS); + mac_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_MAC_CLASS); + l3_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L3_CLASS); + l4_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L4_CLASS); + cont = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_CONT); + + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DROP_EVENT) != 0) { + /* Drop this event */ + return (B_FALSE); + } + flags = 0; + + if (cont != 0) { + /* + * This may be part of a scattered frame, or it may be a + * truncated frame if scatter is disabled on this RXQ. + * Overlength frames can be received if e.g. a VF is configured + * for 1500 MTU but connected to a port set to 9000 MTU + * (see bug56567). + * FIXME: There is not yet any driver that supports scatter on + * Huntington. Scatter support is required for OSX. + */ + flags |= EFX_PKT_CONT; + } + + if (mac_class == ESE_DZ_MAC_CLASS_UCAST) + flags |= EFX_PKT_UNICAST; + + /* Increment the count of descriptors read */ + eersp = &eep->ee_rxq_state[label]; + desc_count = (next_read_lbits - eersp->eers_rx_read_ptr) & + EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); + eersp->eers_rx_read_ptr += desc_count; + + /* + * FIXME: add error checking to make sure this a batched event. + * This could also be an aborted scatter, see Bug36629. + */ + if (desc_count > 1) { + EFX_EV_QSTAT_INCR(eep, EV_RX_BATCH); + flags |= EFX_PKT_PREFIX_LEN; + } + + /* Calculate the index of the the last descriptor consumed */ + last_used_id = (eersp->eers_rx_read_ptr - 1) & eersp->eers_rx_mask; + + /* Check for errors that invalidate checksum and L3/L4 fields */ + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECC_ERR) != 0) { + /* RX frame truncated (error flag is misnamed) */ + EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC); + flags |= EFX_DISCARD; + goto deliver; + } + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECRC_ERR) != 0) { + /* Bad Ethernet frame CRC */ + EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR); + flags |= EFX_DISCARD; + goto deliver; + } + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_PARSE_INCOMPLETE)) { + /* + * Hardware parse failed, due to malformed headers + * or headers that are too long for the parser. + * Headers and checksums must be validated by the host. + */ + // TODO: EFX_EV_QSTAT_INCR(eep, EV_RX_PARSE_INCOMPLETE); + goto deliver; + } + + if ((eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN1) || + (eth_tag_class == ESE_DZ_ETH_TAG_CLASS_VLAN2)) { + flags |= EFX_PKT_VLAN_TAGGED; + } + + switch (l3_class) { + case ESE_DZ_L3_CLASS_IP4: + case ESE_DZ_L3_CLASS_IP4_FRAG: + flags |= EFX_PKT_IPV4; + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_IPCKSUM_ERR)) { + EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR); + } else { + flags |= EFX_CKSUM_IPV4; + } + + if (l4_class == ESE_DZ_L4_CLASS_TCP) { + EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4); + flags |= EFX_PKT_TCP; + } else if (l4_class == ESE_DZ_L4_CLASS_UDP) { + EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4); + flags |= EFX_PKT_UDP; + } else { + EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4); + } + break; + + case ESE_DZ_L3_CLASS_IP6: + case ESE_DZ_L3_CLASS_IP6_FRAG: + flags |= EFX_PKT_IPV6; + + if (l4_class == ESE_DZ_L4_CLASS_TCP) { + EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6); + flags |= EFX_PKT_TCP; + } else if (l4_class == ESE_DZ_L4_CLASS_UDP) { + EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6); + flags |= EFX_PKT_UDP; + } else { + EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6); + } + break; + + default: + EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP); + break; + } + + if (flags & (EFX_PKT_TCP | EFX_PKT_UDP)) { + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_TCPUDP_CKSUM_ERR)) { + EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR); + } else { + flags |= EFX_CKSUM_TCPUDP; + } + } + +deliver: + /* If we're not discarding the packet then it is ok */ + if (~flags & EFX_DISCARD) + EFX_EV_QSTAT_INCR(eep, EV_RX_OK); + + EFSYS_ASSERT(eecp->eec_rx != NULL); + should_abort = eecp->eec_rx(arg, label, last_used_id, size, flags); + + return (should_abort); +} + +static __checkReturn boolean_t +ef10_ev_tx( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + efx_nic_t *enp = eep->ee_enp; + uint32_t id; + uint32_t label; + boolean_t should_abort; + + EFX_EV_QSTAT_INCR(eep, EV_TX); + + /* Discard events after RXQ/TXQ errors */ + if (enp->en_reset_flags & (EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR)) + return (B_FALSE); + + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DROP_EVENT) != 0) { + /* Drop this event */ + return (B_FALSE); + } + + /* Per-packet TX completion (was per-descriptor for Falcon/Siena) */ + id = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_DESCR_INDX); + label = EFX_QWORD_FIELD(*eqp, ESF_DZ_TX_QLABEL); + + EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id); + + EFSYS_ASSERT(eecp->eec_tx != NULL); + should_abort = eecp->eec_tx(arg, label, id); + + return (should_abort); +} + +static __checkReturn boolean_t +ef10_ev_driver( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + unsigned int code; + boolean_t should_abort; + + EFX_EV_QSTAT_INCR(eep, EV_DRIVER); + should_abort = B_FALSE; + + code = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_CODE); + switch (code) { + case ESE_DZ_DRV_TIMER_EV: { + uint32_t id; + + id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_TMR_ID); + + EFSYS_ASSERT(eecp->eec_timer != NULL); + should_abort = eecp->eec_timer(arg, id); + break; + } + + case ESE_DZ_DRV_WAKE_UP_EV: { + uint32_t id; + + id = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_EVQ_ID); + + EFSYS_ASSERT(eecp->eec_wake_up != NULL); + should_abort = eecp->eec_wake_up(arg, id); + break; + } + + case ESE_DZ_DRV_START_UP_EV: + EFSYS_ASSERT(eecp->eec_initialized != NULL); + should_abort = eecp->eec_initialized(arg); + break; + + default: + EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); + break; + } + + return (should_abort); +} + +static __checkReturn boolean_t +ef10_ev_drv_gen( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + uint32_t data; + boolean_t should_abort; + + EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN); + should_abort = B_FALSE; + + data = EFX_QWORD_FIELD(*eqp, ESF_DZ_DRV_SUB_DATA_DW0); + if (data >= ((uint32_t)1 << 16)) { + EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); + + return (B_TRUE); + } + + EFSYS_ASSERT(eecp->eec_software != NULL); + should_abort = eecp->eec_software(arg, (uint16_t)data); + + return (should_abort); +} + +static __checkReturn boolean_t +ef10_ev_mcdi( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + efx_nic_t *enp = eep->ee_enp; + unsigned code; + boolean_t should_abort = B_FALSE; + + EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE); + + code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE); + switch (code) { + case MCDI_EVENT_CODE_BADSSERT: + efx_mcdi_ev_death(enp, EINTR); + break; + + case MCDI_EVENT_CODE_CMDDONE: + efx_mcdi_ev_cpl(enp, + MCDI_EV_FIELD(eqp, CMDDONE_SEQ), + MCDI_EV_FIELD(eqp, CMDDONE_DATALEN), + MCDI_EV_FIELD(eqp, CMDDONE_ERRNO)); + break; + +#if EFSYS_OPT_MCDI_PROXY_AUTH + case MCDI_EVENT_CODE_PROXY_RESPONSE: + /* + * This event notifies a function that an authorization request + * has been processed. If the request was authorized then the + * function can now re-send the original MCDI request. + * See SF-113652-SW "SR-IOV Proxied Network Access Control". + */ + efx_mcdi_ev_proxy_response(enp, + MCDI_EV_FIELD(eqp, PROXY_RESPONSE_HANDLE), + MCDI_EV_FIELD(eqp, PROXY_RESPONSE_RC)); + break; +#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ + + case MCDI_EVENT_CODE_LINKCHANGE: { + efx_link_mode_t link_mode; + + ef10_phy_link_ev(enp, eqp, &link_mode); + should_abort = eecp->eec_link_change(arg, link_mode); + break; + } + + case MCDI_EVENT_CODE_SENSOREVT: { +#if EFSYS_OPT_MON_STATS + efx_mon_stat_t id; + efx_mon_stat_value_t value; + efx_rc_t rc; + + /* Decode monitor stat for MCDI sensor (if supported) */ + if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0) { + /* Report monitor stat change */ + should_abort = eecp->eec_monitor(arg, id, value); + } else if (rc == ENOTSUP) { + should_abort = eecp->eec_exception(arg, + EFX_EXCEPTION_UNKNOWN_SENSOREVT, + MCDI_EV_FIELD(eqp, DATA)); + } else { + EFSYS_ASSERT(rc == ENODEV); /* Wrong port */ + } +#endif + break; + } + + case MCDI_EVENT_CODE_SCHEDERR: + /* Informational only */ + break; + + case MCDI_EVENT_CODE_REBOOT: + /* Falcon/Siena only (should not been seen with Huntington). */ + efx_mcdi_ev_death(enp, EIO); + break; + + case MCDI_EVENT_CODE_MC_REBOOT: + /* MC_REBOOT event is used for Huntington (EF10) and later. */ + efx_mcdi_ev_death(enp, EIO); + break; + + case MCDI_EVENT_CODE_MAC_STATS_DMA: +#if EFSYS_OPT_MAC_STATS + if (eecp->eec_mac_stats != NULL) { + eecp->eec_mac_stats(arg, + MCDI_EV_FIELD(eqp, MAC_STATS_DMA_GENERATION)); + } +#endif + break; + + case MCDI_EVENT_CODE_FWALERT: { + uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON); + + if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS) + should_abort = eecp->eec_exception(arg, + EFX_EXCEPTION_FWALERT_SRAM, + MCDI_EV_FIELD(eqp, FWALERT_DATA)); + else + should_abort = eecp->eec_exception(arg, + EFX_EXCEPTION_UNKNOWN_FWALERT, + MCDI_EV_FIELD(eqp, DATA)); + break; + } + + case MCDI_EVENT_CODE_TX_ERR: { + /* + * After a TXQ error is detected, firmware sends a TX_ERR event. + * This may be followed by TX completions (which we discard), + * and then finally by a TX_FLUSH event. Firmware destroys the + * TXQ automatically after sending the TX_FLUSH event. + */ + enp->en_reset_flags |= EFX_RESET_TXQ_ERR; + + EFSYS_PROBE1(tx_descq_err, uint32_t, MCDI_EV_FIELD(eqp, DATA)); + + /* Inform the driver that a reset is required. */ + eecp->eec_exception(arg, EFX_EXCEPTION_TX_ERROR, + MCDI_EV_FIELD(eqp, TX_ERR_DATA)); + break; + } + + case MCDI_EVENT_CODE_TX_FLUSH: { + uint32_t txq_index = MCDI_EV_FIELD(eqp, TX_FLUSH_TXQ); + + /* + * EF10 firmware sends two TX_FLUSH events: one to the txq's + * event queue, and one to evq 0 (with TX_FLUSH_TO_DRIVER set). + * We want to wait for all completions, so ignore the events + * with TX_FLUSH_TO_DRIVER. + */ + if (MCDI_EV_FIELD(eqp, TX_FLUSH_TO_DRIVER) != 0) { + should_abort = B_FALSE; + break; + } + + EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE); + + EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index); + + EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL); + should_abort = eecp->eec_txq_flush_done(arg, txq_index); + break; + } + + case MCDI_EVENT_CODE_RX_ERR: { + /* + * After an RXQ error is detected, firmware sends an RX_ERR + * event. This may be followed by RX events (which we discard), + * and then finally by an RX_FLUSH event. Firmware destroys the + * RXQ automatically after sending the RX_FLUSH event. + */ + enp->en_reset_flags |= EFX_RESET_RXQ_ERR; + + EFSYS_PROBE1(rx_descq_err, uint32_t, MCDI_EV_FIELD(eqp, DATA)); + + /* Inform the driver that a reset is required. */ + eecp->eec_exception(arg, EFX_EXCEPTION_RX_ERROR, + MCDI_EV_FIELD(eqp, RX_ERR_DATA)); + break; + } + + case MCDI_EVENT_CODE_RX_FLUSH: { + uint32_t rxq_index = MCDI_EV_FIELD(eqp, RX_FLUSH_RXQ); + + /* + * EF10 firmware sends two RX_FLUSH events: one to the rxq's + * event queue, and one to evq 0 (with RX_FLUSH_TO_DRIVER set). + * We want to wait for all completions, so ignore the events + * with RX_FLUSH_TO_DRIVER. + */ + if (MCDI_EV_FIELD(eqp, RX_FLUSH_TO_DRIVER) != 0) { + should_abort = B_FALSE; + break; + } + + EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE); + + EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index); + + EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL); + should_abort = eecp->eec_rxq_flush_done(arg, rxq_index); + break; + } + + default: + EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), + uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); + break; + } + + return (should_abort); +} + + void +ef10_ev_rxlabel_init( + __in efx_evq_t *eep, + __in efx_rxq_t *erp, + __in unsigned int label) +{ + efx_evq_rxq_state_t *eersp; + + EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state)); + eersp = &eep->ee_rxq_state[label]; + + EFSYS_ASSERT3U(eersp->eers_rx_mask, ==, 0); + + eersp->eers_rx_read_ptr = 0; + eersp->eers_rx_mask = erp->er_mask; +} + + void +ef10_ev_rxlabel_fini( + __in efx_evq_t *eep, + __in unsigned int label) +{ + efx_evq_rxq_state_t *eersp; + + EFSYS_ASSERT3U(label, <, EFX_ARRAY_SIZE(eep->ee_rxq_state)); + eersp = &eep->ee_rxq_state[label]; + + EFSYS_ASSERT3U(eersp->eers_rx_mask, !=, 0); + + eersp->eers_rx_read_ptr = 0; + eersp->eers_rx_mask = 0; +} + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_ev.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_filter.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_filter.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_filter.c (revision 301344) @@ -0,0 +1,1482 @@ +/*- + * Copyright (c) 2007-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#if EFSYS_OPT_FILTER + +#define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) + +static efx_filter_spec_t * +ef10_filter_entry_spec( + __in const ef10_filter_table_t *eftp, + __in unsigned int index) +{ + return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & + ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); +} + +static boolean_t +ef10_filter_entry_is_busy( + __in const ef10_filter_table_t *eftp, + __in unsigned int index) +{ + if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) + return (B_TRUE); + else + return (B_FALSE); +} + +static boolean_t +ef10_filter_entry_is_auto_old( + __in const ef10_filter_table_t *eftp, + __in unsigned int index) +{ + if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) + return (B_TRUE); + else + return (B_FALSE); +} + +static void +ef10_filter_set_entry( + __inout ef10_filter_table_t *eftp, + __in unsigned int index, + __in_opt const efx_filter_spec_t *efsp) +{ + EFE_SPEC(eftp, index) = (uintptr_t)efsp; +} + +static void +ef10_filter_set_entry_busy( + __inout ef10_filter_table_t *eftp, + __in unsigned int index) +{ + EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; +} + +static void +ef10_filter_set_entry_not_busy( + __inout ef10_filter_table_t *eftp, + __in unsigned int index) +{ + EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; +} + +static void +ef10_filter_set_entry_auto_old( + __inout ef10_filter_table_t *eftp, + __in unsigned int index) +{ + EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); + EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; +} + +static void +ef10_filter_set_entry_not_auto_old( + __inout ef10_filter_table_t *eftp, + __in unsigned int index) +{ + EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; + EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); +} + + __checkReturn efx_rc_t +ef10_filter_init( + __in efx_nic_t *enp) +{ + efx_rc_t rc; + ef10_filter_table_t *eftp; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + +#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); + EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == + MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); +#undef MATCH_MASK + + EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); + + if (!eftp) { + rc = ENOMEM; + goto fail1; + } + + enp->en_filter.ef_ef10_filter_table = eftp; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_filter_fini( + __in efx_nic_t *enp) +{ + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (enp->en_filter.ef_ef10_filter_table != NULL) { + EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), + enp->en_filter.ef_ef10_filter_table); + } +} + +static __checkReturn efx_rc_t +efx_mcdi_filter_op_add( + __in efx_nic_t *enp, + __in efx_filter_spec_t *spec, + __in unsigned int filter_op, + __inout ef10_filter_handle_t *handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, + MC_CMD_FILTER_OP_OUT_LEN)]; + uint32_t match_fields = 0; + efx_rc_t rc; + + memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FILTER_OP; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; + + switch (filter_op) { + case MC_CMD_FILTER_OP_IN_OP_REPLACE: + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, + handle->efh_lo); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, + handle->efh_hi); + /* Fall through */ + case MC_CMD_FILTER_OP_IN_OP_INSERT: + case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); + break; + default: + EFSYS_ASSERT(0); + rc = EINVAL; + goto fail1; + } + + if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { + /* + * The LOC_MAC_IG match flag can represent unknown unicast + * or multicast filters - use the MAC address to distinguish + * them. + */ + if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) + match_fields |= 1U << + MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; + else + match_fields |= 1U << + MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; + } + + match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); + + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, + EVB_PORT_ID_ASSIGNED); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, + match_fields); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, + MC_CMD_FILTER_OP_IN_RX_DEST_HOST); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, + spec->efs_dmaq_id); + if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, + spec->efs_rss_context); + } + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, + spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? + MC_CMD_FILTER_OP_IN_RX_MODE_RSS : + MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, + MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); + + if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { + /* + * NOTE: Unlike most MCDI requests, the filter fields + * are presented in network (big endian) byte order. + */ + memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), + spec->efs_rem_mac, EFX_MAC_ADDR_LEN); + memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), + spec->efs_loc_mac, EFX_MAC_ADDR_LEN); + + MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, + __CPU_TO_BE_16(spec->efs_rem_port)); + MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, + __CPU_TO_BE_16(spec->efs_loc_port)); + + MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, + __CPU_TO_BE_16(spec->efs_ether_type)); + + MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, + __CPU_TO_BE_16(spec->efs_inner_vid)); + MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, + __CPU_TO_BE_16(spec->efs_outer_vid)); + + /* IP protocol (in low byte, high byte is zero) */ + MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, + spec->efs_ip_proto); + + EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == + MC_CMD_FILTER_OP_IN_SRC_IP_LEN); + EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == + MC_CMD_FILTER_OP_IN_DST_IP_LEN); + + memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), + &spec->efs_rem_host.eo_byte[0], + MC_CMD_FILTER_OP_IN_SRC_IP_LEN); + memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), + &spec->efs_loc_host.eo_byte[0], + MC_CMD_FILTER_OP_IN_DST_IP_LEN); + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); + handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); + +} + +static __checkReturn efx_rc_t +efx_mcdi_filter_op_delete( + __in efx_nic_t *enp, + __in unsigned int filter_op, + __inout ef10_filter_handle_t *handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, + MC_CMD_FILTER_OP_OUT_LEN)]; + efx_rc_t rc; + + memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FILTER_OP; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; + + switch (filter_op) { + case MC_CMD_FILTER_OP_IN_OP_REMOVE: + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, + MC_CMD_FILTER_OP_IN_OP_REMOVE); + break; + case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, + MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); + break; + default: + EFSYS_ASSERT(0); + rc = EINVAL; + goto fail1; + } + + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo); + MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn boolean_t +ef10_filter_equal( + __in const efx_filter_spec_t *left, + __in const efx_filter_spec_t *right) +{ + /* FIXME: Consider rx vs tx filters (look at efs_flags) */ + if (left->efs_match_flags != right->efs_match_flags) + return (B_FALSE); + if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) + return (B_FALSE); + if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) + return (B_FALSE); + if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) + return (B_FALSE); + if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) + return (B_FALSE); + if (left->efs_rem_port != right->efs_rem_port) + return (B_FALSE); + if (left->efs_loc_port != right->efs_loc_port) + return (B_FALSE); + if (left->efs_inner_vid != right->efs_inner_vid) + return (B_FALSE); + if (left->efs_outer_vid != right->efs_outer_vid) + return (B_FALSE); + if (left->efs_ether_type != right->efs_ether_type) + return (B_FALSE); + if (left->efs_ip_proto != right->efs_ip_proto) + return (B_FALSE); + + return (B_TRUE); + +} + +static __checkReturn boolean_t +ef10_filter_same_dest( + __in const efx_filter_spec_t *left, + __in const efx_filter_spec_t *right) +{ + if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && + (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { + if (left->efs_rss_context == right->efs_rss_context) + return (B_TRUE); + } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && + (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { + if (left->efs_dmaq_id == right->efs_dmaq_id) + return (B_TRUE); + } + return (B_FALSE); +} + +static __checkReturn uint32_t +ef10_filter_hash( + __in efx_filter_spec_t *spec) +{ + EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) + == 0); + EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % + sizeof (uint32_t)) == 0); + + /* + * As the area of the efx_filter_spec_t we need to hash is DWORD + * aligned and an exact number of DWORDs in size we can use the + * optimised efx_hash_dwords() rather than efx_hash_bytes() + */ + return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, + (sizeof (efx_filter_spec_t) - + EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / + sizeof (uint32_t), 0)); +} + +/* + * Decide whether a filter should be exclusive or else should allow + * delivery to additional recipients. Currently we decide that + * filters for specific local unicast MAC and IP addresses are + * exclusive. + */ +static __checkReturn boolean_t +ef10_filter_is_exclusive( + __in efx_filter_spec_t *spec) +{ + if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && + !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) + return (B_TRUE); + + if ((spec->efs_match_flags & + (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == + (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { + if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && + ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) + return (B_TRUE); + if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && + (spec->efs_loc_host.eo_u8[0] != 0xff)) + return (B_TRUE); + } + + return (B_FALSE); +} + + __checkReturn efx_rc_t +ef10_filter_restore( + __in efx_nic_t *enp) +{ + int tbl_id; + efx_filter_spec_t *spec; + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + boolean_t restoring; + int state; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { + + EFSYS_LOCK(enp->en_eslp, state); + + spec = ef10_filter_entry_spec(eftp, tbl_id); + if (spec == NULL) { + restoring = B_FALSE; + } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { + /* Ignore busy entries. */ + restoring = B_FALSE; + } else { + ef10_filter_set_entry_busy(eftp, tbl_id); + restoring = B_TRUE; + } + + EFSYS_UNLOCK(enp->en_eslp, state); + + if (restoring == B_FALSE) + continue; + + if (ef10_filter_is_exclusive(spec)) { + rc = efx_mcdi_filter_op_add(enp, spec, + MC_CMD_FILTER_OP_IN_OP_INSERT, + &eftp->eft_entry[tbl_id].efe_handle); + } else { + rc = efx_mcdi_filter_op_add(enp, spec, + MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, + &eftp->eft_entry[tbl_id].efe_handle); + } + + if (rc != 0) + goto fail1; + + EFSYS_LOCK(enp->en_eslp, state); + + ef10_filter_set_entry_not_busy(eftp, tbl_id); + + EFSYS_UNLOCK(enp->en_eslp, state); + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * An arbitrary search limit for the software hash table. As per the linux net + * driver. + */ +#define EF10_FILTER_SEARCH_LIMIT 200 + +static __checkReturn efx_rc_t +ef10_filter_add_internal( + __in efx_nic_t *enp, + __inout efx_filter_spec_t *spec, + __in boolean_t may_replace, + __out_opt uint32_t *filter_id) +{ + efx_rc_t rc; + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t *saved_spec; + uint32_t hash; + unsigned int depth; + int ins_index; + boolean_t replacing = B_FALSE; + unsigned int i; + int state; + boolean_t locked = B_FALSE; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + +#if EFSYS_OPT_RX_SCALE + spec->efs_rss_context = enp->en_rss_context; +#endif + + hash = ef10_filter_hash(spec); + + /* + * FIXME: Add support for inserting filters of different priorities + * and removing lower priority multicast filters (bug 42378) + */ + + /* + * Find any existing filters with the same match tuple or + * else a free slot to insert at. If any of them are busy, + * we have to wait and retry. + */ + for (;;) { + ins_index = -1; + depth = 1; + EFSYS_LOCK(enp->en_eslp, state); + locked = B_TRUE; + + for (;;) { + i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); + saved_spec = ef10_filter_entry_spec(eftp, i); + + if (!saved_spec) { + if (ins_index < 0) { + ins_index = i; + } + } else if (ef10_filter_equal(spec, saved_spec)) { + if (ef10_filter_entry_is_busy(eftp, i)) + break; + if (saved_spec->efs_priority + == EFX_FILTER_PRI_AUTO) { + ins_index = i; + goto found; + } else if (ef10_filter_is_exclusive(spec)) { + if (may_replace) { + ins_index = i; + goto found; + } else { + rc = EEXIST; + goto fail1; + } + } + + /* Leave existing */ + } + + /* + * Once we reach the maximum search depth, use + * the first suitable slot or return EBUSY if + * there was none. + */ + if (depth == EF10_FILTER_SEARCH_LIMIT) { + if (ins_index < 0) { + rc = EBUSY; + goto fail2; + } + goto found; + } + depth++; + } + EFSYS_UNLOCK(enp->en_eslp, state); + locked = B_FALSE; + } + +found: + /* + * Create a software table entry if necessary, and mark it + * busy. We might yet fail to insert, but any attempt to + * insert a conflicting filter while we're waiting for the + * firmware must find the busy entry. + */ + saved_spec = ef10_filter_entry_spec(eftp, ins_index); + if (saved_spec) { + if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { + /* This is a filter we are refreshing */ + ef10_filter_set_entry_not_auto_old(eftp, ins_index); + goto out_unlock; + + } + replacing = B_TRUE; + } else { + EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); + if (!saved_spec) { + rc = ENOMEM; + goto fail3; + } + *saved_spec = *spec; + ef10_filter_set_entry(eftp, ins_index, saved_spec); + } + ef10_filter_set_entry_busy(eftp, ins_index); + + EFSYS_UNLOCK(enp->en_eslp, state); + locked = B_FALSE; + + /* + * On replacing the filter handle may change after after a successful + * replace operation. + */ + if (replacing) { + rc = efx_mcdi_filter_op_add(enp, spec, + MC_CMD_FILTER_OP_IN_OP_REPLACE, + &eftp->eft_entry[ins_index].efe_handle); + } else if (ef10_filter_is_exclusive(spec)) { + rc = efx_mcdi_filter_op_add(enp, spec, + MC_CMD_FILTER_OP_IN_OP_INSERT, + &eftp->eft_entry[ins_index].efe_handle); + } else { + rc = efx_mcdi_filter_op_add(enp, spec, + MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, + &eftp->eft_entry[ins_index].efe_handle); + } + + if (rc != 0) + goto fail4; + + EFSYS_LOCK(enp->en_eslp, state); + locked = B_TRUE; + + if (replacing) { + /* Update the fields that may differ */ + saved_spec->efs_priority = spec->efs_priority; + saved_spec->efs_flags = spec->efs_flags; + saved_spec->efs_rss_context = spec->efs_rss_context; + saved_spec->efs_dmaq_id = spec->efs_dmaq_id; + } + + ef10_filter_set_entry_not_busy(eftp, ins_index); + +out_unlock: + + EFSYS_UNLOCK(enp->en_eslp, state); + locked = B_FALSE; + + if (filter_id) + *filter_id = ins_index; + + return (0); + +fail4: + EFSYS_PROBE(fail4); + + if (!replacing) { + EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); + saved_spec = NULL; + } + ef10_filter_set_entry_not_busy(eftp, ins_index); + ef10_filter_set_entry(eftp, ins_index, NULL); + +fail3: + EFSYS_PROBE(fail3); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + if (locked) + EFSYS_UNLOCK(enp->en_eslp, state); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_filter_add( + __in efx_nic_t *enp, + __inout efx_filter_spec_t *spec, + __in boolean_t may_replace) +{ + efx_rc_t rc; + + rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); + if (rc != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +ef10_filter_delete_internal( + __in efx_nic_t *enp, + __in uint32_t filter_id) +{ + efx_rc_t rc; + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t *spec; + int state; + uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; + + /* + * Find the software table entry and mark it busy. Don't + * remove it yet; any attempt to update while we're waiting + * for the firmware must find the busy entry. + * + * FIXME: What if the busy flag is never cleared? + */ + EFSYS_LOCK(enp->en_eslp, state); + while (ef10_filter_entry_is_busy(table, filter_idx)) { + EFSYS_UNLOCK(enp->en_eslp, state); + EFSYS_SPIN(1); + EFSYS_LOCK(enp->en_eslp, state); + } + if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { + ef10_filter_set_entry_busy(table, filter_idx); + } + EFSYS_UNLOCK(enp->en_eslp, state); + + if (spec == NULL) { + rc = ENOENT; + goto fail1; + } + + /* + * Try to remove the hardware filter. This may fail if the MC has + * rebooted (which frees all hardware filter resources). + */ + if (ef10_filter_is_exclusive(spec)) { + rc = efx_mcdi_filter_op_delete(enp, + MC_CMD_FILTER_OP_IN_OP_REMOVE, + &table->eft_entry[filter_idx].efe_handle); + } else { + rc = efx_mcdi_filter_op_delete(enp, + MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, + &table->eft_entry[filter_idx].efe_handle); + } + + /* Free the software table entry */ + EFSYS_LOCK(enp->en_eslp, state); + ef10_filter_set_entry_not_busy(table, filter_idx); + ef10_filter_set_entry(table, filter_idx, NULL); + EFSYS_UNLOCK(enp->en_eslp, state); + + EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); + + /* Check result of hardware filter removal */ + if (rc != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_filter_delete( + __in efx_nic_t *enp, + __inout efx_filter_spec_t *spec) +{ + efx_rc_t rc; + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t *saved_spec; + unsigned int hash; + unsigned int depth; + unsigned int i; + int state; + boolean_t locked = B_FALSE; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + hash = ef10_filter_hash(spec); + + EFSYS_LOCK(enp->en_eslp, state); + locked = B_TRUE; + + depth = 1; + for (;;) { + i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); + saved_spec = ef10_filter_entry_spec(table, i); + if (saved_spec && ef10_filter_equal(spec, saved_spec) && + ef10_filter_same_dest(spec, saved_spec)) { + break; + } + if (depth == EF10_FILTER_SEARCH_LIMIT) { + rc = ENOENT; + goto fail1; + } + depth++; + } + + EFSYS_UNLOCK(enp->en_eslp, state); + locked = B_FALSE; + + rc = ef10_filter_delete_internal(enp, i); + if (rc != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + if (locked) + EFSYS_UNLOCK(enp->en_eslp, state); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_get_parser_disp_info( + __in efx_nic_t *enp, + __out uint32_t *list, + __out size_t *length) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, + MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; + efx_rc_t rc; + uint32_t i; + boolean_t support_unknown_ucast = B_FALSE; + boolean_t support_unknown_mcast = B_FALSE; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; + + MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, + MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + *length = MCDI_OUT_DWORD(req, + GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); + + if (req.emr_out_length_used < + MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { + rc = EMSGSIZE; + goto fail2; + } + + memcpy(list, + MCDI_OUT2(req, + uint32_t, + GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), + (*length) * sizeof (uint32_t)); + EFX_STATIC_ASSERT(sizeof (uint32_t) == + MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); + + /* + * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change + * the lower priority one to LOC_MAC_IG. + */ + for (i = 0; i < *length; i++) { + if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { + list[i] &= + (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); + support_unknown_ucast = B_TRUE; + } + if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { + list[i] &= + (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); + support_unknown_mcast = B_TRUE; + } + + if (support_unknown_ucast && support_unknown_mcast) { + list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; + break; + } + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_filter_supported_filters( + __in efx_nic_t *enp, + __out uint32_t *list, + __out size_t *length) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0)) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +ef10_filter_insert_unicast( + __in efx_nic_t *enp, + __in_ecount(6) uint8_t const *addr, + __in efx_filter_flag_t filter_flags) +{ + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t spec; + efx_rc_t rc; + + /* Insert the filter for the local station address */ + efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, + filter_flags, + eftp->eft_default_rxq); + efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr); + + rc = ef10_filter_add_internal(enp, &spec, B_TRUE, + &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); + if (rc != 0) + goto fail1; + + eftp->eft_unicst_filter_count++; + EFSYS_ASSERT(eftp->eft_unicst_filter_count <= + EFX_EF10_FILTER_UNICAST_FILTERS_MAX); + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + +static __checkReturn efx_rc_t +ef10_filter_insert_all_unicast( + __in efx_nic_t *enp, + __in efx_filter_flag_t filter_flags) +{ + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t spec; + efx_rc_t rc; + + /* Insert the unknown unicast filter */ + efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, + filter_flags, + eftp->eft_default_rxq); + efx_filter_spec_set_uc_def(&spec); + rc = ef10_filter_add_internal(enp, &spec, B_TRUE, + &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); + if (rc != 0) + goto fail1; + + eftp->eft_unicst_filter_count++; + EFSYS_ASSERT(eftp->eft_unicst_filter_count <= + EFX_EF10_FILTER_UNICAST_FILTERS_MAX); + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + +static __checkReturn efx_rc_t +ef10_filter_insert_multicast_list( + __in efx_nic_t *enp, + __in boolean_t mulcst, + __in boolean_t brdcst, + __in_ecount(6*count) uint8_t const *addrs, + __in uint32_t count, + __in efx_filter_flag_t filter_flags, + __in boolean_t rollback) +{ + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t spec; + uint8_t addr[6]; + uint32_t i; + uint32_t filter_index; + uint32_t filter_count; + efx_rc_t rc; + + if (mulcst == B_FALSE) + count = 0; + + if (count + (brdcst ? 1 : 0) > + EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { + /* Too many MAC addresses */ + rc = EINVAL; + goto fail1; + } + + /* Insert/renew multicast address list filters */ + filter_count = 0; + for (i = 0; i < count; i++) { + efx_filter_spec_init_rx(&spec, + EFX_FILTER_PRI_AUTO, + filter_flags, + eftp->eft_default_rxq); + + efx_filter_spec_set_eth_local(&spec, + EFX_FILTER_SPEC_VID_UNSPEC, + &addrs[i * EFX_MAC_ADDR_LEN]); + + rc = ef10_filter_add_internal(enp, &spec, B_TRUE, + &filter_index); + + if (rc == 0) { + eftp->eft_mulcst_filter_indexes[filter_count] = + filter_index; + filter_count++; + } else if (rollback == B_TRUE) { + /* Only stop upon failure if told to rollback */ + goto rollback; + } + + } + + if (brdcst == B_TRUE) { + /* Insert/renew broadcast address filter */ + efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, + filter_flags, + eftp->eft_default_rxq); + + EFX_MAC_BROADCAST_ADDR_SET(addr); + efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, + addr); + + rc = ef10_filter_add_internal(enp, &spec, B_TRUE, + &filter_index); + + if (rc == 0) { + eftp->eft_mulcst_filter_indexes[filter_count] = + filter_index; + filter_count++; + } else if (rollback == B_TRUE) { + /* Only stop upon failure if told to rollback */ + goto rollback; + } + } + + eftp->eft_mulcst_filter_count = filter_count; + eftp->eft_using_all_mulcst = B_FALSE; + + return (0); + +rollback: + /* Remove any filters we have inserted */ + i = filter_count; + while (i--) { + (void) ef10_filter_delete_internal(enp, + eftp->eft_mulcst_filter_indexes[i]); + } + eftp->eft_mulcst_filter_count = 0; + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +ef10_filter_insert_all_multicast( + __in efx_nic_t *enp, + __in efx_filter_flag_t filter_flags) +{ + ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; + efx_filter_spec_t spec; + efx_rc_t rc; + + /* Insert the unknown multicast filter */ + efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, + filter_flags, + eftp->eft_default_rxq); + efx_filter_spec_set_mc_def(&spec); + + rc = ef10_filter_add_internal(enp, &spec, B_TRUE, + &eftp->eft_mulcst_filter_indexes[0]); + if (rc != 0) + goto fail1; + + eftp->eft_mulcst_filter_count = 1; + eftp->eft_using_all_mulcst = B_TRUE; + + /* + * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. + */ + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static void +ef10_filter_remove_old( + __in efx_nic_t *enp) +{ + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + uint32_t i; + + for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { + if (ef10_filter_entry_is_auto_old(table, i)) { + (void) ef10_filter_delete_internal(enp, i); + } + } +} + + +static __checkReturn efx_rc_t +ef10_filter_get_workarounds( + __in efx_nic_t *enp) +{ + efx_nic_cfg_t *encp = &enp->en_nic_cfg; + uint32_t implemented = 0; + uint32_t enabled = 0; + efx_rc_t rc; + + rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); + if (rc == 0) { + /* Check if chained multicast filter support is enabled */ + if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) + encp->enc_bug26807_workaround = B_TRUE; + else + encp->enc_bug26807_workaround = B_FALSE; + } else if (rc == ENOTSUP) { + /* + * Firmware is too old to support GET_WORKAROUNDS, and support + * for this workaround was implemented later. + */ + encp->enc_bug26807_workaround = B_FALSE; + } else { + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); + +} + + +/* + * Reconfigure all filters. + * If all_unicst and/or all mulcst filters cannot be applied then + * return ENOTSUP (Note the filters for the specified addresses are + * still applied in this case). + */ + __checkReturn efx_rc_t +ef10_filter_reconfigure( + __in efx_nic_t *enp, + __in_ecount(6) uint8_t const *mac_addr, + __in boolean_t all_unicst, + __in boolean_t mulcst, + __in boolean_t all_mulcst, + __in boolean_t brdcst, + __in_ecount(6*count) uint8_t const *addrs, + __in uint32_t count) +{ + efx_nic_cfg_t *encp = &enp->en_nic_cfg; + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + efx_filter_flag_t filter_flags; + unsigned i; + efx_rc_t all_unicst_rc = 0; + efx_rc_t all_mulcst_rc = 0; + efx_rc_t rc; + + if (table->eft_default_rxq == NULL) { + /* + * Filters direct traffic to the default RXQ, and so cannot be + * inserted until it is available. Any currently configured + * filters must be removed (ignore errors in case the MC + * has rebooted, which removes hardware filters). + */ + for (i = 0; i < table->eft_unicst_filter_count; i++) { + (void) ef10_filter_delete_internal(enp, + table->eft_unicst_filter_indexes[i]); + } + table->eft_unicst_filter_count = 0; + + for (i = 0; i < table->eft_mulcst_filter_count; i++) { + (void) ef10_filter_delete_internal(enp, + table->eft_mulcst_filter_indexes[i]); + } + table->eft_mulcst_filter_count = 0; + + return (0); + } + + if (table->eft_using_rss) + filter_flags = EFX_FILTER_FLAG_RX_RSS; + else + filter_flags = 0; + + /* Mark old filters which may need to be removed */ + for (i = 0; i < table->eft_unicst_filter_count; i++) { + ef10_filter_set_entry_auto_old(table, + table->eft_unicst_filter_indexes[i]); + } + for (i = 0; i < table->eft_mulcst_filter_count; i++) { + ef10_filter_set_entry_auto_old(table, + table->eft_mulcst_filter_indexes[i]); + } + + /* + * Insert or renew unicast filters. + * + * Frimware does not perform chaining on unicast filters. As traffic is + * therefore only delivered to the first matching filter, we should + * always insert the specific filter for our MAC address, to try and + * ensure we get that traffic. + * + * (If the filter for our MAC address has already been inserted by + * another function, we won't receive traffic sent to us, even if we + * insert a unicast mismatch filter. To prevent traffic stealing, this + * therefore relies on the privilege model only allowing functions to + * insert filters for their own MAC address unless explicitly given + * additional privileges by the user. This also means that, even on a + * priviliged function, inserting a unicast mismatch filter may not + * catch all traffic in multi PCI function scenarios.) + */ + table->eft_unicst_filter_count = 0; + rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); + if (all_unicst || (rc != 0)) { + all_unicst_rc = ef10_filter_insert_all_unicast(enp, + filter_flags); + if ((rc != 0) && (all_unicst_rc != 0)) + goto fail1; + } + + /* + * WORKAROUND_BUG26807 controls firmware support for chained multicast + * filters, and can only be enabled or disabled when the hardware filter + * table is empty. + * + * Chained multicast filters require support from the datapath firmware, + * and may not be available (e.g. low-latency variants or old Huntington + * firmware). + * + * Firmware will reset (FLR) functions which have inserted filters in + * the hardware filter table when the workaround is enabled/disabled. + * Functions without any hardware filters are not reset. + * + * Re-check if the workaround is enabled after adding unicast hardware + * filters. This ensures that encp->enc_bug26807_workaround matches the + * firmware state, and that later changes to enable/disable the + * workaround will result in this function seeing a reset (FLR). + * + * In common-code drivers, we only support multiple PCI function + * scenarios with firmware that supports multicast chaining, so we can + * assume it is enabled for such cases and hence simplify the filter + * insertion logic. Firmware that does not support multicast chaining + * does not support multiple PCI function configurations either, so + * filter insertion is much simpler and the same strategies can still be + * used. + */ + if ((rc = ef10_filter_get_workarounds(enp)) != 0) + goto fail2; + + if ((table->eft_using_all_mulcst != all_mulcst) && + (encp->enc_bug26807_workaround == B_TRUE)) { + /* + * Multicast filter chaining is enabled, so traffic that matches + * more than one multicast filter will be replicated and + * delivered to multiple recipients. To avoid this duplicate + * delivery, remove old multicast filters before inserting new + * multicast filters. + */ + ef10_filter_remove_old(enp); + } + + /* Insert or renew multicast filters */ + if (all_mulcst == B_TRUE) { + /* + * Insert the all multicast filter. If that fails, try to insert + * all of our multicast filters (but without rollback on + * failure). + */ + all_mulcst_rc = ef10_filter_insert_all_multicast(enp, + filter_flags); + if (all_mulcst_rc != 0) { + rc = ef10_filter_insert_multicast_list(enp, B_TRUE, + brdcst, addrs, count, filter_flags, B_FALSE); + if (rc != 0) + goto fail3; + } + } else { + /* + * Insert filters for multicast addresses. + * If any insertion fails, then rollback and try to insert the + * all multicast filter instead. + * If that also fails, try to insert all of the multicast + * filters (but without rollback on failure). + */ + rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, + addrs, count, filter_flags, B_TRUE); + if (rc != 0) { + if ((table->eft_using_all_mulcst == B_FALSE) && + (encp->enc_bug26807_workaround == B_TRUE)) { + /* + * Multicast filter chaining is on, so remove + * old filters before inserting the multicast + * all filter to avoid duplicate delivery caused + * by packets matching multiple filters. + */ + ef10_filter_remove_old(enp); + } + + rc = ef10_filter_insert_all_multicast(enp, + filter_flags); + if (rc != 0) { + rc = ef10_filter_insert_multicast_list(enp, + mulcst, brdcst, + addrs, count, filter_flags, B_FALSE); + if (rc != 0) + goto fail4; + } + } + } + + /* Remove old filters which were not renewed */ + ef10_filter_remove_old(enp); + + /* report if any optional flags were rejected */ + if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || + ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { + rc = ENOTSUP; + } + + return (rc); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + /* Clear auto old flags */ + for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { + if (ef10_filter_entry_is_auto_old(table, i)) { + ef10_filter_set_entry_not_auto_old(table, i); + } + } + + return (rc); +} + + void +ef10_filter_get_default_rxq( + __in efx_nic_t *enp, + __out efx_rxq_t **erpp, + __out boolean_t *using_rss) +{ + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + + *erpp = table->eft_default_rxq; + *using_rss = table->eft_using_rss; +} + + + void +ef10_filter_default_rxq_set( + __in efx_nic_t *enp, + __in efx_rxq_t *erp, + __in boolean_t using_rss) +{ + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + +#if EFSYS_OPT_RX_SCALE + EFSYS_ASSERT((using_rss == B_FALSE) || + (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); + table->eft_using_rss = using_rss; +#else + EFSYS_ASSERT(using_rss == B_FALSE); + table->eft_using_rss = B_FALSE; +#endif + table->eft_default_rxq = erp; +} + + void +ef10_filter_default_rxq_clear( + __in efx_nic_t *enp) +{ + ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; + + table->eft_default_rxq = NULL; + table->eft_using_rss = B_FALSE; +} + + +#endif /* EFSYS_OPT_FILTER */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_filter.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_intr.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_intr.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_intr.c (revision 301344) @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + + __checkReturn efx_rc_t +ef10_intr_init( + __in efx_nic_t *enp, + __in efx_intr_type_t type, + __in efsys_mem_t *esmp) +{ + _NOTE(ARGUNUSED(enp, type, esmp)) + return (0); +} + + + void +ef10_intr_enable( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + + + void +ef10_intr_disable( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + + + void +ef10_intr_disable_unlocked( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + + +static __checkReturn efx_rc_t +efx_mcdi_trigger_interrupt( + __in efx_nic_t *enp, + __in unsigned int level) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_TRIGGER_INTERRUPT_IN_LEN, + MC_CMD_TRIGGER_INTERRUPT_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (level >= enp->en_nic_cfg.enc_intr_limit) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_TRIGGER_INTERRUPT; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_TRIGGER_INTERRUPT_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_TRIGGER_INTERRUPT_OUT_LEN; + + MCDI_IN_SET_DWORD(req, TRIGGER_INTERRUPT_IN_INTR_LEVEL, level); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_intr_trigger( + __in efx_nic_t *enp, + __in unsigned int level) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_rc_t rc; + + if (encp->enc_bug41750_workaround) { + /* + * bug 41750: Test interrupts don't work on Greenport + * bug 50084: Test interrupts don't work on VFs + */ + rc = ENOTSUP; + goto fail1; + } + + if ((rc = efx_mcdi_trigger_interrupt(enp, level)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_intr_status_line( + __in efx_nic_t *enp, + __out boolean_t *fatalp, + __out uint32_t *qmaskp) +{ + efx_dword_t dword; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Read the queue mask and implicitly acknowledge the interrupt. */ + EFX_BAR_READD(enp, ER_DZ_BIU_INT_ISR_REG, &dword, B_FALSE); + *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); + + EFSYS_PROBE1(qmask, uint32_t, *qmaskp); + + *fatalp = B_FALSE; +} + + void +ef10_intr_status_message( + __in efx_nic_t *enp, + __in unsigned int message, + __out boolean_t *fatalp) +{ + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + _NOTE(ARGUNUSED(enp, message)) + + /* EF10 fatal errors are reported via events */ + *fatalp = B_FALSE; +} + + void +ef10_intr_fatal( + __in efx_nic_t *enp) +{ + /* EF10 fatal errors are reported via events */ + _NOTE(ARGUNUSED(enp)) +} + + void +ef10_intr_fini( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_intr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_mac.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_mac.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_mac.c (revision 301344) @@ -0,0 +1,752 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + + __checkReturn efx_rc_t +ef10_mac_poll( + __in efx_nic_t *enp, + __out efx_link_mode_t *link_modep) +{ + efx_port_t *epp = &(enp->en_port); + ef10_link_state_t els; + efx_rc_t rc; + + if ((rc = ef10_phy_get_link(enp, &els)) != 0) + goto fail1; + + epp->ep_adv_cap_mask = els.els_adv_cap_mask; + epp->ep_fcntl = els.els_fcntl; + + *link_modep = els.els_link_mode; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + *link_modep = EFX_LINK_UNKNOWN; + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mac_up( + __in efx_nic_t *enp, + __out boolean_t *mac_upp) +{ + ef10_link_state_t els; + efx_rc_t rc; + + /* + * Because EF10 doesn't *require* polling, we can't rely on + * ef10_mac_poll() being executed to populate epp->ep_mac_up. + */ + if ((rc = ef10_phy_get_link(enp, &els)) != 0) + goto fail1; + + *mac_upp = els.els_mac_up; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * EF10 adapters use MC_CMD_VADAPTOR_SET_MAC to set the + * MAC address; the address field in MC_CMD_SET_MAC has no + * effect. + * MC_CMD_VADAPTOR_SET_MAC requires mac-spoofing privilege and + * the port to have no filters or queues active. + */ +static __checkReturn efx_rc_t +efx_mcdi_vadapter_set_mac( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VADAPTOR_SET_MAC_IN_LEN, + MC_CMD_VADAPTOR_SET_MAC_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VADAPTOR_SET_MAC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VADAPTOR_SET_MAC_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VADAPTOR_SET_MAC_OUT_LEN; + + MCDI_IN_SET_DWORD(req, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, + enp->en_vport_id); + EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, VADAPTOR_SET_MAC_IN_MACADDR), + epp->ep_mac_addr); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mac_addr_set( + __in efx_nic_t *enp) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_vadapter_set_mac(enp)) != 0) { + if (rc != ENOTSUP) + goto fail1; + + /* + * Fallback for older Huntington firmware without Vadapter + * support. + */ + if ((rc = ef10_mac_reconfigure(enp)) != 0) + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_mtu_set( + __in efx_nic_t *enp, + __in uint32_t mtu) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_SET_MAC_EXT_IN_LEN, + MC_CMD_SET_MAC_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_MAC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_MAC_EXT_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; + + /* Only configure the MTU in this call to MC_CMD_SET_MAC */ + MCDI_IN_SET_DWORD(req, SET_MAC_EXT_IN_MTU, mtu); + MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_EXT_IN_CONTROL, + SET_MAC_EXT_IN_CFG_MTU, 1); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mac_pdu_set( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_rc_t rc; + + if (encp->enc_enhanced_set_mac_supported) { + if ((rc = efx_mcdi_mtu_set(enp, epp->ep_mac_pdu)) != 0) + goto fail1; + } else { + /* + * Fallback for older Huntington firmware, which always + * configure all of the parameters to MC_CMD_SET_MAC. This isn't + * suitable for setting the MTU on unpriviliged functions. + */ + if ((rc = ef10_mac_reconfigure(enp)) != 0) + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +__checkReturn efx_rc_t +ef10_mac_reconfigure( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN, + MC_CMD_SET_MAC_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_MAC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_MAC_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; + + MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu); + MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0); + EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR), + epp->ep_mac_addr); + + /* + * Note: The Huntington MAC does not support REJECT_BRDCST. + * The REJECT_UNCST flag will also prevent multicast traffic + * from reaching the filters. As Huntington filters drop any + * traffic that does not match a filter it is ok to leave the + * MAC running in promiscuous mode. See bug41141. + * + * FIXME: Does REJECT_UNCST behave the same way on Medford? + */ + MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT, + SET_MAC_IN_REJECT_UNCST, 0, + SET_MAC_IN_REJECT_BRDCST, 0); + + /* + * Flow control, whether it is auto-negotiated or not, + * is set via the PHY advertised capabilities. When set to + * automatic the MAC will use the PHY settings to determine + * the flow control settings. + */ + MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, MC_CMD_FCNTL_AUTO); + + /* Do not include the Ethernet frame checksum in RX packets */ + MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_IN_FLAGS, + SET_MAC_IN_FLAG_INCLUDE_FCS, 0); + + efx_mcdi_execute_quiet(enp, &req); + + if (req.emr_rc != 0) { + /* + * Unprivileged functions cannot control link state, + * but still need to configure filters. + */ + if (req.emr_rc != EACCES) { + rc = req.emr_rc; + goto fail1; + } + } + + /* + * Apply the filters for the MAC configuration. + * If the NIC isn't ready to accept filters this may + * return success without setting anything. + */ + rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, + epp->ep_all_unicst, epp->ep_mulcst, + epp->ep_all_mulcst, epp->ep_brdcst, + epp->ep_mulcst_addr_list, + epp->ep_mulcst_addr_count); + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mac_multicast_list_set( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + const efx_mac_ops_t *emop = epp->ep_emop; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if ((rc = emop->emo_reconfigure(enp)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mac_filter_default_rxq_set( + __in efx_nic_t *enp, + __in efx_rxq_t *erp, + __in boolean_t using_rss) +{ + efx_port_t *epp = &(enp->en_port); + efx_rxq_t *old_rxq; + boolean_t old_using_rss; + efx_rc_t rc; + + ef10_filter_get_default_rxq(enp, &old_rxq, &old_using_rss); + + ef10_filter_default_rxq_set(enp, erp, using_rss); + + rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, + epp->ep_all_unicst, epp->ep_mulcst, + epp->ep_all_mulcst, epp->ep_brdcst, + epp->ep_mulcst_addr_list, + epp->ep_mulcst_addr_count); + + if (rc != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + ef10_filter_default_rxq_set(enp, old_rxq, old_using_rss); + + return (rc); +} + + void +ef10_mac_filter_default_rxq_clear( + __in efx_nic_t *enp) +{ + efx_port_t *epp = &(enp->en_port); + + ef10_filter_default_rxq_clear(enp); + + efx_filter_reconfigure(enp, epp->ep_mac_addr, + epp->ep_all_unicst, epp->ep_mulcst, + epp->ep_all_mulcst, epp->ep_brdcst, + epp->ep_mulcst_addr_list, + epp->ep_mulcst_addr_count); +} + + +#if EFSYS_OPT_LOOPBACK + + __checkReturn efx_rc_t +ef10_mac_loopback_set( + __in efx_nic_t *enp, + __in efx_link_mode_t link_mode, + __in efx_loopback_type_t loopback_type) +{ + efx_port_t *epp = &(enp->en_port); + const efx_phy_ops_t *epop = epp->ep_epop; + efx_loopback_type_t old_loopback_type; + efx_link_mode_t old_loopback_link_mode; + efx_rc_t rc; + + /* The PHY object handles this on EF10 */ + old_loopback_type = epp->ep_loopback_type; + old_loopback_link_mode = epp->ep_loopback_link_mode; + epp->ep_loopback_type = loopback_type; + epp->ep_loopback_link_mode = link_mode; + + if ((rc = epop->epo_reconfigure(enp)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + epp->ep_loopback_type = old_loopback_type; + epp->ep_loopback_link_mode = old_loopback_link_mode; + + return (rc); +} + +#endif /* EFSYS_OPT_LOOPBACK */ + +#if EFSYS_OPT_MAC_STATS + +#define EF10_MAC_STAT_READ(_esmp, _field, _eqp) \ + EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp) + + + __checkReturn efx_rc_t +ef10_mac_stats_update( + __in efx_nic_t *enp, + __in efsys_mem_t *esmp, + __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat, + __inout_opt uint32_t *generationp) +{ + efx_qword_t value; + efx_qword_t generation_start; + efx_qword_t generation_end; + + _NOTE(ARGUNUSED(enp)) + + /* Read END first so we don't race with the MC */ + EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END, + &generation_end); + EFSYS_MEM_READ_BARRIER(); + + /* TX */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_CONTROL_PKTS, &value); + EFSYS_STAT_SUBR_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PAUSE_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PAUSE_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_UNICAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_UNICST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTICAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULTICST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BROADCAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_BRDCST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BYTES, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_OCTETS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_128_TO_255_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_128_TO_255_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_256_TO_511_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_256_TO_511_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_512_TO_1023_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_512_TO_1023_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_1024_TO_15XX_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_1024_TO_15XX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_GTJUMBO_PKTS, &value); + EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BAD_FCS_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_SGL_COL_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULT_COL_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_COL_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LATE_COLLISION_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LATE_COL_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_DEFERRED_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_DEF_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value); + + /* RX */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNICAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_UNICST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MULTICAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MULTICST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BROADCAST_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_BRDCST_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PAUSE_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PAUSE_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNDERSIZE_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_64_PKTS, &value); + EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_65_TO_127_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_65_TO_127_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_128_TO_255_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_128_TO_255_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_256_TO_511_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_256_TO_511_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_512_TO_1023_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_512_TO_1023_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_1024_TO_15XX_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_1024_TO_15XX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_GTJUMBO_PKTS, &value); + EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BAD_FCS_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FCS_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_OVERFLOW_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_DROP_EVENTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_FALSE_CARRIER_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FALSE_CARRIER_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_SYMBOL_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_ALIGN_ERROR_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_ALIGN_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_INTERNAL_ERRORS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_JABBER_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_JABBER_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_CHAR_ERR, &value); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_CHAR_ERR]), + &(value.eq_dword[0])); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_CHAR_ERR]), + &(value.eq_dword[1])); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_CHAR_ERR, &value); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_CHAR_ERR]), + &(value.eq_dword[0])); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_CHAR_ERR]), + &(value.eq_dword[1])); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_DISP_ERR, &value); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_DISP_ERR]), + &(value.eq_dword[0])); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_DISP_ERR]), + &(value.eq_dword[1])); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_DISP_ERR, &value); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_DISP_ERR]), + &(value.eq_dword[0])); + EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_DISP_ERR]), + &(value.eq_dword[1])); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MATCH_FAULT, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MATCH_FAULT]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value); + + /* Packet memory (EF10 only) */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_BB_OVERFLOW, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_BB_OVERFLOW]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_BB_OVERFLOW, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_BB_OVERFLOW]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_VFIFO_FULL, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_VFIFO_FULL]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_VFIFO_FULL, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_VFIFO_FULL]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_QBB, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_QBB]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_QBB, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_QBB]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_MAPPING, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_MAPPING]), &value); + + /* RX datapath */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_Q_DISABLED_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_Q_DISABLED_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_DI_DROPPED_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_DI_DROPPED_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_STREAMING_PKTS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_STREAMING_PKTS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_FETCH]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_WAIT_CONDITIONS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_WAIT]), &value); + + + /* VADAPTER RX */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_BYTES, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_BYTES]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_OVERFLOW, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_OVERFLOW]), &value); + + /* VADAPTER TX */ + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_PACKETS, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_PACKETS]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_BYTES, + &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES]), + &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_PACKETS, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_PACKETS]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_BYTES, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_BYTES]), &value); + + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_OVERFLOW, &value); + EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_OVERFLOW]), &value); + + + EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); + EFSYS_MEM_READ_BARRIER(); + EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START, + &generation_start); + + /* Check that we didn't read the stats in the middle of a DMA */ + /* Not a good enough check ? */ + if (memcmp(&generation_start, &generation_end, + sizeof (generation_start))) + return (EAGAIN); + + if (generationp) + *generationp = EFX_QWORD_FIELD(generation_start, EFX_DWORD_0); + + return (0); +} + +#endif /* EFSYS_OPT_MAC_STATS */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_mac.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_mcdi.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_mcdi.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_mcdi.c (revision 301344) @@ -0,0 +1,303 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#if EFSYS_OPT_MCDI + +#ifndef WITH_MCDI_V2 +#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands." +#endif + + + __checkReturn efx_rc_t +ef10_mcdi_init( + __in efx_nic_t *enp, + __in const efx_mcdi_transport_t *emtp) +{ + efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); + efsys_mem_t *esmp = emtp->emt_dma_mem; + efx_dword_t dword; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA); + + /* + * All EF10 firmware supports MCDIv2 and MCDIv1. + * Medford BootROM supports MCDIv2 and MCDIv1. + * Huntington BootROM supports MCDIv1 only. + */ + emip->emi_max_version = 2; + + /* A host DMA buffer is required for EF10 MCDI */ + if (esmp == NULL) { + rc = EINVAL; + goto fail1; + } + + /* + * Ensure that the MC doorbell is in a known state before issuing MCDI + * commands. The recovery algorithm requires that the MC command buffer + * must be 256 byte aligned. See bug24769. + */ + if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) { + rc = EINVAL; + goto fail2; + } + EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1); + EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); + + /* Save initial MC reboot status */ + (void) ef10_mcdi_poll_reboot(enp); + + /* Start a new epoch (allow fresh MCDI requests to succeed) */ + efx_mcdi_new_epoch(enp); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_mcdi_fini( + __in efx_nic_t *enp) +{ + efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); + + emip->emi_new_epoch = B_FALSE; +} + + void +ef10_mcdi_send_request( + __in efx_nic_t *enp, + __in void *hdrp, + __in size_t hdr_len, + __in void *sdup, + __in size_t sdu_len) +{ + const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; + efsys_mem_t *esmp = emtp->emt_dma_mem; + efx_dword_t dword; + unsigned int pos; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Write the header */ + for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) { + dword = *(efx_dword_t *)((uint8_t *)hdrp + pos); + EFSYS_MEM_WRITED(esmp, pos, &dword); + } + + /* Write the payload */ + for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { + dword = *(efx_dword_t *)((uint8_t *)sdup + pos); + EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword); + } + + /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ + EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len); + EFSYS_PIO_WRITE_BARRIER(); + + /* Ring the doorbell to post the command DMA address to the MC */ + EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, + EFSYS_MEM_ADDR(esmp) >> 32); + EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); + + EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, + EFSYS_MEM_ADDR(esmp) & 0xffffffff); + EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); +} + + __checkReturn boolean_t +ef10_mcdi_poll_response( + __in efx_nic_t *enp) +{ + const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; + efsys_mem_t *esmp = emtp->emt_dma_mem; + efx_dword_t hdr; + + EFSYS_MEM_READD(esmp, 0, &hdr); + return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); +} + + void +ef10_mcdi_read_response( + __in efx_nic_t *enp, + __out_bcount(length) void *bufferp, + __in size_t offset, + __in size_t length) +{ + const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; + efsys_mem_t *esmp = emtp->emt_dma_mem; + unsigned int pos; + efx_dword_t data; + + for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { + EFSYS_MEM_READD(esmp, offset + pos, &data); + memcpy((uint8_t *)bufferp + pos, &data, + MIN(sizeof (data), length - pos)); + } +} + + efx_rc_t +ef10_mcdi_poll_reboot( + __in efx_nic_t *enp) +{ + efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); + efx_dword_t dword; + uint32_t old_status; + uint32_t new_status; + efx_rc_t rc; + + old_status = emip->emi_mc_reboot_status; + + /* Update MC reboot status word */ + EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); + new_status = dword.ed_u32[0]; + + /* MC has rebooted if the value has changed */ + if (new_status != old_status) { + emip->emi_mc_reboot_status = new_status; + + /* + * FIXME: Ignore detected MC REBOOT for now. + * + * The Siena support for checking for MC reboot from status + * flags is broken - see comments in siena_mcdi_poll_reboot(). + * As the generic MCDI code is shared the EF10 reboot + * detection suffers similar problems. + * + * Do not report an error when the boot status changes until + * this can be handled by common code drivers (and reworked to + * support Siena too). + */ + if (B_FALSE) { + rc = EIO; + goto fail1; + } + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_mcdi_feature_supported( + __in efx_nic_t *enp, + __in efx_mcdi_feature_id_t id, + __out boolean_t *supportedp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t privilege_mask = encp->enc_privilege_mask; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * Use privilege mask state at MCDI attach. + */ + + switch (id) { + case EFX_MCDI_FEATURE_FW_UPDATE: + /* + * Admin privilege must be used prior to introduction of + * specific flag. + */ + *supportedp = + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); + break; + case EFX_MCDI_FEATURE_LINK_CONTROL: + /* + * Admin privilege used prior to introduction of + * specific flag. + */ + *supportedp = + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); + break; + case EFX_MCDI_FEATURE_MACADDR_CHANGE: + /* + * Admin privilege must be used prior to introduction of + * mac spoofing privilege (at v4.6), which is used up to + * introduction of change mac spoofing privilege (at v4.7) + */ + *supportedp = + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); + break; + case EFX_MCDI_FEATURE_MAC_SPOOFING: + /* + * Admin privilege must be used prior to introduction of + * mac spoofing privilege (at v4.6), which is used up to + * introduction of mac spoofing TX privilege (at v4.7) + */ + *supportedp = + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || + EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); + break; + default: + rc = ENOTSUP; + goto fail1; + break; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#endif /* EFSYS_OPT_MCDI */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_mcdi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_nic.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_nic.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_nic.c (revision 301344) @@ -0,0 +1,1616 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" +#if EFSYS_OPT_MON_MCDI +#include "mcdi_mon.h" +#endif + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#include "ef10_tlv_layout.h" + + __checkReturn efx_rc_t +efx_mcdi_get_port_assignment( + __in efx_nic_t *enp, + __out uint32_t *portp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, + MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_port_modes( + __in efx_nic_t *enp, + __out uint32_t *modesp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, + MC_CMD_GET_PORT_MODES_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PORT_MODES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + /* + * Require only Modes and DefaultMode fields. + * (CurrentMode field was added for Medford) + */ + if (req.emr_out_length_used < + MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { + rc = EMSGSIZE; + goto fail2; + } + + *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_vadaptor_alloc( + __in efx_nic_t *enp, + __in uint32_t port_id) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, + MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; + + MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); + MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, + VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, + enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_vadaptor_free( + __in efx_nic_t *enp, + __in uint32_t port_id) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, + MC_CMD_VADAPTOR_FREE_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VADAPTOR_FREE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; + + MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_mac_address_pf( + __in efx_nic_t *enp, + __out_ecount_opt(6) uint8_t mac_addrp[6]) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, + MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { + rc = ENOENT; + goto fail3; + } + + if (mac_addrp != NULL) { + uint8_t *addrp; + + addrp = MCDI_OUT2(req, uint8_t, + GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); + + EFX_MAC_ADDR_COPY(mac_addrp, addrp); + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_mac_address_vf( + __in efx_nic_t *enp, + __out_ecount_opt(6) uint8_t mac_addrp[6]) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, + MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; + + MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, + EVB_PORT_ID_ASSIGNED); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < + MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { + rc = EMSGSIZE; + goto fail2; + } + + if (MCDI_OUT_DWORD(req, + VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { + rc = ENOENT; + goto fail3; + } + + if (mac_addrp != NULL) { + uint8_t *addrp; + + addrp = MCDI_OUT2(req, uint8_t, + VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); + + EFX_MAC_ADDR_COPY(mac_addrp, addrp); + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_clock( + __in efx_nic_t *enp, + __out uint32_t *sys_freqp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, + MC_CMD_GET_CLOCK_OUT_LEN)]; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_CLOCK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); + if (*sys_freqp == 0) { + rc = EINVAL; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +efx_mcdi_get_vector_cfg( + __in efx_nic_t *enp, + __out_opt uint32_t *vec_basep, + __out_opt uint32_t *pf_nvecp, + __out_opt uint32_t *vf_nvecp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, + MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_VECTOR_CFG; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + if (vec_basep != NULL) + *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); + if (pf_nvecp != NULL) + *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); + if (vf_nvecp != NULL) + *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_get_capabilities( + __in efx_nic_t *enp, + __out uint32_t *flagsp, + __out uint32_t *flags2p) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, + MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_CAPABILITIES; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); + + if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) + *flags2p = 0; + else + *flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_alloc_vis( + __in efx_nic_t *enp, + __in uint32_t min_vi_count, + __in uint32_t max_vi_count, + __out uint32_t *vi_basep, + __out uint32_t *vi_countp, + __out uint32_t *vi_shiftp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, + MC_CMD_ALLOC_VIS_OUT_LEN)]; + efx_rc_t rc; + + if (vi_countp == NULL) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ALLOC_VIS; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; + + MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); + MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); + *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); + + /* Report VI_SHIFT if available (always zero for Huntington) */ + if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) + *vi_shiftp = 0; + else + *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_free_vis( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + efx_rc_t rc; + + EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); + EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); + + req.emr_cmd = MC_CMD_FREE_VIS; + req.emr_in_buf = NULL; + req.emr_in_length = 0; + req.emr_out_buf = NULL; + req.emr_out_length = 0; + + efx_mcdi_execute_quiet(enp, &req); + + /* Ignore ELREADY (no allocated VIs, so nothing to free) */ + if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +static __checkReturn efx_rc_t +efx_mcdi_alloc_piobuf( + __in efx_nic_t *enp, + __out efx_piobuf_handle_t *handlep) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, + MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + if (handlep == NULL) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ALLOC_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; + + efx_mcdi_execute_quiet(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { + rc = EMSGSIZE; + goto fail3; + } + + *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_free_piobuf( + __in efx_nic_t *enp, + __in efx_piobuf_handle_t handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, + MC_CMD_FREE_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FREE_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); + + efx_mcdi_execute_quiet(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_link_piobuf( + __in efx_nic_t *enp, + __in uint32_t vi_index, + __in efx_piobuf_handle_t handle) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, + MC_CMD_LINK_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_LINK_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); + MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_unlink_piobuf( + __in efx_nic_t *enp, + __in uint32_t vi_index) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, + MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_UNLINK_PIOBUF; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; + + MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static void +ef10_nic_alloc_piobufs( + __in efx_nic_t *enp, + __in uint32_t max_piobuf_count) +{ + efx_piobuf_handle_t *handlep; + unsigned int i; + efx_rc_t rc; + + EFSYS_ASSERT3U(max_piobuf_count, <=, + EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); + + enp->en_arch.ef10.ena_piobuf_count = 0; + + for (i = 0; i < max_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) + goto fail1; + + enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; + enp->en_arch.ef10.ena_piobuf_count++; + } + + return; + +fail1: + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + efx_mcdi_free_piobuf(enp, *handlep); + *handlep = EFX_PIOBUF_HANDLE_INVALID; + } + enp->en_arch.ef10.ena_piobuf_count = 0; +} + + +static void +ef10_nic_free_piobufs( + __in efx_nic_t *enp) +{ + efx_piobuf_handle_t *handlep; + unsigned int i; + + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; + + efx_mcdi_free_piobuf(enp, *handlep); + *handlep = EFX_PIOBUF_HANDLE_INVALID; + } + enp->en_arch.ef10.ena_piobuf_count = 0; +} + +/* Sub-allocate a block from a piobuf */ + __checkReturn efx_rc_t +ef10_nic_pio_alloc( + __inout efx_nic_t *enp, + __out uint32_t *bufnump, + __out efx_piobuf_handle_t *handlep, + __out uint32_t *blknump, + __out uint32_t *offsetp, + __out size_t *sizep) +{ + efx_nic_cfg_t *encp = &enp->en_nic_cfg; + efx_drv_cfg_t *edcp = &enp->en_drv_cfg; + uint32_t blk_per_buf; + uint32_t buf, blk; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + EFSYS_ASSERT(bufnump); + EFSYS_ASSERT(handlep); + EFSYS_ASSERT(blknump); + EFSYS_ASSERT(offsetp); + EFSYS_ASSERT(sizep); + + if ((edcp->edc_pio_alloc_size == 0) || + (enp->en_arch.ef10.ena_piobuf_count == 0)) { + rc = ENOMEM; + goto fail1; + } + blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; + + for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { + uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; + + if (~(*map) == 0) + continue; + + EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); + for (blk = 0; blk < blk_per_buf; blk++) { + if ((*map & (1u << blk)) == 0) { + *map |= (1u << blk); + goto done; + } + } + } + rc = ENOMEM; + goto fail2; + +done: + *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; + *bufnump = buf; + *blknump = blk; + *sizep = edcp->edc_pio_alloc_size; + *offsetp = blk * (*sizep); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* Free a piobuf sub-allocated block */ + __checkReturn efx_rc_t +ef10_nic_pio_free( + __inout efx_nic_t *enp, + __in uint32_t bufnum, + __in uint32_t blknum) +{ + uint32_t *map; + efx_rc_t rc; + + if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || + (blknum >= (8 * sizeof (*map)))) { + rc = EINVAL; + goto fail1; + } + + map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; + if ((*map & (1u << blknum)) == 0) { + rc = ENOENT; + goto fail2; + } + *map &= ~(1u << blknum); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_pio_link( + __inout efx_nic_t *enp, + __in uint32_t vi_index, + __in efx_piobuf_handle_t handle) +{ + return (efx_mcdi_link_piobuf(enp, vi_index, handle)); +} + + __checkReturn efx_rc_t +ef10_nic_pio_unlink( + __inout efx_nic_t *enp, + __in uint32_t vi_index) +{ + return (efx_mcdi_unlink_piobuf(enp, vi_index)); +} + + __checkReturn efx_rc_t +ef10_get_datapath_caps( + __in efx_nic_t *enp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t flags; + uint32_t flags2; + efx_rc_t rc; + + if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0) + goto fail1; + +#define CAP_FLAG(flags1, field) \ + ((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) + +#define CAP_FLAG2(flags2, field) \ + ((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) + + /* + * Huntington RXDP firmware inserts a 0 or 14 byte prefix. + * We only support the 14 byte prefix here. + */ + if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) { + rc = ENOTSUP; + goto fail2; + } + encp->enc_rx_prefix_size = 14; + + /* Check if the firmware supports TSO */ + encp->enc_fw_assisted_tso_enabled = + CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports FATSOv2 */ + encp->enc_fw_assisted_tso_v2_enabled = + CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE; + + /* Check if the firmware has vadapter/vport/vswitch support */ + encp->enc_datapath_cap_evb = + CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports VLAN insertion */ + encp->enc_hw_tx_insert_vlan_enabled = + CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports RX event batching */ + encp->enc_rx_batching_enabled = + CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE; + + if (encp->enc_rx_batching_enabled) + encp->enc_rx_batch_max = 16; + + /* Check if the firmware supports disabling scatter on RXQs */ + encp->enc_rx_disable_scatter_supported = + CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; + + /* Check if the firmware supports set mac with running filters */ + encp->enc_allow_set_mac_with_installed_filters = + CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? + B_TRUE : B_FALSE; + + /* + * Check if firmware supports the extended MC_CMD_SET_MAC, which allows + * specifying which parameters to configure. + */ + encp->enc_enhanced_set_mac_supported = + CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; + +#undef CAP_FLAG +#undef CAP_FLAG2 + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_get_privilege_mask( + __in efx_nic_t *enp, + __out uint32_t *maskp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + uint32_t mask; + efx_rc_t rc; + + if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, + &mask)) != 0) { + if (rc != ENOTSUP) + goto fail1; + + /* Fallback for old firmware without privilege mask support */ + if (EFX_PCI_FUNCTION_IS_PF(encp)) { + /* Assume PF has admin privilege */ + mask = EF10_LEGACY_PF_PRIVILEGE_MASK; + } else { + /* VF is always unprivileged by default */ + mask = EF10_LEGACY_VF_PRIVILEGE_MASK; + } + } + + *maskp = mask; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + +/* + * The external port mapping is a one-based numbering of the external + * connectors on the board. It does not distinguish off-board separated + * outputs such as multi-headed cables. + * The number of ports that map to each external port connector + * on the board is determined by the chip family and the port modes to + * which the NIC can be configured. The mapping table lists modes with + * port numbering requirements in increasing order. + */ +static struct { + efx_family_t family; + uint32_t modes_mask; + uint32_t stride; +} __ef10_external_port_mappings[] = { + /* Supported modes requiring 1 output per port */ + { + EFX_FAMILY_HUNTINGTON, + (1 << TLV_PORT_MODE_10G) | + (1 << TLV_PORT_MODE_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G), + 1 + }, + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_10G) | + (1 << TLV_PORT_MODE_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G), + 1 + }, + /* Supported modes requiring 2 outputs per port */ + { + EFX_FAMILY_HUNTINGTON, + (1 << TLV_PORT_MODE_40G) | + (1 << TLV_PORT_MODE_40G_40G) | + (1 << TLV_PORT_MODE_40G_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_40G), + 2 + }, + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_40G) | + (1 << TLV_PORT_MODE_40G_40G) | + (1 << TLV_PORT_MODE_40G_10G_10G) | + (1 << TLV_PORT_MODE_10G_10G_40G), + 2 + }, + /* Supported modes requiring 4 outputs per port */ + { + EFX_FAMILY_MEDFORD, + (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) | + (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2), + 4 + }, +}; + + __checkReturn efx_rc_t +ef10_external_port_mapping( + __in efx_nic_t *enp, + __in uint32_t port, + __out uint8_t *external_portp) +{ + efx_rc_t rc; + int i; + uint32_t port_modes; + uint32_t matches; + uint32_t stride = 1; /* default 1-1 mapping */ + + if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { + /* No port mode information available - use default mapping */ + goto out; + } + + /* + * Infer the internal port -> external port mapping from + * the possible port modes for this NIC. + */ + for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { + if (__ef10_external_port_mappings[i].family != + enp->en_family) + continue; + matches = (__ef10_external_port_mappings[i].modes_mask & + port_modes); + if (matches != 0) { + stride = __ef10_external_port_mappings[i].stride; + port_modes &= ~matches; + } + } + + if (port_modes != 0) { + /* Some advertised modes are not supported */ + rc = ENOTSUP; + goto fail1; + } + +out: + /* + * Scale as required by last matched mode and then convert to + * one-based numbering + */ + *external_portp = (uint8_t)(port / stride) + 1; + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_nic_probe( + __in efx_nic_t *enp) +{ + const efx_nic_ops_t *enop = enp->en_enop; + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Read and clear any assertion state */ + if ((rc = efx_mcdi_read_assertion(enp)) != 0) + goto fail1; + + /* Exit the assertion handler */ + if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) + if (rc != EACCES) + goto fail2; + + if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) + goto fail3; + + if ((rc = enop->eno_board_cfg(enp)) != 0) + if (rc != EACCES) + goto fail4; + + /* + * Set default driver config limits (based on board config). + * + * FIXME: For now allocate a fixed number of VIs which is likely to be + * sufficient and small enough to allow multiple functions on the same + * port. + */ + edcp->edc_min_vi_count = edcp->edc_max_vi_count = + MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); + + /* The client driver must configure and enable PIO buffer support */ + edcp->edc_max_piobuf_count = 0; + edcp->edc_pio_alloc_size = 0; + +#if EFSYS_OPT_MAC_STATS + /* Wipe the MAC statistics */ + if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) + goto fail5; +#endif + +#if EFSYS_OPT_LOOPBACK + if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) + goto fail6; +#endif + +#if EFSYS_OPT_MON_STATS + if ((rc = mcdi_mon_cfg_build(enp)) != 0) { + /* Unprivileged functions do not have access to sensors */ + if (rc != EACCES) + goto fail7; + } +#endif + + encp->enc_features = enp->en_features; + + return (0); + +#if EFSYS_OPT_MON_STATS +fail7: + EFSYS_PROBE(fail7); +#endif +#if EFSYS_OPT_LOOPBACK +fail6: + EFSYS_PROBE(fail6); +#endif +#if EFSYS_OPT_MAC_STATS +fail5: + EFSYS_PROBE(fail5); +#endif +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_set_drv_limits( + __inout efx_nic_t *enp, + __in efx_drv_limits_t *edlp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + uint32_t min_evq_count, max_evq_count; + uint32_t min_rxq_count, max_rxq_count; + uint32_t min_txq_count, max_txq_count; + efx_rc_t rc; + + if (edlp == NULL) { + rc = EINVAL; + goto fail1; + } + + /* Get minimum required and maximum usable VI limits */ + min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); + min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); + min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); + + edcp->edc_min_vi_count = + MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); + + max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); + max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); + max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); + + edcp->edc_max_vi_count = + MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); + + /* + * Check limits for sub-allocated piobuf blocks. + * PIO is optional, so don't fail if the limits are incorrect. + */ + if ((encp->enc_piobuf_size == 0) || + (encp->enc_piobuf_limit == 0) || + (edlp->edl_min_pio_alloc_size == 0) || + (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { + /* Disable PIO */ + edcp->edc_max_piobuf_count = 0; + edcp->edc_pio_alloc_size = 0; + } else { + uint32_t blk_size, blk_count, blks_per_piobuf; + + blk_size = + MAX(edlp->edl_min_pio_alloc_size, + encp->enc_piobuf_min_alloc_size); + + blks_per_piobuf = encp->enc_piobuf_size / blk_size; + EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); + + blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); + + /* A zero max pio alloc count means unlimited */ + if ((edlp->edl_max_pio_alloc_count > 0) && + (edlp->edl_max_pio_alloc_count < blk_count)) { + blk_count = edlp->edl_max_pio_alloc_count; + } + + edcp->edc_pio_alloc_size = blk_size; + edcp->edc_max_piobuf_count = + (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + __checkReturn efx_rc_t +ef10_nic_reset( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, + MC_CMD_ENTITY_RESET_OUT_LEN)]; + efx_rc_t rc; + + /* ef10_nic_reset() is called to recover from BADASSERT failures. */ + if ((rc = efx_mcdi_read_assertion(enp)) != 0) + goto fail1; + if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) + goto fail2; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_ENTITY_RESET; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; + + MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, + ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + /* Clear RX/TX DMA queue errors */ + enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_init( + __in efx_nic_t *enp) +{ + efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); + uint32_t min_vi_count, max_vi_count; + uint32_t vi_count, vi_base, vi_shift; + uint32_t i; + uint32_t retry; + uint32_t delay_us; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Enable reporting of some events (e.g. link change) */ + if ((rc = efx_mcdi_log_ctrl(enp)) != 0) + goto fail1; + + /* Allocate (optional) on-chip PIO buffers */ + ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); + + /* + * For best performance, PIO writes should use a write-combined + * (WC) memory mapping. Using a separate WC mapping for the PIO + * aperture of each VI would be a burden to drivers (and not + * possible if the host page size is >4Kbyte). + * + * To avoid this we use a single uncached (UC) mapping for VI + * register access, and a single WC mapping for extra VIs used + * for PIO writes. + * + * Each piobuf must be linked to a VI in the WC mapping, and to + * each VI that is using a sub-allocated block from the piobuf. + */ + min_vi_count = edcp->edc_min_vi_count; + max_vi_count = + edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; + + /* Ensure that the previously attached driver's VIs are freed */ + if ((rc = efx_mcdi_free_vis(enp)) != 0) + goto fail2; + + /* + * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this + * fails then retrying the request for fewer VI resources may succeed. + */ + vi_count = 0; + if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, + &vi_base, &vi_count, &vi_shift)) != 0) + goto fail3; + + EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); + + if (vi_count < min_vi_count) { + rc = ENOMEM; + goto fail4; + } + + enp->en_arch.ef10.ena_vi_base = vi_base; + enp->en_arch.ef10.ena_vi_count = vi_count; + enp->en_arch.ef10.ena_vi_shift = vi_shift; + + if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { + /* Not enough extra VIs to map piobufs */ + ef10_nic_free_piobufs(enp); + } + + enp->en_arch.ef10.ena_pio_write_vi_base = + vi_count - enp->en_arch.ef10.ena_piobuf_count; + + /* Save UC memory mapping details */ + enp->en_arch.ef10.ena_uc_mem_map_offset = 0; + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + enp->en_arch.ef10.ena_uc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_pio_write_vi_base); + } else { + enp->en_arch.ef10.ena_uc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_vi_count); + } + + /* Save WC memory mapping details */ + enp->en_arch.ef10.ena_wc_mem_map_offset = + enp->en_arch.ef10.ena_uc_mem_map_offset + + enp->en_arch.ef10.ena_uc_mem_map_size; + + enp->en_arch.ef10.ena_wc_mem_map_size = + (ER_DZ_TX_PIOBUF_STEP * + enp->en_arch.ef10.ena_piobuf_count); + + /* Link piobufs to extra VIs in WC mapping */ + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + rc = efx_mcdi_link_piobuf(enp, + enp->en_arch.ef10.ena_pio_write_vi_base + i, + enp->en_arch.ef10.ena_piobuf_handle[i]); + if (rc != 0) + break; + } + } + + /* + * Allocate a vAdaptor attached to our upstream vPort/pPort. + * + * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF + * driver has yet to bring up the EVB port. See bug 56147. In this case, + * retry the request several times after waiting a while. The wait time + * between retries starts small (10ms) and exponentially increases. + * Total wait time is a little over two seconds. Retry logic in the + * client driver may mean this whole loop is repeated if it continues to + * fail. + */ + retry = 0; + delay_us = 10000; + while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { + if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || + (rc != ENOENT)) { + /* + * Do not retry alloc for PF, or for other errors on + * a VF. + */ + goto fail5; + } + + /* VF startup before PF is ready. Retry allocation. */ + if (retry > 5) { + /* Too many attempts */ + rc = EINVAL; + goto fail6; + } + EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); + EFSYS_SLEEP(delay_us); + retry++; + if (delay_us < 500000) + delay_us <<= 2; + } + + enp->en_vport_id = EVB_PORT_ID_ASSIGNED; + enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; + + return (0); + +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); + + ef10_nic_free_piobufs(enp); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nic_get_vi_pool( + __in efx_nic_t *enp, + __out uint32_t *vi_countp) +{ + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * Report VIs that the client driver can use. + * Do not include VIs used for PIO buffer writes. + */ + *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; + + return (0); +} + + __checkReturn efx_rc_t +ef10_nic_get_bar_region( + __in efx_nic_t *enp, + __in efx_nic_region_t region, + __out uint32_t *offsetp, + __out size_t *sizep) +{ + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * TODO: Specify host memory mapping alignment and granularity + * in efx_drv_limits_t so that they can be taken into account + * when allocating extra VIs for PIO writes. + */ + switch (region) { + case EFX_REGION_VI: + /* UC mapped memory BAR region for VI registers */ + *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; + *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; + break; + + case EFX_REGION_PIO_WRITE_VI: + /* WC mapped memory BAR region for piobuf writes */ + *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; + *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; + break; + + default: + rc = EINVAL; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_nic_fini( + __in efx_nic_t *enp) +{ + uint32_t i; + efx_rc_t rc; + + (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); + enp->en_vport_id = 0; + + /* Unlink piobufs from extra VIs in WC mapping */ + if (enp->en_arch.ef10.ena_piobuf_count > 0) { + for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { + rc = efx_mcdi_unlink_piobuf(enp, + enp->en_arch.ef10.ena_pio_write_vi_base + i); + if (rc != 0) + break; + } + } + + ef10_nic_free_piobufs(enp); + + (void) efx_mcdi_free_vis(enp); + enp->en_arch.ef10.ena_vi_count = 0; +} + + void +ef10_nic_unprobe( + __in efx_nic_t *enp) +{ +#if EFSYS_OPT_MON_STATS + mcdi_mon_cfg_free(enp); +#endif /* EFSYS_OPT_MON_STATS */ + (void) efx_mcdi_drv_attach(enp, B_FALSE); +} + +#if EFSYS_OPT_DIAG + + __checkReturn efx_rc_t +ef10_nic_register_test( + __in efx_nic_t *enp) +{ + efx_rc_t rc; + + /* FIXME */ + _NOTE(ARGUNUSED(enp)) + if (B_FALSE) { + rc = ENOTSUP; + goto fail1; + } + /* FIXME */ + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#endif /* EFSYS_OPT_DIAG */ + + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_nic.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_nvram.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_nvram.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_nvram.c (revision 301344) @@ -0,0 +1,2333 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM + +#include "ef10_tlv_layout.h" + +/* Cursor for TLV partition format */ +typedef struct tlv_cursor_s { + uint32_t *block; /* Base of data block */ + uint32_t *current; /* Cursor position */ + uint32_t *end; /* End tag position */ + uint32_t *limit; /* Last dword of data block */ +} tlv_cursor_t; + +typedef struct nvram_partition_s { + uint16_t type; + uint8_t chip_select; + uint8_t flags; + /* + * The full length of the NVRAM partition. + * This is different from tlv_partition_header.total_length, + * which can be smaller. + */ + uint32_t length; + uint32_t erase_size; + uint32_t *data; + tlv_cursor_t tlv_cursor; +} nvram_partition_t; + + +static __checkReturn efx_rc_t +tlv_validate_state( + __inout tlv_cursor_t *cursor); + + +static void +tlv_init_block( + __out uint32_t *block) +{ + *block = __CPU_TO_LE_32(TLV_TAG_END); +} + +static uint32_t +tlv_tag( + __in tlv_cursor_t *cursor) +{ + uint32_t dword, tag; + + dword = cursor->current[0]; + tag = __LE_TO_CPU_32(dword); + + return (tag); +} + +static size_t +tlv_length( + __in tlv_cursor_t *cursor) +{ + uint32_t dword, length; + + if (tlv_tag(cursor) == TLV_TAG_END) + return (0); + + dword = cursor->current[1]; + length = __LE_TO_CPU_32(dword); + + return ((size_t)length); +} + +static uint8_t * +tlv_value( + __in tlv_cursor_t *cursor) +{ + if (tlv_tag(cursor) == TLV_TAG_END) + return (NULL); + + return ((uint8_t *)(&cursor->current[2])); +} + +static uint8_t * +tlv_item( + __in tlv_cursor_t *cursor) +{ + if (tlv_tag(cursor) == TLV_TAG_END) + return (NULL); + + return ((uint8_t *)cursor->current); +} + +/* + * TLV item DWORD length is tag + length + value (rounded up to DWORD) + * equivalent to tlv_n_words_for_len in mc-comms tlv.c + */ +#define TLV_DWORD_COUNT(length) \ + (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t))) + + +static uint32_t * +tlv_next_item_ptr( + __in tlv_cursor_t *cursor) +{ + uint32_t length; + + length = tlv_length(cursor); + + return (cursor->current + TLV_DWORD_COUNT(length)); +} + +static __checkReturn efx_rc_t +tlv_advance( + __inout tlv_cursor_t *cursor) +{ + efx_rc_t rc; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + if (cursor->current == cursor->end) { + /* No more tags after END tag */ + cursor->current = NULL; + rc = ENOENT; + goto fail2; + } + + /* Advance to next item and validate */ + cursor->current = tlv_next_item_ptr(cursor); + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail3; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static efx_rc_t +tlv_rewind( + __in tlv_cursor_t *cursor) +{ + efx_rc_t rc; + + cursor->current = cursor->block; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static efx_rc_t +tlv_find( + __inout tlv_cursor_t *cursor, + __in uint32_t tag) +{ + efx_rc_t rc; + + rc = tlv_rewind(cursor); + while (rc == 0) { + if (tlv_tag(cursor) == tag) + break; + + rc = tlv_advance(cursor); + } + return (rc); +} + +static __checkReturn efx_rc_t +tlv_validate_state( + __inout tlv_cursor_t *cursor) +{ + efx_rc_t rc; + + /* Check cursor position */ + if (cursor->current < cursor->block) { + rc = EINVAL; + goto fail1; + } + if (cursor->current > cursor->limit) { + rc = EINVAL; + goto fail2; + } + + if (tlv_tag(cursor) != TLV_TAG_END) { + /* Check current item has space for tag and length */ + if (cursor->current > (cursor->limit - 2)) { + cursor->current = NULL; + rc = EFAULT; + goto fail3; + } + + /* Check we have value data for current item and another tag */ + if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) { + cursor->current = NULL; + rc = EFAULT; + goto fail4; + } + } + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static efx_rc_t +tlv_init_cursor( + __out tlv_cursor_t *cursor, + __in uint32_t *block, + __in uint32_t *limit, + __in uint32_t *current) +{ + cursor->block = block; + cursor->limit = limit; + + cursor->current = current; + cursor->end = NULL; + + return (tlv_validate_state(cursor)); +} + +static __checkReturn efx_rc_t +tlv_init_cursor_from_size( + __out tlv_cursor_t *cursor, + __in_bcount(size) + uint8_t *block, + __in size_t size) +{ + uint32_t *limit; + limit = (uint32_t *)(block + size - sizeof (uint32_t)); + return (tlv_init_cursor(cursor, (uint32_t *)block, + limit, (uint32_t *)block)); +} + +static __checkReturn efx_rc_t +tlv_init_cursor_at_offset( + __out tlv_cursor_t *cursor, + __in_bcount(size) + uint8_t *block, + __in size_t size, + __in size_t offset) +{ + uint32_t *limit; + uint32_t *current; + limit = (uint32_t *)(block + size - sizeof (uint32_t)); + current = (uint32_t *)(block + offset); + return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current)); +} + +static __checkReturn efx_rc_t +tlv_require_end( + __inout tlv_cursor_t *cursor) +{ + uint32_t *pos; + efx_rc_t rc; + + if (cursor->end == NULL) { + pos = cursor->current; + if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0) + goto fail1; + + cursor->end = cursor->current; + cursor->current = pos; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static size_t +tlv_block_length_used( + __inout tlv_cursor_t *cursor) +{ + efx_rc_t rc; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + if ((rc = tlv_require_end(cursor)) != 0) + goto fail2; + + /* Return space used (including the END tag) */ + return (cursor->end + 1 - cursor->block) * sizeof (uint32_t); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (0); +} + +static uint32_t * +tlv_last_segment_end( + __in tlv_cursor_t *cursor) +{ + tlv_cursor_t segment_cursor; + uint32_t *last_segment_end = cursor->block; + uint32_t *segment_start = cursor->block; + + /* + * Go through each segment and check that it has an end tag. If there + * is no end tag then the previous segment was the last valid one, + * so return the pointer to its end tag. + */ + while (1) { + if (tlv_init_cursor(&segment_cursor, segment_start, + cursor->limit, segment_start) != 0) + break; + if (tlv_require_end(&segment_cursor) != 0) + break; + last_segment_end = segment_cursor.end; + segment_start = segment_cursor.end + 1; + } + + return (last_segment_end); +} + + +static uint32_t * +tlv_write( + __in tlv_cursor_t *cursor, + __in uint32_t tag, + __in_bcount(size) uint8_t *data, + __in size_t size) +{ + uint32_t len = size; + uint32_t *ptr; + + ptr = cursor->current; + + *ptr++ = __CPU_TO_LE_32(tag); + *ptr++ = __CPU_TO_LE_32(len); + + if (len > 0) { + ptr[(len - 1) / sizeof (uint32_t)] = 0; + memcpy(ptr, data, len); + ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr); + } + + return (ptr); +} + +static __checkReturn efx_rc_t +tlv_insert( + __inout tlv_cursor_t *cursor, + __in uint32_t tag, + __in_bcount(size) + uint8_t *data, + __in size_t size) +{ + unsigned int delta; + uint32_t *last_segment_end; + efx_rc_t rc; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + if ((rc = tlv_require_end(cursor)) != 0) + goto fail2; + + if (tag == TLV_TAG_END) { + rc = EINVAL; + goto fail3; + } + + last_segment_end = tlv_last_segment_end(cursor); + + delta = TLV_DWORD_COUNT(size); + if (last_segment_end + 1 + delta > cursor->limit) { + rc = ENOSPC; + goto fail4; + } + + /* Move data up: new space at cursor->current */ + memmove(cursor->current + delta, cursor->current, + (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); + + /* Adjust the end pointer */ + cursor->end += delta; + + /* Write new TLV item */ + tlv_write(cursor, tag, data, size); + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +tlv_delete( + __inout tlv_cursor_t *cursor) +{ + unsigned int delta; + uint32_t *last_segment_end; + efx_rc_t rc; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + if (tlv_tag(cursor) == TLV_TAG_END) { + rc = EINVAL; + goto fail2; + } + + delta = TLV_DWORD_COUNT(tlv_length(cursor)); + + if ((rc = tlv_require_end(cursor)) != 0) + goto fail3; + + last_segment_end = tlv_last_segment_end(cursor); + + /* Shuffle things down, destroying the item at cursor->current */ + memmove(cursor->current, cursor->current + delta, + (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); + /* Zero the new space at the end of the TLV chain */ + memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t)); + /* Adjust the end pointer */ + cursor->end -= delta; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +tlv_modify( + __inout tlv_cursor_t *cursor, + __in uint32_t tag, + __in_bcount(size) + uint8_t *data, + __in size_t size) +{ + uint32_t *pos; + unsigned int old_ndwords; + unsigned int new_ndwords; + unsigned int delta; + uint32_t *last_segment_end; + efx_rc_t rc; + + if ((rc = tlv_validate_state(cursor)) != 0) + goto fail1; + + if (tlv_tag(cursor) == TLV_TAG_END) { + rc = EINVAL; + goto fail2; + } + if (tlv_tag(cursor) != tag) { + rc = EINVAL; + goto fail3; + } + + old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor)); + new_ndwords = TLV_DWORD_COUNT(size); + + if ((rc = tlv_require_end(cursor)) != 0) + goto fail4; + + last_segment_end = tlv_last_segment_end(cursor); + + if (new_ndwords > old_ndwords) { + /* Expand space used for TLV item */ + delta = new_ndwords - old_ndwords; + pos = cursor->current + old_ndwords; + + if (last_segment_end + 1 + delta > cursor->limit) { + rc = ENOSPC; + goto fail5; + } + + /* Move up: new space at (cursor->current + old_ndwords) */ + memmove(pos + delta, pos, + (last_segment_end + 1 - pos) * sizeof (uint32_t)); + + /* Adjust the end pointer */ + cursor->end += delta; + + } else if (new_ndwords < old_ndwords) { + /* Shrink space used for TLV item */ + delta = old_ndwords - new_ndwords; + pos = cursor->current + new_ndwords; + + /* Move down: remove words at (cursor->current + new_ndwords) */ + memmove(pos, pos + delta, + (last_segment_end + 1 - pos) * sizeof (uint32_t)); + + /* Zero the new space at the end of the TLV chain */ + memset(last_segment_end + 1 - delta, 0, + delta * sizeof (uint32_t)); + + /* Adjust the end pointer */ + cursor->end -= delta; + } + + /* Write new data */ + tlv_write(cursor, tag, data, size); + + return (0); + +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static uint32_t checksum_tlv_partition( + __in nvram_partition_t *partition) +{ + tlv_cursor_t *cursor; + uint32_t *ptr; + uint32_t *end; + uint32_t csum; + size_t len; + + cursor = &partition->tlv_cursor; + len = tlv_block_length_used(cursor); + EFSYS_ASSERT3U((len & 3), ==, 0); + + csum = 0; + ptr = partition->data; + end = &ptr[len >> 2]; + + while (ptr < end) + csum += __LE_TO_CPU_32(*ptr++); + + return (csum); +} + +static __checkReturn efx_rc_t +tlv_update_partition_len_and_cks( + __in tlv_cursor_t *cursor) +{ + efx_rc_t rc; + nvram_partition_t partition; + struct tlv_partition_header *header; + struct tlv_partition_trailer *trailer; + size_t new_len; + + /* + * We just modified the partition, so the total length may not be + * valid. Don't use tlv_find(), which performs some sanity checks + * that may fail here. + */ + partition.data = cursor->block; + memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor)); + header = (struct tlv_partition_header *)partition.data; + /* Sanity check. */ + if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) { + rc = EFAULT; + goto fail1; + } + new_len = tlv_block_length_used(&partition.tlv_cursor); + if (new_len == 0) { + rc = EFAULT; + goto fail2; + } + header->total_length = __CPU_TO_LE_32(new_len); + /* Ensure the modified partition always has a new generation count. */ + header->generation = __CPU_TO_LE_32( + __LE_TO_CPU_32(header->generation) + 1); + + trailer = (struct tlv_partition_trailer *)((uint8_t *)header + + new_len - sizeof (*trailer) - sizeof (uint32_t)); + trailer->generation = header->generation; + trailer->checksum = __CPU_TO_LE_32( + __LE_TO_CPU_32(trailer->checksum) - + checksum_tlv_partition(&partition)); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* Validate buffer contents (before writing to flash) */ + __checkReturn efx_rc_t +ef10_nvram_buffer_validate( + __in efx_nic_t *enp, + __in uint32_t partn, + __in_bcount(partn_size) caddr_t partn_data, + __in size_t partn_size) +{ + tlv_cursor_t cursor; + struct tlv_partition_header *header; + struct tlv_partition_trailer *trailer; + size_t total_length; + uint32_t cksum; + int pos; + efx_rc_t rc; + + EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); + + if ((partn_data == NULL) || (partn_size == 0)) { + rc = EINVAL; + goto fail1; + } + + /* The partition header must be the first item (at offset zero) */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, + partn_size)) != 0) { + rc = EFAULT; + goto fail2; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail3; + } + header = (struct tlv_partition_header *)tlv_item(&cursor); + + /* Check TLV partition length (includes the END tag) */ + total_length = __LE_TO_CPU_32(header->total_length); + if (total_length > partn_size) { + rc = EFBIG; + goto fail4; + } + + /* Check partition ends with PARTITION_TRAILER and END tags */ + if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { + rc = EINVAL; + goto fail5; + } + trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); + + if ((rc = tlv_advance(&cursor)) != 0) { + rc = EINVAL; + goto fail6; + } + if (tlv_tag(&cursor) != TLV_TAG_END) { + rc = EINVAL; + goto fail7; + } + + /* Check generation counts are consistent */ + if (trailer->generation != header->generation) { + rc = EINVAL; + goto fail8; + } + + /* Verify partition checksum */ + cksum = 0; + for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { + cksum += *((uint32_t *)(partn_data + pos)); + } + if (cksum != 0) { + rc = EINVAL; + goto fail9; + } + + return (0); + +fail9: + EFSYS_PROBE(fail9); +fail8: + EFSYS_PROBE(fail8); +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + + __checkReturn efx_rc_t +ef10_nvram_buffer_create( + __in efx_nic_t *enp, + __in uint16_t partn_type, + __in_bcount(partn_size) caddr_t partn_data, + __in size_t partn_size) +{ + uint32_t *buf = (uint32_t *)partn_data; + efx_rc_t rc; + tlv_cursor_t cursor; + struct tlv_partition_header header; + struct tlv_partition_trailer trailer; + + unsigned min_buf_size = sizeof (struct tlv_partition_header) + + sizeof (struct tlv_partition_trailer); + if (partn_size < min_buf_size) { + rc = EINVAL; + goto fail1; + } + + memset(buf, 0xff, partn_size); + + tlv_init_block(buf); + if ((rc = tlv_init_cursor(&cursor, buf, + (uint32_t *)((uint8_t *)buf + partn_size), + buf)) != 0) { + goto fail2; + } + + header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); + header.length = __CPU_TO_LE_32(sizeof (header) - 8); + header.type_id = __CPU_TO_LE_16(partn_type); + header.preset = 0; + header.generation = __CPU_TO_LE_32(1); + header.total_length = 0; /* This will be fixed below. */ + if ((rc = tlv_insert( + &cursor, TLV_TAG_PARTITION_HEADER, + (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) + goto fail3; + if ((rc = tlv_advance(&cursor)) != 0) + goto fail4; + + trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); + trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); + trailer.generation = header.generation; + trailer.checksum = 0; /* This will be fixed below. */ + if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, + (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) + goto fail5; + + if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) + goto fail6; + + /* Check that the partition is valid. */ + if ((rc = ef10_nvram_buffer_validate(enp, partn_type, + partn_data, partn_size)) != 0) + goto fail7; + + return (0); + +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static uint32_t +byte_offset( + __in uint32_t *position, + __in uint32_t *base) +{ + return (uint32_t)((uint8_t *)position - (uint8_t *)base); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_find_item_start( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __out uint32_t *startp) +{ + // Read past partition header to find start address of the first key + tlv_cursor_t cursor; + efx_rc_t rc; + + /* A PARTITION_HEADER tag must be the first item (at offset zero) */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, + buffer_size)) != 0) { + rc = EFAULT; + goto fail1; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail2; + } + + if ((rc = tlv_advance(&cursor)) != 0) { + rc = EINVAL; + goto fail3; + } + *startp = byte_offset(cursor.current, cursor.block); + + if ((rc = tlv_require_end(&cursor)) != 0) + goto fail4; + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_find_end( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __in uint32_t offset, + __out uint32_t *endp) +{ + // Read to end of partition + tlv_cursor_t cursor; + efx_rc_t rc; + + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, + buffer_size)) != 0) { + rc = EFAULT; + goto fail1; + } + + if ((rc = tlv_require_end(&cursor)) != 0) + goto fail2; + + *endp = byte_offset(tlv_last_segment_end(&cursor)+1, cursor.block); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn __success(return != B_FALSE) boolean_t +ef10_nvram_buffer_find_item( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __in uint32_t offset, + __out uint32_t *startp, + __out uint32_t *lengthp) +{ + // Find TLV at offset and return key start and length + tlv_cursor_t cursor; + uint8_t *key; + uint32_t tag; + + if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, + buffer_size, offset) != 0) { + return (B_FALSE); + } + + while ((key = tlv_item(&cursor)) != NULL) { + tag = tlv_tag(&cursor); + if (tag == TLV_TAG_PARTITION_HEADER || + tag == TLV_TAG_PARTITION_TRAILER) { + if (tlv_advance(&cursor) != 0) { + break; + } + continue; + } + *startp = byte_offset(cursor.current, cursor.block); + *lengthp = byte_offset(tlv_next_item_ptr(&cursor), + cursor.current); + return (B_TRUE); + } + + return (B_FALSE); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_get_item( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __in uint32_t offset, + __in uint32_t length, + __out_bcount_part(item_max_size, *lengthp) + caddr_t itemp, + __in size_t item_max_size, + __out uint32_t *lengthp) +{ + efx_rc_t rc; + tlv_cursor_t cursor; + uint32_t item_length; + + if (item_max_size < length) { + rc = ENOSPC; + goto fail1; + } + + if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, + buffer_size, offset)) != 0) { + goto fail2; + } + + item_length = tlv_length(&cursor); + if (length < item_length) { + rc = ENOSPC; + goto fail3; + } + memcpy(itemp, tlv_value(&cursor), item_length); + + *lengthp = item_length; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_insert_item( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __in uint32_t offset, + __in_bcount(length) caddr_t keyp, + __in uint32_t length, + __out uint32_t *lengthp) +{ + efx_rc_t rc; + tlv_cursor_t cursor; + + if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, + buffer_size, offset)) != 0) { + goto fail1; + } + + rc = tlv_insert(&cursor, TLV_TAG_LICENSE, keyp, length); + + if (rc != 0) { + goto fail2; + } + + *lengthp = byte_offset(tlv_next_item_ptr(&cursor), + cursor.current); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_delete_item( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size, + __in uint32_t offset, + __in uint32_t length, + __in uint32_t end) +{ + efx_rc_t rc; + tlv_cursor_t cursor; + + if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, + buffer_size, offset)) != 0) { + goto fail1; + } + + if ((rc = tlv_delete(&cursor)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_buffer_finish( + __in_bcount(buffer_size) + caddr_t bufferp, + __in size_t buffer_size) +{ + efx_rc_t rc; + tlv_cursor_t cursor; + + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, + buffer_size)) != 0) { + rc = EFAULT; + goto fail1; + } + + if ((rc = tlv_require_end(&cursor)) != 0) + goto fail2; + + if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) + goto fail3; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + + +/* + * Read and validate a segment from a partition. A segment is a complete + * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may + * be multiple segments in a partition, so seg_offset allows segments + * beyond the first to be read. + */ +static __checkReturn efx_rc_t +ef10_nvram_read_tlv_segment( + __in efx_nic_t *enp, + __in uint32_t partn, + __in size_t seg_offset, + __in_bcount(max_seg_size) caddr_t seg_data, + __in size_t max_seg_size) +{ + tlv_cursor_t cursor; + struct tlv_partition_header *header; + struct tlv_partition_trailer *trailer; + size_t total_length; + uint32_t cksum; + int pos; + efx_rc_t rc; + + EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); + + if ((seg_data == NULL) || (max_seg_size == 0)) { + rc = EINVAL; + goto fail1; + } + + /* Read initial chunk of the segment, starting at offset */ + if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, + EF10_NVRAM_CHUNK, + MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { + goto fail2; + } + + /* A PARTITION_HEADER tag must be the first item at the given offset */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, + max_seg_size)) != 0) { + rc = EFAULT; + goto fail3; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail4; + } + header = (struct tlv_partition_header *)tlv_item(&cursor); + + /* Check TLV segment length (includes the END tag) */ + total_length = __LE_TO_CPU_32(header->total_length); + if (total_length > max_seg_size) { + rc = EFBIG; + goto fail5; + } + + /* Read the remaining segment content */ + if (total_length > EF10_NVRAM_CHUNK) { + if ((rc = ef10_nvram_partn_read_mode(enp, partn, + seg_offset + EF10_NVRAM_CHUNK, + seg_data + EF10_NVRAM_CHUNK, + total_length - EF10_NVRAM_CHUNK, + MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) + goto fail6; + } + + /* Check segment ends with PARTITION_TRAILER and END tags */ + if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { + rc = EINVAL; + goto fail7; + } + trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); + + if ((rc = tlv_advance(&cursor)) != 0) { + rc = EINVAL; + goto fail8; + } + if (tlv_tag(&cursor) != TLV_TAG_END) { + rc = EINVAL; + goto fail9; + } + + /* Check data read from segment is consistent */ + if (trailer->generation != header->generation) { + /* + * The partition data may have been modified between successive + * MCDI NVRAM_READ requests by the MC or another PCI function. + * + * The caller must retry to obtain consistent partition data. + */ + rc = EAGAIN; + goto fail10; + } + + /* Verify segment checksum */ + cksum = 0; + for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { + cksum += *((uint32_t *)(seg_data + pos)); + } + if (cksum != 0) { + rc = EINVAL; + goto fail11; + } + + return (0); + +fail11: + EFSYS_PROBE(fail11); +fail10: + EFSYS_PROBE(fail10); +fail9: + EFSYS_PROBE(fail9); +fail8: + EFSYS_PROBE(fail8); +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * Read a single TLV item from a host memory + * buffer containing a TLV formatted segment. + */ + __checkReturn efx_rc_t +ef10_nvram_buf_read_tlv( + __in efx_nic_t *enp, + __in_bcount(max_seg_size) caddr_t seg_data, + __in size_t max_seg_size, + __in uint32_t tag, + __deref_out_bcount_opt(*sizep) caddr_t *datap, + __out size_t *sizep) +{ + tlv_cursor_t cursor; + caddr_t data; + size_t length; + caddr_t value; + efx_rc_t rc; + + if ((seg_data == NULL) || (max_seg_size == 0)) { + rc = EINVAL; + goto fail1; + } + + /* Find requested TLV tag in segment data */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, + max_seg_size)) != 0) { + rc = EFAULT; + goto fail2; + } + if ((rc = tlv_find(&cursor, tag)) != 0) { + rc = ENOENT; + goto fail3; + } + value = (caddr_t)tlv_value(&cursor); + length = tlv_length(&cursor); + + if (length == 0) + data = NULL; + else { + /* Copy out data from TLV item */ + EFSYS_KMEM_ALLOC(enp->en_esip, length, data); + if (data == NULL) { + rc = ENOMEM; + goto fail4; + } + memcpy(data, value, length); + } + + *datap = data; + *sizep = length; + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* Read a single TLV item from the first segment in a TLV formatted partition */ + __checkReturn efx_rc_t +ef10_nvram_partn_read_tlv( + __in efx_nic_t *enp, + __in uint32_t partn, + __in uint32_t tag, + __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, + __out size_t *seg_sizep) +{ + caddr_t seg_data = NULL; + size_t partn_size = 0; + size_t length; + caddr_t data; + int retry; + efx_rc_t rc; + + /* Allocate sufficient memory for the entire partition */ + if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) + goto fail1; + + if (partn_size == 0) { + rc = ENOENT; + goto fail2; + } + + EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); + if (seg_data == NULL) { + rc = ENOMEM; + goto fail3; + } + + /* + * Read the first segment in a TLV partition. Retry until consistent + * segment contents are returned. Inconsistent data may be read if: + * a) the segment contents are invalid + * b) the MC has rebooted while we were reading the partition + * c) the partition has been modified while we were reading it + * Limit retry attempts to ensure forward progress. + */ + retry = 10; + do { + rc = ef10_nvram_read_tlv_segment(enp, partn, 0, + seg_data, partn_size); + } while ((rc == EAGAIN) && (--retry > 0)); + + if (rc != 0) { + /* Failed to obtain consistent segment data */ + goto fail4; + } + + if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, + tag, &data, &length)) != 0) + goto fail5; + + EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); + + *seg_datap = data; + *seg_sizep = length; + + return (0); + +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); + + EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* Compute the size of a segment. */ + static __checkReturn efx_rc_t +ef10_nvram_buf_segment_size( + __in caddr_t seg_data, + __in size_t max_seg_size, + __out size_t *seg_sizep) +{ + efx_rc_t rc; + tlv_cursor_t cursor; + struct tlv_partition_header *header; + uint32_t cksum; + int pos; + uint32_t *end_tag_position; + uint32_t segment_length; + + /* A PARTITION_HEADER tag must be the first item at the given offset */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, + max_seg_size)) != 0) { + rc = EFAULT; + goto fail1; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail2; + } + header = (struct tlv_partition_header *)tlv_item(&cursor); + + /* Check TLV segment length (includes the END tag) */ + *seg_sizep = __LE_TO_CPU_32(header->total_length); + if (*seg_sizep > max_seg_size) { + rc = EFBIG; + goto fail3; + } + + /* Check segment ends with PARTITION_TRAILER and END tags */ + if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { + rc = EINVAL; + goto fail4; + } + + if ((rc = tlv_advance(&cursor)) != 0) { + rc = EINVAL; + goto fail5; + } + if (tlv_tag(&cursor) != TLV_TAG_END) { + rc = EINVAL; + goto fail6; + } + end_tag_position = cursor.current; + + /* Verify segment checksum */ + cksum = 0; + for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { + cksum += *((uint32_t *)(seg_data + pos)); + } + if (cksum != 0) { + rc = EINVAL; + goto fail7; + } + + /* + * Calculate total length from HEADER to END tags and compare to + * max_seg_size and the total_length field in the HEADER tag. + */ + segment_length = tlv_block_length_used(&cursor); + + if (segment_length > max_seg_size) { + rc = EINVAL; + goto fail8; + } + + if (segment_length != *seg_sizep) { + rc = EINVAL; + goto fail9; + } + + /* Skip over the first HEADER tag. */ + rc = tlv_rewind(&cursor); + rc = tlv_advance(&cursor); + + while (rc == 0) { + if (tlv_tag(&cursor) == TLV_TAG_END) { + /* Check that the END tag is the one found earlier. */ + if (cursor.current != end_tag_position) + goto fail10; + break; + } + /* Check for duplicate HEADER tags before the END tag. */ + if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail11; + } + + rc = tlv_advance(&cursor); + } + if (rc != 0) + goto fail12; + + return (0); + +fail12: + EFSYS_PROBE(fail12); +fail11: + EFSYS_PROBE(fail11); +fail10: + EFSYS_PROBE(fail10); +fail9: + EFSYS_PROBE(fail9); +fail8: + EFSYS_PROBE(fail8); +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * Add or update a single TLV item in a host memory buffer containing a TLV + * formatted segment. Historically partitions consisted of only one segment. + */ + __checkReturn efx_rc_t +ef10_nvram_buf_write_tlv( + __inout_bcount(max_seg_size) caddr_t seg_data, + __in size_t max_seg_size, + __in uint32_t tag, + __in_bcount(tag_size) caddr_t tag_data, + __in size_t tag_size, + __out size_t *total_lengthp) +{ + tlv_cursor_t cursor; + struct tlv_partition_header *header; + struct tlv_partition_trailer *trailer; + uint32_t generation; + uint32_t cksum; + int pos; + efx_rc_t rc; + + /* A PARTITION_HEADER tag must be the first item (at offset zero) */ + if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, + max_seg_size)) != 0) { + rc = EFAULT; + goto fail1; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail2; + } + header = (struct tlv_partition_header *)tlv_item(&cursor); + + /* Update the TLV chain to contain the new data */ + if ((rc = tlv_find(&cursor, tag)) == 0) { + /* Modify existing TLV item */ + if ((rc = tlv_modify(&cursor, tag, + (uint8_t *)tag_data, tag_size)) != 0) + goto fail3; + } else { + /* Insert a new TLV item before the PARTITION_TRAILER */ + rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); + if (rc != 0) { + rc = EINVAL; + goto fail4; + } + if ((rc = tlv_insert(&cursor, tag, + (uint8_t *)tag_data, tag_size)) != 0) { + rc = EINVAL; + goto fail5; + } + } + + /* Find the trailer tag */ + if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { + rc = EINVAL; + goto fail6; + } + trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); + + /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ + *total_lengthp = tlv_block_length_used(&cursor); + if (*total_lengthp > max_seg_size) { + rc = ENOSPC; + goto fail7; + } + generation = __LE_TO_CPU_32(header->generation) + 1; + + header->total_length = __CPU_TO_LE_32(*total_lengthp); + header->generation = __CPU_TO_LE_32(generation); + trailer->generation = __CPU_TO_LE_32(generation); + + /* Recompute PARTITION_TRAILER checksum */ + trailer->checksum = 0; + cksum = 0; + for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { + cksum += *((uint32_t *)(seg_data + pos)); + } + trailer->checksum = ~cksum + 1; + + return (0); + +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * Add or update a single TLV item in the first segment of a TLV formatted + * dynamic config partition. The first segment is the current active + * configuration. + */ + __checkReturn efx_rc_t +ef10_nvram_partn_write_tlv( + __in efx_nic_t *enp, + __in uint32_t partn, + __in uint32_t tag, + __in_bcount(size) caddr_t data, + __in size_t size) +{ + return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, + size, B_FALSE); +} + +/* + * Read a segment from nvram at the given offset into a buffer (segment_data) + * and optionally write a new tag to it. + */ + static __checkReturn efx_rc_t +ef10_nvram_segment_write_tlv( + __in efx_nic_t *enp, + __in uint32_t partn, + __in uint32_t tag, + __in_bcount(size) caddr_t data, + __in size_t size, + __inout caddr_t *seg_datap, + __inout size_t *partn_offsetp, + __inout size_t *src_remain_lenp, + __inout size_t *dest_remain_lenp, + __in boolean_t write) +{ + efx_rc_t rc; + efx_rc_t status; + size_t original_segment_size; + size_t modified_segment_size; + + /* + * Read the segment from NVRAM into the segment_data buffer and validate + * it, returning if it does not validate. This is not a failure unless + * this is the first segment in a partition. In this case the caller + * must propagate the error. + */ + status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, + *seg_datap, *src_remain_lenp); + if (status != 0) + return (EINVAL); + + status = ef10_nvram_buf_segment_size(*seg_datap, + *src_remain_lenp, &original_segment_size); + if (status != 0) + return (EINVAL); + + if (write) { + /* Update the contents of the segment in the buffer */ + if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, + *dest_remain_lenp, tag, data, size, + &modified_segment_size)) != 0) + goto fail1; + *dest_remain_lenp -= modified_segment_size; + *seg_datap += modified_segment_size; + } else { + /* + * We won't modify this segment, but still need to update the + * remaining lengths and pointers. + */ + *dest_remain_lenp -= original_segment_size; + *seg_datap += original_segment_size; + } + + *partn_offsetp += original_segment_size; + *src_remain_lenp -= original_segment_size; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * Add or update a single TLV item in either the first segment or in all + * segments in a TLV formatted dynamic config partition. Dynamic config + * partitions on boards that support RFID are divided into a number of segments, + * each formatted like a partition, with header, trailer and end tags. The first + * segment is the current active configuration. + * + * The segments are initialised by manftest and each contain a different + * configuration e.g. firmware variant. The firmware can be instructed + * via RFID to copy a segment to replace the first segment, hence changing the + * active configuration. This allows ops to change the configuration of a board + * prior to shipment using RFID. + * + * Changes to the dynamic config may need to be written to all segments (e.g. + * firmware versions) or just the first segment (changes to the active + * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". + * If only the first segment is written the code still needs to be aware of the + * possible presence of subsequent segments as writing to a segment may cause + * its size to increase, which would overwrite the subsequent segments and + * invalidate them. + */ + __checkReturn efx_rc_t +ef10_nvram_partn_write_segment_tlv( + __in efx_nic_t *enp, + __in uint32_t partn, + __in uint32_t tag, + __in_bcount(size) caddr_t data, + __in size_t size, + __in boolean_t all_segments) +{ + size_t partn_size = 0; + caddr_t partn_data; + size_t total_length = 0; + efx_rc_t rc; + size_t current_offset = 0; + size_t remaining_original_length; + size_t remaining_modified_length; + caddr_t segment_data; + + EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); + + /* Allocate sufficient memory for the entire partition */ + if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) + goto fail1; + + EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); + if (partn_data == NULL) { + rc = ENOMEM; + goto fail2; + } + + remaining_original_length = partn_size; + remaining_modified_length = partn_size; + segment_data = partn_data; + + /* Lock the partition */ + if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) + goto fail3; + + /* Iterate over each (potential) segment to update it. */ + do { + boolean_t write = all_segments || current_offset == 0; + + rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, + &segment_data, ¤t_offset, &remaining_original_length, + &remaining_modified_length, write); + if (rc != 0) { + if (current_offset == 0) { + /* + * If no data has been read then the first + * segment is invalid, which is an error. + */ + goto fail4; + } + break; + } + } while (current_offset < partn_size); + + total_length = segment_data - partn_data; + + /* + * We've run out of space. This should actually be dealt with by + * ef10_nvram_buf_write_tlv returning ENOSPC. + */ + if (total_length > partn_size) { + rc = ENOSPC; + goto fail5; + } + + /* Erase the whole partition in NVRAM */ + if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) + goto fail6; + + /* Write new partition contents from the buffer to NVRAM */ + if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, + total_length)) != 0) + goto fail7; + + /* Unlock the partition */ + ef10_nvram_partn_unlock(enp, partn); + + EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); + + return (0); + +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); + + ef10_nvram_partn_unlock(enp, partn); +fail3: + EFSYS_PROBE(fail3); + + EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * Get the size of a NVRAM partition. This is the total size allocated in nvram, + * not the data used by the segments in the partition. + */ + __checkReturn efx_rc_t +ef10_nvram_partn_size( + __in efx_nic_t *enp, + __in uint32_t partn, + __out size_t *sizep) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, + NULL, NULL, NULL)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_lock( + __in efx_nic_t *enp, + __in uint32_t partn) +{ + efx_rc_t rc; + + if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_read_mode( + __in efx_nic_t *enp, + __in uint32_t partn, + __in unsigned int offset, + __out_bcount(size) caddr_t data, + __in size_t size, + __in uint32_t mode) +{ + size_t chunk; + efx_rc_t rc; + + while (size > 0) { + chunk = MIN(size, EF10_NVRAM_CHUNK); + + if ((rc = efx_mcdi_nvram_read(enp, partn, offset, + data, chunk, mode)) != 0) { + goto fail1; + } + + size -= chunk; + data += chunk; + offset += chunk; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_read( + __in efx_nic_t *enp, + __in uint32_t partn, + __in unsigned int offset, + __out_bcount(size) caddr_t data, + __in size_t size) +{ + /* + * Read requests which come in through the EFX API expect to + * read the current, active partition. + */ + return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, + MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_erase( + __in efx_nic_t *enp, + __in uint32_t partn, + __in unsigned int offset, + __in size_t size) +{ + efx_rc_t rc; + uint32_t erase_size; + + if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, + &erase_size, NULL)) != 0) + goto fail1; + + if (erase_size == 0) { + if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) + goto fail2; + } else { + if (size % erase_size != 0) { + rc = EINVAL; + goto fail3; + } + while (size > 0) { + if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, + erase_size)) != 0) + goto fail4; + offset += erase_size; + size -= erase_size; + } + } + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_write( + __in efx_nic_t *enp, + __in uint32_t partn, + __in unsigned int offset, + __out_bcount(size) caddr_t data, + __in size_t size) +{ + size_t chunk; + uint32_t write_size; + efx_rc_t rc; + + if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, + NULL, &write_size)) != 0) + goto fail1; + + if (write_size != 0) { + /* + * Check that the size is a multiple of the write chunk size if + * the write chunk size is available. + */ + if (size % write_size != 0) { + rc = EINVAL; + goto fail2; + } + } else { + write_size = EF10_NVRAM_CHUNK; + } + + while (size > 0) { + chunk = MIN(size, write_size); + + if ((rc = efx_mcdi_nvram_write(enp, partn, offset, + data, chunk)) != 0) { + goto fail3; + } + + size -= chunk; + data += chunk; + offset += chunk; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_nvram_partn_unlock( + __in efx_nic_t *enp, + __in uint32_t partn) +{ + boolean_t reboot; + efx_rc_t rc; + + reboot = B_FALSE; + if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) + goto fail1; + + return; + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_set_version( + __in efx_nic_t *enp, + __in uint32_t partn, + __in_ecount(4) uint16_t version[4]) +{ + struct tlv_partition_version partn_version; + size_t size; + efx_rc_t rc; + + /* Add or modify partition version TLV item */ + partn_version.version_w = __CPU_TO_LE_16(version[0]); + partn_version.version_x = __CPU_TO_LE_16(version[1]); + partn_version.version_y = __CPU_TO_LE_16(version[2]); + partn_version.version_z = __CPU_TO_LE_16(version[3]); + + size = sizeof (partn_version) - (2 * sizeof (uint32_t)); + + /* Write the version number to all segments in the partition */ + if ((rc = ef10_nvram_partn_write_segment_tlv(enp, + NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, + TLV_TAG_PARTITION_VERSION(partn), + (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ + +#if EFSYS_OPT_NVRAM + +typedef struct ef10_parttbl_entry_s { + unsigned int partn; + unsigned int port; + efx_nvram_type_t nvtype; +} ef10_parttbl_entry_t; + +/* Translate EFX NVRAM types to firmware partition types */ +static ef10_parttbl_entry_t hunt_parttbl[] = { + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} +}; + +static ef10_parttbl_entry_t medford_parttbl[] = { + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, + {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, + {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, + {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} +}; + +static __checkReturn efx_rc_t +ef10_parttbl_get( + __in efx_nic_t *enp, + __out ef10_parttbl_entry_t **parttblp, + __out size_t *parttbl_rowsp) +{ + switch (enp->en_family) { + case EFX_FAMILY_HUNTINGTON: + *parttblp = hunt_parttbl; + *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); + break; + + case EFX_FAMILY_MEDFORD: + *parttblp = medford_parttbl; + *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); + break; + + default: + EFSYS_ASSERT(B_FALSE); + return (EINVAL); + } + return (0); +} + + __checkReturn efx_rc_t +ef10_nvram_type_to_partn( + __in efx_nic_t *enp, + __in efx_nvram_type_t type, + __out uint32_t *partnp) +{ + efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); + ef10_parttbl_entry_t *parttbl = NULL; + size_t parttbl_rows = 0; + unsigned int i; + + EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); + EFSYS_ASSERT(partnp != NULL); + + if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { + for (i = 0; i < parttbl_rows; i++) { + ef10_parttbl_entry_t *entry = &parttbl[i]; + + if (entry->nvtype == type && + entry->port == emip->emi_port) { + *partnp = entry->partn; + return (0); + } + } + } + + return (ENOTSUP); +} + +#if EFSYS_OPT_DIAG + +static __checkReturn efx_rc_t +ef10_nvram_partn_to_type( + __in efx_nic_t *enp, + __in uint32_t partn, + __out efx_nvram_type_t *typep) +{ + efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); + ef10_parttbl_entry_t *parttbl = NULL; + size_t parttbl_rows = 0; + unsigned int i; + + EFSYS_ASSERT(typep != NULL); + + if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { + for (i = 0; i < parttbl_rows; i++) { + ef10_parttbl_entry_t *entry = &parttbl[i]; + + if (entry->partn == partn && + entry->port == emip->emi_port) { + *typep = entry->nvtype; + return (0); + } + } + } + + return (ENOTSUP); +} + + __checkReturn efx_rc_t +ef10_nvram_test( + __in efx_nic_t *enp) +{ + efx_nvram_type_t type; + unsigned int npartns = 0; + uint32_t *partns = NULL; + size_t size; + unsigned int i; + efx_rc_t rc; + + /* Read available partitions from NVRAM partition map */ + size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); + EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); + if (partns == NULL) { + rc = ENOMEM; + goto fail1; + } + + if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, + &npartns)) != 0) { + goto fail2; + } + + for (i = 0; i < npartns; i++) { + /* Check if the partition is supported for this port */ + if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) + continue; + + if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) + goto fail3; + } + + EFSYS_KMEM_FREE(enp->en_esip, size, partns); + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); + EFSYS_KMEM_FREE(enp->en_esip, size, partns); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + return (rc); +} + +#endif /* EFSYS_OPT_DIAG */ + + __checkReturn efx_rc_t +ef10_nvram_partn_get_version( + __in efx_nic_t *enp, + __in uint32_t partn, + __out uint32_t *subtypep, + __out_ecount(4) uint16_t version[4]) +{ + efx_rc_t rc; + + /* FIXME: get highest partn version from all ports */ + /* FIXME: return partn description if available */ + + if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, + version, NULL, 0)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_nvram_partn_rw_start( + __in efx_nic_t *enp, + __in uint32_t partn, + __out size_t *chunk_sizep) +{ + efx_rc_t rc; + + if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) + goto fail1; + + if (chunk_sizep != NULL) + *chunk_sizep = EF10_NVRAM_CHUNK; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_nvram_partn_rw_finish( + __in efx_nic_t *enp, + __in uint32_t partn) +{ + ef10_nvram_partn_unlock(enp, partn); +} + +#endif /* EFSYS_OPT_NVRAM */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_nvram.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_phy.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_phy.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_phy.c (revision 301344) @@ -0,0 +1,518 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +static void +mcdi_phy_decode_cap( + __in uint32_t mcdi_cap, + __out uint32_t *maskp) +{ + uint32_t mask; + + mask = 0; + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_100HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_100FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) + mask |= (1 << EFX_PHY_CAP_1000HDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_1000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_10000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) + mask |= (1 << EFX_PHY_CAP_40000FDX); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) + mask |= (1 << EFX_PHY_CAP_PAUSE); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + mask |= (1 << EFX_PHY_CAP_ASYM); + if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) + mask |= (1 << EFX_PHY_CAP_AN); + + *maskp = mask; +} + +static void +mcdi_phy_decode_link_mode( + __in efx_nic_t *enp, + __in uint32_t link_flags, + __in unsigned int speed, + __in unsigned int fcntl, + __out efx_link_mode_t *link_modep, + __out unsigned int *fcntlp) +{ + boolean_t fd = !!(link_flags & + (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); + boolean_t up = !!(link_flags & + (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); + + _NOTE(ARGUNUSED(enp)) + + if (!up) + *link_modep = EFX_LINK_DOWN; + else if (speed == 40000 && fd) + *link_modep = EFX_LINK_40000FDX; + else if (speed == 10000 && fd) + *link_modep = EFX_LINK_10000FDX; + else if (speed == 1000) + *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; + else if (speed == 100) + *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; + else if (speed == 10) + *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; + else + *link_modep = EFX_LINK_UNKNOWN; + + if (fcntl == MC_CMD_FCNTL_OFF) + *fcntlp = 0; + else if (fcntl == MC_CMD_FCNTL_RESPOND) + *fcntlp = EFX_FCNTL_RESPOND; + else if (fcntl == MC_CMD_FCNTL_GENERATE) + *fcntlp = EFX_FCNTL_GENERATE; + else if (fcntl == MC_CMD_FCNTL_BIDIR) + *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; + else { + EFSYS_PROBE1(mc_pcol_error, int, fcntl); + *fcntlp = 0; + } +} + + + void +ef10_phy_link_ev( + __in efx_nic_t *enp, + __in efx_qword_t *eqp, + __out efx_link_mode_t *link_modep) +{ + efx_port_t *epp = &(enp->en_port); + unsigned int link_flags; + unsigned int speed; + unsigned int fcntl; + efx_link_mode_t link_mode; + uint32_t lp_cap_mask; + + /* + * Convert the LINKCHANGE speed enumeration into mbit/s, in the + * same way as GET_LINK encodes the speed + */ + switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { + case MCDI_EVENT_LINKCHANGE_SPEED_100M: + speed = 100; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_1G: + speed = 1000; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_10G: + speed = 10000; + break; + case MCDI_EVENT_LINKCHANGE_SPEED_40G: + speed = 40000; + break; + default: + speed = 0; + break; + } + + link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); + mcdi_phy_decode_link_mode(enp, link_flags, speed, + MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), + &link_mode, &fcntl); + mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), + &lp_cap_mask); + + /* + * It's safe to update ep_lp_cap_mask without the driver's port lock + * because presumably any concurrently running efx_port_poll() is + * only going to arrive at the same value. + * + * ep_fcntl has two meanings. It's either the link common fcntl + * (if the PHY supports AN), or it's the forced link state. If + * the former, it's safe to update the value for the same reason as + * for ep_lp_cap_mask. If the latter, then just ignore the value, + * because we can race with efx_mac_fcntl_set(). + */ + epp->ep_lp_cap_mask = lp_cap_mask; + epp->ep_fcntl = fcntl; + + *link_modep = link_mode; +} + + __checkReturn efx_rc_t +ef10_phy_power( + __in efx_nic_t *enp, + __in boolean_t power) +{ + efx_rc_t rc; + + if (!power) + return (0); + + /* Check if the PHY is a zombie */ + if ((rc = ef10_phy_verify(enp)) != 0) + goto fail1; + + enp->en_reset_flags |= EFX_RESET_PHY; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_get_link( + __in efx_nic_t *enp, + __out ef10_link_state_t *elsp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, + MC_CMD_GET_LINK_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_LINK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), + &elsp->els_adv_cap_mask); + mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), + &elsp->els_lp_cap_mask); + + mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), + MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), + MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), + &elsp->els_link_mode, &elsp->els_fcntl); + +#if EFSYS_OPT_LOOPBACK + /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); + EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); + + elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); +#endif /* EFSYS_OPT_LOOPBACK */ + + elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_reconfigure( + __in efx_nic_t *enp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_port_t *epp = &(enp->en_port); + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, + MC_CMD_SET_LINK_OUT_LEN)]; + uint32_t cap_mask; + unsigned int led_mode; + unsigned int speed; + efx_rc_t rc; + + if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL) + goto out; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_LINK; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; + + cap_mask = epp->ep_adv_cap_mask; + MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, + PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, + PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, + PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, + PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, + PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, + PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, + PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, + PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, + PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, + PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); + /* Too many fields for for POPULATE macros, so insert this afterwards */ + MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, + PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1); + +#if EFSYS_OPT_LOOPBACK + MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, + epp->ep_loopback_type); + switch (epp->ep_loopback_link_mode) { + case EFX_LINK_100FDX: + speed = 100; + break; + case EFX_LINK_1000FDX: + speed = 1000; + break; + case EFX_LINK_10000FDX: + speed = 10000; + break; + case EFX_LINK_40000FDX: + speed = 40000; + break; + default: + speed = 0; + } +#else + MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); + speed = 0; +#endif /* EFSYS_OPT_LOOPBACK */ + MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); + +#if EFSYS_OPT_PHY_FLAGS + MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); +#else + MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); +#endif /* EFSYS_OPT_PHY_FLAGS */ + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + /* And set the blink mode */ + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_SET_ID_LED; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; + +#if EFSYS_OPT_PHY_LED_CONTROL + switch (epp->ep_phy_led_mode) { + case EFX_PHY_LED_DEFAULT: + led_mode = MC_CMD_LED_DEFAULT; + break; + case EFX_PHY_LED_OFF: + led_mode = MC_CMD_LED_OFF; + break; + case EFX_PHY_LED_ON: + led_mode = MC_CMD_LED_ON; + break; + default: + EFSYS_ASSERT(0); + led_mode = MC_CMD_LED_DEFAULT; + } + + MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); +#else + MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); +#endif /* EFSYS_OPT_PHY_LED_CONTROL */ + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } +out: + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_verify( + __in efx_nic_t *enp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, + MC_CMD_GET_PHY_STATE_OUT_LEN)]; + uint32_t state; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_GET_PHY_STATE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { + rc = EMSGSIZE; + goto fail2; + } + + state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); + if (state != MC_CMD_PHY_STATE_OK) { + if (state != MC_CMD_PHY_STATE_ZOMBIE) + EFSYS_PROBE1(mc_pcol_error, int, state); + rc = ENOTACTIVE; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_phy_oui_get( + __in efx_nic_t *enp, + __out uint32_t *ouip) +{ + _NOTE(ARGUNUSED(enp, ouip)) + + return (ENOTSUP); +} + +#if EFSYS_OPT_PHY_STATS + + __checkReturn efx_rc_t +ef10_phy_stats_update( + __in efx_nic_t *enp, + __in efsys_mem_t *esmp, + __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) +{ + /* TBD: no stats support in firmware yet */ + _NOTE(ARGUNUSED(enp, esmp)) + memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); + + return (0); +} + +#endif /* EFSYS_OPT_PHY_STATS */ + +#if EFSYS_OPT_PHY_PROPS + +#if EFSYS_OPT_NAMES + + const char * +ef10_phy_prop_name( + __in efx_nic_t *enp, + __in unsigned int id) +{ + _NOTE(ARGUNUSED(enp, id)) + + return (NULL); +} + +#endif /* EFSYS_OPT_NAMES */ + + __checkReturn efx_rc_t +ef10_phy_prop_get( + __in efx_nic_t *enp, + __in unsigned int id, + __in uint32_t flags, + __out uint32_t *valp) +{ + _NOTE(ARGUNUSED(enp, id, flags, valp)) + + return (ENOTSUP); +} + + __checkReturn efx_rc_t +ef10_phy_prop_set( + __in efx_nic_t *enp, + __in unsigned int id, + __in uint32_t val) +{ + _NOTE(ARGUNUSED(enp, id, val)) + + return (ENOTSUP); +} + +#endif /* EFSYS_OPT_PHY_PROPS */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_phy.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_rx.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_rx.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_rx.c (revision 301344) @@ -0,0 +1,826 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + + +static __checkReturn efx_rc_t +efx_mcdi_init_rxq( + __in efx_nic_t *enp, + __in uint32_t size, + __in uint32_t target_evq, + __in uint32_t label, + __in uint32_t instance, + __in efsys_mem_t *esmp, + __in boolean_t disable_scatter) +{ + efx_mcdi_req_t req; + uint8_t payload[ + MAX(MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS)), + MC_CMD_INIT_RXQ_OUT_LEN)]; + int npages = EFX_RXQ_NBUFS(size); + int i; + efx_qword_t *dma_addr; + uint64_t addr; + efx_rc_t rc; + + EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS); + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_INIT_RXQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages); + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size); + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq); + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label); + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance); + MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS, + INIT_RXQ_IN_FLAG_BUFF_MODE, 0, + INIT_RXQ_IN_FLAG_HDR_SPLIT, 0, + INIT_RXQ_IN_FLAG_TIMESTAMP, 0, + INIT_RXQ_IN_CRC_MODE, 0, + INIT_RXQ_IN_FLAG_PREFIX, 1, + INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter); + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0); + MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + + dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); + addr = EFSYS_MEM_ADDR(esmp); + + for (i = 0; i < npages; i++) { + EFX_POPULATE_QWORD_2(*dma_addr, + EFX_DWORD_1, (uint32_t)(addr >> 32), + EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); + + dma_addr++; + addr += EFX_BUF_SIZE; + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_fini_rxq( + __in efx_nic_t *enp, + __in uint32_t instance) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FINI_RXQ_IN_LEN, + MC_CMD_FINI_RXQ_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FINI_RXQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance); + + efx_mcdi_execute(enp, &req); + + if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +#if EFSYS_OPT_RX_SCALE +static __checkReturn efx_rc_t +efx_mcdi_rss_context_alloc( + __in efx_nic_t *enp, + __in efx_rx_scale_support_t scale_support, + __in uint32_t num_queues, + __out uint32_t *rss_contextp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN, + MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN)]; + uint32_t rss_context; + uint32_t context_type; + efx_rc_t rc; + + if (num_queues > EFX_MAXRSS) { + rc = EINVAL; + goto fail1; + } + + switch (scale_support) { + case EFX_RX_SCALE_EXCLUSIVE: + context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE; + break; + case EFX_RX_SCALE_SHARED: + context_type = MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED; + break; + default: + rc = EINVAL; + goto fail2; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_RSS_CONTEXT_ALLOC; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN; + + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, + EVB_PORT_ID_ASSIGNED); + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_TYPE, context_type); + /* NUM_QUEUES is only used to validate indirection table offsets */ + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, num_queues); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + if (req.emr_out_length_used < MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN) { + rc = EMSGSIZE; + goto fail4; + } + + rss_context = MCDI_OUT_DWORD(req, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); + if (rss_context == EF10_RSS_CONTEXT_INVALID) { + rc = ENOENT; + goto fail5; + } + + *rss_contextp = rss_context; + + return (0); + +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE +static efx_rc_t +efx_mcdi_rss_context_free( + __in efx_nic_t *enp, + __in uint32_t rss_context) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_FREE_IN_LEN, + MC_CMD_RSS_CONTEXT_FREE_OUT_LEN)]; + efx_rc_t rc; + + if (rss_context == EF10_RSS_CONTEXT_INVALID) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_RSS_CONTEXT_FREE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_RSS_CONTEXT_FREE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_RSS_CONTEXT_FREE_OUT_LEN; + + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_FREE_IN_RSS_CONTEXT_ID, rss_context); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE +static efx_rc_t +efx_mcdi_rss_context_set_flags( + __in efx_nic_t *enp, + __in uint32_t rss_context, + __in efx_rx_hash_type_t type) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN, + MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN)]; + efx_rc_t rc; + + if (rss_context == EF10_RSS_CONTEXT_INVALID) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_FLAGS; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN; + + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID, + rss_context); + + MCDI_IN_POPULATE_DWORD_4(req, RSS_CONTEXT_SET_FLAGS_IN_FLAGS, + RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN, + (type & (1U << EFX_RX_HASH_IPV4)) ? 1 : 0, + RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV4_EN, + (type & (1U << EFX_RX_HASH_TCPIPV4)) ? 1 : 0, + RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN, + (type & (1U << EFX_RX_HASH_IPV6)) ? 1 : 0, + RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN, + (type & (1U << EFX_RX_HASH_TCPIPV6)) ? 1 : 0); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE +static efx_rc_t +efx_mcdi_rss_context_set_key( + __in efx_nic_t *enp, + __in uint32_t rss_context, + __in_ecount(n) uint8_t *key, + __in size_t n) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN, + MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN)]; + efx_rc_t rc; + + if (rss_context == EF10_RSS_CONTEXT_INVALID) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_KEY; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_KEY_OUT_LEN; + + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_KEY_IN_RSS_CONTEXT_ID, + rss_context); + + EFSYS_ASSERT3U(n, ==, MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); + if (n != MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN) { + rc = EINVAL; + goto fail2; + } + + memcpy(MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY), + key, n); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE +static efx_rc_t +efx_mcdi_rss_context_set_table( + __in efx_nic_t *enp, + __in uint32_t rss_context, + __in_ecount(n) unsigned int *table, + __in size_t n) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN, + MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN)]; + uint8_t *req_table; + int i, rc; + + if (rss_context == EF10_RSS_CONTEXT_INVALID) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_RSS_CONTEXT_SET_TABLE; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_RSS_CONTEXT_SET_TABLE_OUT_LEN; + + MCDI_IN_SET_DWORD(req, RSS_CONTEXT_SET_TABLE_IN_RSS_CONTEXT_ID, + rss_context); + + req_table = + MCDI_IN2(req, uint8_t, RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE); + + for (i = 0; + i < MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN; + i++) { + req_table[i] = (n > 0) ? (uint8_t)table[i % n] : 0; + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + + + __checkReturn efx_rc_t +ef10_rx_init( + __in efx_nic_t *enp) +{ +#if EFSYS_OPT_RX_SCALE + + if (efx_mcdi_rss_context_alloc(enp, EFX_RX_SCALE_EXCLUSIVE, EFX_MAXRSS, + &enp->en_rss_context) == 0) { + /* + * Allocated an exclusive RSS context, which allows both the + * indirection table and key to be modified. + */ + enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE; + enp->en_hash_support = EFX_RX_HASH_AVAILABLE; + } else { + /* + * Failed to allocate an exclusive RSS context. Continue + * operation without support for RSS. The pseudo-header in + * received packets will not contain a Toeplitz hash value. + */ + enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; + enp->en_hash_support = EFX_RX_HASH_UNAVAILABLE; + } + +#endif /* EFSYS_OPT_RX_SCALE */ + + return (0); +} + +#if EFSYS_OPT_RX_SCATTER + __checkReturn efx_rc_t +ef10_rx_scatter_enable( + __in efx_nic_t *enp, + __in unsigned int buf_size) +{ + _NOTE(ARGUNUSED(enp, buf_size)) + return (0); +} +#endif /* EFSYS_OPT_RX_SCATTER */ + +#if EFSYS_OPT_RX_SCALE + __checkReturn efx_rc_t +ef10_rx_scale_mode_set( + __in efx_nic_t *enp, + __in efx_rx_hash_alg_t alg, + __in efx_rx_hash_type_t type, + __in boolean_t insert) +{ + efx_rc_t rc; + + EFSYS_ASSERT3U(alg, ==, EFX_RX_HASHALG_TOEPLITZ); + EFSYS_ASSERT3U(insert, ==, B_TRUE); + + if ((alg != EFX_RX_HASHALG_TOEPLITZ) || (insert == B_FALSE)) { + rc = EINVAL; + goto fail1; + } + + if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { + rc = ENOTSUP; + goto fail2; + } + + if ((rc = efx_mcdi_rss_context_set_flags(enp, + enp->en_rss_context, type)) != 0) + goto fail3; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE + __checkReturn efx_rc_t +ef10_rx_scale_key_set( + __in efx_nic_t *enp, + __in_ecount(n) uint8_t *key, + __in size_t n) +{ + efx_rc_t rc; + + if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { + rc = ENOTSUP; + goto fail1; + } + + if ((rc = efx_mcdi_rss_context_set_key(enp, + enp->en_rss_context, key, n)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + +#if EFSYS_OPT_RX_SCALE + __checkReturn efx_rc_t +ef10_rx_scale_tbl_set( + __in efx_nic_t *enp, + __in_ecount(n) unsigned int *table, + __in size_t n) +{ + efx_rc_t rc; + + if (enp->en_rss_support == EFX_RX_SCALE_UNAVAILABLE) { + rc = ENOTSUP; + goto fail1; + } + + if ((rc = efx_mcdi_rss_context_set_table(enp, + enp->en_rss_context, table, n)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} +#endif /* EFSYS_OPT_RX_SCALE */ + + +/* + * EF10 RX pseudo-header + * --------------------- + * + * Receive packets are prefixed by an (optional) 14 byte pseudo-header: + * + * +00: Toeplitz hash value. + * (32bit little-endian) + * +04: Outer VLAN tag. Zero if the packet did not have an outer VLAN tag. + * (16bit big-endian) + * +06: Inner VLAN tag. Zero if the packet did not have an inner VLAN tag. + * (16bit big-endian) + * +08: Packet Length. Zero if the RX datapath was in cut-through mode. + * (16bit little-endian) + * +10: MAC timestamp. Zero if timestamping is not enabled. + * (32bit little-endian) + * + * See "The RX Pseudo-header" in SF-109306-TC. + */ + + __checkReturn efx_rc_t +ef10_rx_prefix_pktlen( + __in efx_nic_t *enp, + __in uint8_t *buffer, + __out uint16_t *lengthp) +{ + /* + * The RX pseudo-header contains the packet length, excluding the + * pseudo-header. If the hardware receive datapath was operating in + * cut-through mode then the length in the RX pseudo-header will be + * zero, and the packet length must be obtained from the DMA length + * reported in the RX event. + */ + *lengthp = buffer[8] | (buffer[9] << 8); + return (0); +} + +#if EFSYS_OPT_RX_SCALE + __checkReturn uint32_t +ef10_rx_prefix_hash( + __in efx_nic_t *enp, + __in efx_rx_hash_alg_t func, + __in uint8_t *buffer) +{ + switch (func) { + case EFX_RX_HASHALG_TOEPLITZ: + return (buffer[0] | + (buffer[1] << 8) | + (buffer[2] << 16) | + (buffer[3] << 24)); + + default: + EFSYS_ASSERT(0); + return (0); + } +} +#endif /* EFSYS_OPT_RX_SCALE */ + + void +ef10_rx_qpost( + __in efx_rxq_t *erp, + __in_ecount(n) efsys_dma_addr_t *addrp, + __in size_t size, + __in unsigned int n, + __in unsigned int completed, + __in unsigned int added) +{ + efx_qword_t qword; + unsigned int i; + unsigned int offset; + unsigned int id; + + /* The client driver must not overfill the queue */ + EFSYS_ASSERT3U(added - completed + n, <=, + EFX_RXQ_LIMIT(erp->er_mask + 1)); + + id = added & (erp->er_mask); + for (i = 0; i < n; i++) { + EFSYS_PROBE4(rx_post, unsigned int, erp->er_index, + unsigned int, id, efsys_dma_addr_t, addrp[i], + size_t, size); + + EFX_POPULATE_QWORD_3(qword, + ESF_DZ_RX_KER_BYTE_CNT, (uint32_t)(size), + ESF_DZ_RX_KER_BUF_ADDR_DW0, + (uint32_t)(addrp[i] & 0xffffffff), + ESF_DZ_RX_KER_BUF_ADDR_DW1, + (uint32_t)(addrp[i] >> 32)); + + offset = id * sizeof (efx_qword_t); + EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword); + + id = (id + 1) & (erp->er_mask); + } +} + + void +ef10_rx_qpush( + __in efx_rxq_t *erp, + __in unsigned int added, + __inout unsigned int *pushedp) +{ + efx_nic_t *enp = erp->er_enp; + unsigned int pushed = *pushedp; + uint32_t wptr; + efx_dword_t dword; + + /* Hardware has alignment restriction for WPTR */ + wptr = P2ALIGN(added, EF10_RX_WPTR_ALIGN); + if (pushed == wptr) + return; + + *pushedp = wptr; + + /* Push the populated descriptors out */ + wptr &= erp->er_mask; + + EFX_POPULATE_DWORD_1(dword, ERF_DZ_RX_DESC_WPTR, wptr); + + /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ + EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1, + wptr, pushed & erp->er_mask); + EFSYS_PIO_WRITE_BARRIER(); + EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG, + erp->er_index, &dword, B_FALSE); +} + + __checkReturn efx_rc_t +ef10_rx_qflush( + __in efx_rxq_t *erp) +{ + efx_nic_t *enp = erp->er_enp; + efx_rc_t rc; + + if ((rc = efx_mcdi_fini_rxq(enp, erp->er_index)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_rx_qenable( + __in efx_rxq_t *erp) +{ + /* FIXME */ + _NOTE(ARGUNUSED(erp)) + /* FIXME */ +} + + __checkReturn efx_rc_t +ef10_rx_qcreate( + __in efx_nic_t *enp, + __in unsigned int index, + __in unsigned int label, + __in efx_rxq_type_t type, + __in efsys_mem_t *esmp, + __in size_t n, + __in uint32_t id, + __in efx_evq_t *eep, + __in efx_rxq_t *erp) +{ + efx_nic_cfg_t *encp = &(enp->en_nic_cfg); + efx_rc_t rc; + boolean_t disable_scatter; + + _NOTE(ARGUNUSED(erp)) + + EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << ESF_DZ_RX_QLABEL_WIDTH)); + EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS); + EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit); + + EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS)); + EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS)); + + if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) { + rc = EINVAL; + goto fail1; + } + if (index >= encp->enc_rxq_limit) { + rc = EINVAL; + goto fail2; + } + + /* Scatter can only be disabled if the firmware supports doing so */ + if ((type != EFX_RXQ_TYPE_SCATTER) && + enp->en_nic_cfg.enc_rx_disable_scatter_supported) { + disable_scatter = B_TRUE; + } else { + disable_scatter = B_FALSE; + } + + if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index, + esmp, disable_scatter)) != 0) + goto fail3; + + erp->er_eep = eep; + erp->er_label = label; + + ef10_ev_rxlabel_init(eep, erp, label); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_rx_qdestroy( + __in efx_rxq_t *erp) +{ + efx_nic_t *enp = erp->er_enp; + efx_evq_t *eep = erp->er_eep; + unsigned int label = erp->er_label; + + ef10_ev_rxlabel_fini(eep, label); + + EFSYS_ASSERT(enp->en_rx_qcount != 0); + --enp->en_rx_qcount; + + EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp); +} + + void +ef10_rx_fini( + __in efx_nic_t *enp) +{ +#if EFSYS_OPT_RX_SCALE + if (enp->en_rss_support != EFX_RX_SCALE_UNAVAILABLE) { + (void) efx_mcdi_rss_context_free(enp, enp->en_rss_context); + } + enp->en_rss_context = 0; + enp->en_rss_support = EFX_RX_SCALE_UNAVAILABLE; +#else + _NOTE(ARGUNUSED(enp)) +#endif /* EFSYS_OPT_RX_SCALE */ +} + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_rx.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_tx.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_tx.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_tx.c (revision 301344) @@ -0,0 +1,710 @@ +/*- + * Copyright (c) 2012-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#if EFSYS_OPT_QSTATS +#define EFX_TX_QSTAT_INCR(_etp, _stat) \ + do { \ + (_etp)->et_stat[_stat]++; \ + _NOTE(CONSTANTCONDITION) \ + } while (B_FALSE) +#else +#define EFX_TX_QSTAT_INCR(_etp, _stat) +#endif + +static __checkReturn efx_rc_t +efx_mcdi_init_txq( + __in efx_nic_t *enp, + __in uint32_t size, + __in uint32_t target_evq, + __in uint32_t label, + __in uint32_t instance, + __in uint16_t flags, + __in efsys_mem_t *esmp) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_INIT_TXQ_IN_LEN(EFX_TXQ_MAX_BUFS), + MC_CMD_INIT_TXQ_OUT_LEN)]; + efx_qword_t *dma_addr; + uint64_t addr; + int npages; + int i; + efx_rc_t rc; + + EFSYS_ASSERT(EFX_TXQ_MAX_BUFS >= + EFX_TXQ_NBUFS(EFX_TXQ_MAXNDESCS(&enp->en_nic_cfg))); + + npages = EFX_TXQ_NBUFS(size); + if (npages > MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_INIT_TXQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages); + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, size); + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq); + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label); + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance); + + MCDI_IN_POPULATE_DWORD_7(req, INIT_TXQ_IN_FLAGS, + INIT_TXQ_IN_FLAG_BUFF_MODE, 0, + INIT_TXQ_IN_FLAG_IP_CSUM_DIS, + (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1, + INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, + (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1, + INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0, + INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0, + INIT_TXQ_IN_CRC_MODE, 0, + INIT_TXQ_IN_FLAG_TIMESTAMP, 0); + + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0); + MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + + dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR); + addr = EFSYS_MEM_ADDR(esmp); + + for (i = 0; i < npages; i++) { + EFX_POPULATE_QWORD_2(*dma_addr, + EFX_DWORD_1, (uint32_t)(addr >> 32), + EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); + + dma_addr++; + addr += EFX_BUF_SIZE; + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +efx_mcdi_fini_txq( + __in efx_nic_t *enp, + __in uint32_t instance) +{ + efx_mcdi_req_t req; + uint8_t payload[MAX(MC_CMD_FINI_TXQ_IN_LEN, + MC_CMD_FINI_TXQ_OUT_LEN)]; + efx_rc_t rc; + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_FINI_TXQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN; + + MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance); + + efx_mcdi_execute(enp, &req); + + if ((req.emr_rc != 0) && (req.emr_rc != MC_CMD_ERR_EALREADY)) { + rc = req.emr_rc; + goto fail1; + } + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_tx_init( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) + return (0); +} + + void +ef10_tx_fini( + __in efx_nic_t *enp) +{ + _NOTE(ARGUNUSED(enp)) +} + + __checkReturn efx_rc_t +ef10_tx_qcreate( + __in efx_nic_t *enp, + __in unsigned int index, + __in unsigned int label, + __in efsys_mem_t *esmp, + __in size_t n, + __in uint32_t id, + __in uint16_t flags, + __in efx_evq_t *eep, + __in efx_txq_t *etp, + __out unsigned int *addedp) +{ + efx_qword_t desc; + efx_rc_t rc; + + + if ((rc = efx_mcdi_init_txq(enp, n, eep->ee_index, label, index, flags, + esmp)) != 0) + goto fail1; + + /* + * A previous user of this TX queue may have written a descriptor to the + * TX push collector, but not pushed the doorbell (e.g. after a crash). + * The next doorbell write would then push the stale descriptor. + * + * Ensure the (per network port) TX push collector is cleared by writing + * a no-op TX option descriptor. See bug29981 for details. + */ + *addedp = 1; + EFX_POPULATE_QWORD_4(desc, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_CRC_CSUM, + ESF_DZ_TX_OPTION_UDP_TCP_CSUM, + (flags & EFX_TXQ_CKSUM_TCPUDP) ? 1 : 0, + ESF_DZ_TX_OPTION_IP_CSUM, + (flags & EFX_TXQ_CKSUM_IPV4) ? 1 : 0); + + EFSYS_MEM_WRITEQ(etp->et_esmp, 0, &desc); + ef10_tx_qpush(etp, *addedp, 0); + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_tx_qdestroy( + __in efx_txq_t *etp) +{ + /* FIXME */ + _NOTE(ARGUNUSED(etp)) + /* FIXME */ +} + + __checkReturn efx_rc_t +ef10_tx_qpio_enable( + __in efx_txq_t *etp) +{ + efx_nic_t *enp = etp->et_enp; + efx_piobuf_handle_t handle; + efx_rc_t rc; + + if (etp->et_pio_size != 0) { + rc = EALREADY; + goto fail1; + } + + /* Sub-allocate a PIO block from a piobuf */ + if ((rc = ef10_nic_pio_alloc(enp, + &etp->et_pio_bufnum, + &handle, + &etp->et_pio_blknum, + &etp->et_pio_offset, + &etp->et_pio_size)) != 0) { + goto fail2; + } + EFSYS_ASSERT3U(etp->et_pio_size, !=, 0); + + /* Link the piobuf to this TXQ */ + if ((rc = ef10_nic_pio_link(enp, etp->et_index, handle)) != 0) { + goto fail3; + } + + /* + * et_pio_offset is the offset of the sub-allocated block within the + * hardware PIO buffer. It is used as the buffer address in the PIO + * option descriptor. + * + * et_pio_write_offset is the offset of the sub-allocated block from the + * start of the write-combined memory mapping, and is used for writing + * data into the PIO buffer. + */ + etp->et_pio_write_offset = + (etp->et_pio_bufnum * ER_DZ_TX_PIOBUF_STEP) + + ER_DZ_TX_PIOBUF_OFST + etp->et_pio_offset; + + return (0); + +fail3: + EFSYS_PROBE(fail3); + ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum); + etp->et_pio_size = 0; +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_tx_qpio_disable( + __in efx_txq_t *etp) +{ + efx_nic_t *enp = etp->et_enp; + + if (etp->et_pio_size != 0) { + /* Unlink the piobuf from this TXQ */ + ef10_nic_pio_unlink(enp, etp->et_index); + + /* Free the sub-allocated PIO block */ + ef10_nic_pio_free(enp, etp->et_pio_bufnum, etp->et_pio_blknum); + etp->et_pio_size = 0; + etp->et_pio_write_offset = 0; + } +} + + __checkReturn efx_rc_t +ef10_tx_qpio_write( + __in efx_txq_t *etp, + __in_ecount(length) uint8_t *buffer, + __in size_t length, + __in size_t offset) +{ + efx_nic_t *enp = etp->et_enp; + efsys_bar_t *esbp = enp->en_esbp; + uint32_t write_offset; + uint32_t write_offset_limit; + efx_qword_t *eqp; + efx_rc_t rc; + + EFSYS_ASSERT(length % sizeof (efx_qword_t) == 0); + + if (etp->et_pio_size == 0) { + rc = ENOENT; + goto fail1; + } + if (offset + length > etp->et_pio_size) { + rc = ENOSPC; + goto fail2; + } + + /* + * Writes to PIO buffers must be 64 bit aligned, and multiples of + * 64 bits. + */ + write_offset = etp->et_pio_write_offset + offset; + write_offset_limit = write_offset + length; + eqp = (efx_qword_t *)buffer; + while (write_offset < write_offset_limit) { + EFSYS_BAR_WC_WRITEQ(esbp, write_offset, eqp); + eqp++; + write_offset += sizeof (efx_qword_t); + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_tx_qpio_post( + __in efx_txq_t *etp, + __in size_t pkt_length, + __in unsigned int completed, + __inout unsigned int *addedp) +{ + efx_qword_t pio_desc; + unsigned int id; + size_t offset; + unsigned int added = *addedp; + efx_rc_t rc; + + + if (added - completed + 1 > EFX_TXQ_LIMIT(etp->et_mask + 1)) { + rc = ENOSPC; + goto fail1; + } + + if (etp->et_pio_size == 0) { + rc = ENOENT; + goto fail2; + } + + id = added++ & etp->et_mask; + offset = id * sizeof (efx_qword_t); + + EFSYS_PROBE4(tx_pio_post, unsigned int, etp->et_index, + unsigned int, id, uint32_t, etp->et_pio_offset, + size_t, pkt_length); + + EFX_POPULATE_QWORD_5(pio_desc, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, 1, + ESF_DZ_TX_PIO_CONT, 0, + ESF_DZ_TX_PIO_BYTE_CNT, pkt_length, + ESF_DZ_TX_PIO_BUF_ADDR, etp->et_pio_offset); + + EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &pio_desc); + + EFX_TX_QSTAT_INCR(etp, TX_POST_PIO); + + *addedp = added; + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_tx_qpost( + __in efx_txq_t *etp, + __in_ecount(n) efx_buffer_t *eb, + __in unsigned int n, + __in unsigned int completed, + __inout unsigned int *addedp) +{ + unsigned int added = *addedp; + unsigned int i; + efx_rc_t rc; + + if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { + rc = ENOSPC; + goto fail1; + } + + for (i = 0; i < n; i++) { + efx_buffer_t *ebp = &eb[i]; + efsys_dma_addr_t addr = ebp->eb_addr; + size_t size = ebp->eb_size; + boolean_t eop = ebp->eb_eop; + unsigned int id; + size_t offset; + efx_qword_t qword; + + /* Fragments must not span 4k boundaries. */ + EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= (addr + size)); + + id = added++ & etp->et_mask; + offset = id * sizeof (efx_qword_t); + + EFSYS_PROBE5(tx_post, unsigned int, etp->et_index, + unsigned int, id, efsys_dma_addr_t, addr, + size_t, size, boolean_t, eop); + + EFX_POPULATE_QWORD_5(qword, + ESF_DZ_TX_KER_TYPE, 0, + ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1, + ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size), + ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), + ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); + + EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &qword); + } + + EFX_TX_QSTAT_INCR(etp, TX_POST); + + *addedp = added; + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +/* + * This improves performance by pushing a TX descriptor at the same time as the + * doorbell. The descriptor must be added to the TXQ, so that can be used if the + * hardware decides not to use the pushed descriptor. + */ + void +ef10_tx_qpush( + __in efx_txq_t *etp, + __in unsigned int added, + __in unsigned int pushed) +{ + efx_nic_t *enp = etp->et_enp; + unsigned int wptr; + unsigned int id; + size_t offset; + efx_qword_t desc; + efx_oword_t oword; + + wptr = added & etp->et_mask; + id = pushed & etp->et_mask; + offset = id * sizeof (efx_qword_t); + + EFSYS_MEM_READQ(etp->et_esmp, offset, &desc); + EFX_POPULATE_OWORD_3(oword, + ERF_DZ_TX_DESC_WPTR, wptr, + ERF_DZ_TX_DESC_HWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_1), + ERF_DZ_TX_DESC_LWORD, EFX_QWORD_FIELD(desc, EFX_DWORD_0)); + + /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ + EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, id); + EFSYS_PIO_WRITE_BARRIER(); + EFX_BAR_TBL_DOORBELL_WRITEO(enp, ER_DZ_TX_DESC_UPD_REG, etp->et_index, + &oword); +} + + __checkReturn efx_rc_t +ef10_tx_qdesc_post( + __in efx_txq_t *etp, + __in_ecount(n) efx_desc_t *ed, + __in unsigned int n, + __in unsigned int completed, + __inout unsigned int *addedp) +{ + unsigned int added = *addedp; + unsigned int i; + efx_rc_t rc; + + if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { + rc = ENOSPC; + goto fail1; + } + + for (i = 0; i < n; i++) { + efx_desc_t *edp = &ed[i]; + unsigned int id; + size_t offset; + + id = added++ & etp->et_mask; + offset = id * sizeof (efx_desc_t); + + EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq); + } + + EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index, + unsigned int, added, unsigned int, n); + + EFX_TX_QSTAT_INCR(etp, TX_POST); + + *addedp = added; + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_tx_qdesc_dma_create( + __in efx_txq_t *etp, + __in efsys_dma_addr_t addr, + __in size_t size, + __in boolean_t eop, + __out efx_desc_t *edp) +{ + /* Fragments must not span 4k boundaries. */ + EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size); + + EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index, + efsys_dma_addr_t, addr, + size_t, size, boolean_t, eop); + + EFX_POPULATE_QWORD_5(edp->ed_eq, + ESF_DZ_TX_KER_TYPE, 0, + ESF_DZ_TX_KER_CONT, (eop) ? 0 : 1, + ESF_DZ_TX_KER_BYTE_CNT, (uint32_t)(size), + ESF_DZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), + ESF_DZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); +} + + void +ef10_tx_qdesc_tso_create( + __in efx_txq_t *etp, + __in uint16_t ipv4_id, + __in uint32_t tcp_seq, + __in uint8_t tcp_flags, + __out efx_desc_t *edp) +{ + EFSYS_PROBE4(tx_desc_tso_create, unsigned int, etp->et_index, + uint16_t, ipv4_id, uint32_t, tcp_seq, + uint8_t, tcp_flags); + + EFX_POPULATE_QWORD_5(edp->ed_eq, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, + ESE_DZ_TX_OPTION_DESC_TSO, + ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags, + ESF_DZ_TX_TSO_IP_ID, ipv4_id, + ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq); +} + + void +ef10_tx_qdesc_tso2_create( + __in efx_txq_t *etp, + __in uint16_t ipv4_id, + __in uint32_t tcp_seq, + __in uint16_t tcp_mss, + __out_ecount(count) efx_desc_t *edp, + __in int count) +{ + EFSYS_PROBE4(tx_desc_tso2_create, unsigned int, etp->et_index, + uint16_t, ipv4_id, uint32_t, tcp_seq, + uint16_t, tcp_mss); + + EFSYS_ASSERT(count >= EFX_TX_FATSOV2_OPT_NDESCS); + + EFX_POPULATE_QWORD_5(edp[0].ed_eq, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, + ESE_DZ_TX_OPTION_DESC_TSO, + ESF_DZ_TX_TSO_OPTION_TYPE, + ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A, + ESF_DZ_TX_TSO_IP_ID, ipv4_id, + ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq); + EFX_POPULATE_QWORD_4(edp[1].ed_eq, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, + ESE_DZ_TX_OPTION_DESC_TSO, + ESF_DZ_TX_TSO_OPTION_TYPE, + ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B, + ESF_DZ_TX_TSO_TCP_MSS, tcp_mss); +} + + void +ef10_tx_qdesc_vlantci_create( + __in efx_txq_t *etp, + __in uint16_t tci, + __out efx_desc_t *edp) +{ + EFSYS_PROBE2(tx_desc_vlantci_create, unsigned int, etp->et_index, + uint16_t, tci); + + EFX_POPULATE_QWORD_4(edp->ed_eq, + ESF_DZ_TX_DESC_IS_OPT, 1, + ESF_DZ_TX_OPTION_TYPE, + ESE_DZ_TX_OPTION_DESC_VLAN, + ESF_DZ_TX_VLAN_OP, tci ? 1 : 0, + ESF_DZ_TX_VLAN_TAG1, tci); +} + + + __checkReturn efx_rc_t +ef10_tx_qpace( + __in efx_txq_t *etp, + __in unsigned int ns) +{ + efx_rc_t rc; + + /* FIXME */ + _NOTE(ARGUNUSED(etp, ns)) + if (B_FALSE) { + rc = ENOTSUP; + goto fail1; + } + /* FIXME */ + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_tx_qflush( + __in efx_txq_t *etp) +{ + efx_nic_t *enp = etp->et_enp; + efx_rc_t rc; + + if ((rc = efx_mcdi_fini_txq(enp, etp->et_index)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_tx_qenable( + __in efx_txq_t *etp) +{ + /* FIXME */ + _NOTE(ARGUNUSED(etp)) + /* FIXME */ +} + +#if EFSYS_OPT_QSTATS + void +ef10_tx_qstats_update( + __in efx_txq_t *etp, + __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) +{ + unsigned int id; + + for (id = 0; id < TX_NQSTATS; id++) { + efsys_stat_t *essp = &stat[id]; + + EFSYS_STAT_INCR(essp, etp->et_stat[id]); + etp->et_stat[id] = 0; + } +} + +#endif /* EFSYS_OPT_QSTATS */ + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_tx.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/ef10_vpd.c =================================================================== --- stable/10/sys/dev/sfxge/common/ef10_vpd.c (nonexistent) +++ stable/10/sys/dev/sfxge/common/ef10_vpd.c (revision 301344) @@ -0,0 +1,463 @@ +/*- + * Copyright (c) 2009-2015 Solarflare Communications 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: + * + * 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 OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "efx.h" +#include "efx_impl.h" + + +#if EFSYS_OPT_VPD + +#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD + +#include "ef10_tlv_layout.h" + + __checkReturn efx_rc_t +ef10_vpd_init( + __in efx_nic_t *enp) +{ + caddr_t svpd; + size_t svpd_size; + uint32_t pci_pf; + uint32_t tag; + efx_rc_t rc; + + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (enp->en_nic_cfg.enc_vpd_is_global) { + tag = TLV_TAG_GLOBAL_STATIC_VPD; + } else { + pci_pf = enp->en_nic_cfg.enc_pf; + tag = TLV_TAG_PF_STATIC_VPD(pci_pf); + } + + /* + * The VPD interface exposes VPD resources from the combined static and + * dynamic VPD storage. As the static VPD configuration should *never* + * change, we can cache it. + */ + svpd = NULL; + svpd_size = 0; + rc = ef10_nvram_partn_read_tlv(enp, + NVRAM_PARTITION_TYPE_STATIC_CONFIG, + tag, &svpd, &svpd_size); + if (rc != 0) { + if (rc == EACCES) { + /* Unprivileged functions cannot access VPD */ + goto out; + } + goto fail1; + } + + if (svpd != NULL && svpd_size > 0) { + if ((rc = efx_vpd_hunk_verify(svpd, svpd_size, NULL)) != 0) + goto fail2; + } + + enp->en_arch.ef10.ena_svpd = svpd; + enp->en_arch.ef10.ena_svpd_length = svpd_size; + +out: + return (0); + +fail2: + EFSYS_PROBE(fail2); + + EFSYS_KMEM_FREE(enp->en_esip, svpd_size, svpd); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_size( + __in efx_nic_t *enp, + __out size_t *sizep) +{ + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * This function returns the total size the user should allocate + * for all VPD operations. We've already cached the static vpd, + * so we just need to return an upper bound on the dynamic vpd, + * which is the size of the DYNAMIC_CONFIG partition. + */ + if ((rc = efx_mcdi_nvram_info(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, + sizep, NULL, NULL, NULL)) != 0) + goto fail1; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_read( + __in efx_nic_t *enp, + __out_bcount(size) caddr_t data, + __in size_t size) +{ + caddr_t dvpd; + size_t dvpd_size; + uint32_t pci_pf; + uint32_t tag; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (enp->en_nic_cfg.enc_vpd_is_global) { + tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; + } else { + pci_pf = enp->en_nic_cfg.enc_pf; + tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); + } + + if ((rc = ef10_nvram_partn_read_tlv(enp, + NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, + tag, &dvpd, &dvpd_size)) != 0) + goto fail1; + + if (dvpd_size > size) { + rc = ENOSPC; + goto fail2; + } + memcpy(data, dvpd, dvpd_size); + + /* Pad data with all-1s, consistent with update operations */ + memset(data + dvpd_size, 0xff, size - dvpd_size); + + EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); + + return (0); + +fail2: + EFSYS_PROBE(fail2); + + EFSYS_KMEM_FREE(enp->en_esip, dvpd_size, dvpd); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_verify( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size) +{ + efx_vpd_tag_t stag; + efx_vpd_tag_t dtag; + efx_vpd_keyword_t skey; + efx_vpd_keyword_t dkey; + unsigned int scont; + unsigned int dcont; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* + * Strictly you could take the view that dynamic vpd is optional. + * Instead, to conform more closely to the read/verify/reinit() + * paradigm, we require dynamic vpd. ef10_vpd_reinit() will + * reinitialize it as required. + */ + if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) + goto fail1; + + /* + * Verify that there is no duplication between the static and + * dynamic cfg sectors. + */ + if (enp->en_arch.ef10.ena_svpd_length == 0) + goto done; + + dcont = 0; + _NOTE(CONSTANTCONDITION) + while (1) { + if ((rc = efx_vpd_hunk_next(data, size, &dtag, + &dkey, NULL, NULL, &dcont)) != 0) + goto fail2; + if (dcont == 0) + break; + + /* + * Skip the RV keyword. It should be present in both the static + * and dynamic cfg sectors. + */ + if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V')) + continue; + + scont = 0; + _NOTE(CONSTANTCONDITION) + while (1) { + if ((rc = efx_vpd_hunk_next( + enp->en_arch.ef10.ena_svpd, + enp->en_arch.ef10.ena_svpd_length, &stag, &skey, + NULL, NULL, &scont)) != 0) + goto fail3; + if (scont == 0) + break; + + if (stag == dtag && skey == dkey) { + rc = EEXIST; + goto fail4; + } + } + } + +done: + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_reinit( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size) +{ + boolean_t wantpid; + efx_rc_t rc; + + /* + * Only create an ID string if the dynamic cfg doesn't have one + */ + if (enp->en_arch.ef10.ena_svpd_length == 0) + wantpid = B_TRUE; + else { + unsigned int offset; + uint8_t length; + + rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, + enp->en_arch.ef10.ena_svpd_length, + EFX_VPD_ID, 0, &offset, &length); + if (rc == 0) + wantpid = B_FALSE; + else if (rc == ENOENT) + wantpid = B_TRUE; + else + goto fail1; + } + + if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_get( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size, + __inout efx_vpd_value_t *evvp) +{ + unsigned int offset; + uint8_t length; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* Attempt to satisfy the request from svpd first */ + if (enp->en_arch.ef10.ena_svpd_length > 0) { + if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, + enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, + evvp->evv_keyword, &offset, &length)) == 0) { + evvp->evv_length = length; + memcpy(evvp->evv_value, + enp->en_arch.ef10.ena_svpd + offset, length); + return (0); + } else if (rc != ENOENT) + goto fail1; + } + + /* And then from the provided data buffer */ + if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, + evvp->evv_keyword, &offset, &length)) != 0) + goto fail2; + + evvp->evv_length = length; + memcpy(evvp->evv_value, data + offset, length); + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_set( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size, + __in efx_vpd_value_t *evvp) +{ + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + /* If the provided (tag,keyword) exists in svpd, then it is readonly */ + if (enp->en_arch.ef10.ena_svpd_length > 0) { + unsigned int offset; + uint8_t length; + + if ((rc = efx_vpd_hunk_get(enp->en_arch.ef10.ena_svpd, + enp->en_arch.ef10.ena_svpd_length, evvp->evv_tag, + evvp->evv_keyword, &offset, &length)) == 0) { + rc = EACCES; + goto fail1; + } + } + + if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) + goto fail2; + + return (0); + +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + __checkReturn efx_rc_t +ef10_vpd_next( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size, + __out efx_vpd_value_t *evvp, + __inout unsigned int *contp) +{ + _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) + + return (ENOTSUP); +} + + __checkReturn efx_rc_t +ef10_vpd_write( + __in efx_nic_t *enp, + __in_bcount(size) caddr_t data, + __in size_t size) +{ + size_t vpd_length; + uint32_t pci_pf; + uint32_t tag; + efx_rc_t rc; + + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (enp->en_nic_cfg.enc_vpd_is_global) { + tag = TLV_TAG_GLOBAL_DYNAMIC_VPD; + } else { + pci_pf = enp->en_nic_cfg.enc_pf; + tag = TLV_TAG_PF_DYNAMIC_VPD(pci_pf); + } + + /* Determine total length of new dynamic VPD */ + if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) + goto fail1; + + /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ + if ((rc = ef10_nvram_partn_write_segment_tlv(enp, + NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, + tag, data, vpd_length, B_TRUE)) != 0) { + goto fail2; + } + + return (0); + +fail2: + EFSYS_PROBE(fail2); + +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + + void +ef10_vpd_fini( + __in efx_nic_t *enp) +{ + EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || + enp->en_family == EFX_FAMILY_MEDFORD); + + if (enp->en_arch.ef10.ena_svpd_length > 0) { + EFSYS_KMEM_FREE(enp->en_esip, enp->en_arch.ef10.ena_svpd_length, + enp->en_arch.ef10.ena_svpd); + + enp->en_arch.ef10.ena_svpd = NULL; + enp->en_arch.ef10.ena_svpd_length = 0; + } +} + +#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ + +#endif /* EFSYS_OPT_VPD */ Property changes on: stable/10/sys/dev/sfxge/common/ef10_vpd.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/dev/sfxge/common/efx_tx.c =================================================================== --- stable/10/sys/dev/sfxge/common/efx_tx.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/efx_tx.c (revision 301344) @@ -1,1091 +1,1091 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications 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: * * 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 OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_QSTATS #define EFX_TX_QSTAT_INCR(_etp, _stat) \ do { \ (_etp)->et_stat[_stat]++; \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #else #define EFX_TX_QSTAT_INCR(_etp, _stat) #endif #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_tx_init( __in efx_nic_t *enp); static void falconsiena_tx_fini( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __in efx_txq_t *etp, __out unsigned int *addedp); static void falconsiena_tx_qdestroy( __in efx_txq_t *etp); static __checkReturn efx_rc_t falconsiena_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); static void falconsiena_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed); static __checkReturn efx_rc_t falconsiena_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns); static __checkReturn efx_rc_t falconsiena_tx_qflush( __in efx_txq_t *etp); static void falconsiena_tx_qenable( __in efx_txq_t *etp); __checkReturn efx_rc_t falconsiena_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); void falconsiena_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp); #if EFSYS_OPT_QSTATS static void falconsiena_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat); #endif #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA static const efx_tx_ops_t __efx_tx_siena_ops = { falconsiena_tx_init, /* etxo_init */ falconsiena_tx_fini, /* etxo_fini */ falconsiena_tx_qcreate, /* etxo_qcreate */ falconsiena_tx_qdestroy, /* etxo_qdestroy */ falconsiena_tx_qpost, /* etxo_qpost */ falconsiena_tx_qpush, /* etxo_qpush */ falconsiena_tx_qpace, /* etxo_qpace */ falconsiena_tx_qflush, /* etxo_qflush */ falconsiena_tx_qenable, /* etxo_qenable */ NULL, /* etxo_qpio_enable */ NULL, /* etxo_qpio_disable */ NULL, /* etxo_qpio_write */ NULL, /* etxo_qpio_post */ falconsiena_tx_qdesc_post, /* etxo_qdesc_post */ falconsiena_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ NULL, /* etxo_qdesc_tso_create */ NULL, /* etxo_qdesc_tso2_create */ NULL, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS falconsiena_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON static const efx_tx_ops_t __efx_tx_hunt_ops = { ef10_tx_init, /* etxo_init */ ef10_tx_fini, /* etxo_fini */ ef10_tx_qcreate, /* etxo_qcreate */ ef10_tx_qdestroy, /* etxo_qdestroy */ ef10_tx_qpost, /* etxo_qpost */ ef10_tx_qpush, /* etxo_qpush */ ef10_tx_qpace, /* etxo_qpace */ ef10_tx_qflush, /* etxo_qflush */ ef10_tx_qenable, /* etxo_qenable */ ef10_tx_qpio_enable, /* etxo_qpio_enable */ ef10_tx_qpio_disable, /* etxo_qpio_disable */ ef10_tx_qpio_write, /* etxo_qpio_write */ ef10_tx_qpio_post, /* etxo_qpio_post */ ef10_tx_qdesc_post, /* etxo_qdesc_post */ ef10_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ - hunt_tx_qdesc_tso_create, /* etxo_qdesc_tso_create */ + ef10_tx_qdesc_tso_create, /* etxo_qdesc_tso_create */ ef10_tx_qdesc_tso2_create, /* etxo_qdesc_tso2_create */ ef10_tx_qdesc_vlantci_create, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS ef10_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD static const efx_tx_ops_t __efx_tx_medford_ops = { ef10_tx_init, /* etxo_init */ ef10_tx_fini, /* etxo_fini */ ef10_tx_qcreate, /* etxo_qcreate */ ef10_tx_qdestroy, /* etxo_qdestroy */ ef10_tx_qpost, /* etxo_qpost */ ef10_tx_qpush, /* etxo_qpush */ ef10_tx_qpace, /* etxo_qpace */ ef10_tx_qflush, /* etxo_qflush */ ef10_tx_qenable, /* etxo_qenable */ ef10_tx_qpio_enable, /* etxo_qpio_enable */ ef10_tx_qpio_disable, /* etxo_qpio_disable */ ef10_tx_qpio_write, /* etxo_qpio_write */ ef10_tx_qpio_post, /* etxo_qpio_post */ ef10_tx_qdesc_post, /* etxo_qdesc_post */ ef10_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ NULL, /* etxo_qdesc_tso_create */ ef10_tx_qdesc_tso2_create, /* etxo_qdesc_tso2_create */ ef10_tx_qdesc_vlantci_create, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS ef10_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_tx_init( __in efx_nic_t *enp) { const efx_tx_ops_t *etxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (!(enp->en_mod_flags & EFX_MOD_EV)) { rc = EINVAL; goto fail1; } if (enp->en_mod_flags & EFX_MOD_TX) { rc = EINVAL; goto fail2; } switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: etxop = &__efx_tx_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: etxop = &__efx_tx_hunt_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: etxop = &__efx_tx_medford_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail3; } EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0); if ((rc = etxop->etxo_init(enp)) != 0) goto fail4; enp->en_etxop = etxop; enp->en_mod_flags |= EFX_MOD_TX; return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_etxop = NULL; enp->en_mod_flags &= ~EFX_MOD_TX; return (rc); } void efx_tx_fini( __in efx_nic_t *enp) { const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX); EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0); etxop->etxo_fini(enp); enp->en_etxop = NULL; enp->en_mod_flags &= ~EFX_MOD_TX; } __checkReturn efx_rc_t efx_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __deref_out efx_txq_t **etpp, __out unsigned int *addedp) { const efx_tx_ops_t *etxop = enp->en_etxop; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_txq_t *etp; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX); EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit); /* Allocate an TXQ object */ EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp); if (etp == NULL) { rc = ENOMEM; goto fail1; } etp->et_magic = EFX_TXQ_MAGIC; etp->et_enp = enp; etp->et_index = index; etp->et_mask = n - 1; etp->et_esmp = esmp; /* Initial descriptor index may be modified by etxo_qcreate */ *addedp = 0; if ((rc = etxop->etxo_qcreate(enp, index, label, esmp, n, id, flags, eep, etp, addedp)) != 0) goto fail2; enp->en_tx_qcount++; *etpp = etp; return (0); fail2: EFSYS_PROBE(fail2); EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qdestroy( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(enp->en_tx_qcount != 0); --enp->en_tx_qcount; etxop->etxo_qdestroy(etp); /* Free the TXQ object */ EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp); } __checkReturn efx_rc_t efx_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qpost(etp, eb, n, completed, addedp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qpush(etp, added, pushed); } __checkReturn efx_rc_t efx_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qpace(etp, ns)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qflush( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qflush(etp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qenable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qenable(etp); } __checkReturn efx_rc_t efx_tx_qpio_enable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (~enp->en_features & EFX_FEATURE_PIO_BUFFERS) { rc = ENOTSUP; goto fail1; } if (etxop->etxo_qpio_enable == NULL) { rc = ENOTSUP; goto fail2; } if ((rc = etxop->etxo_qpio_enable(etp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qpio_disable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_disable != NULL) etxop->etxo_qpio_disable(etp); } __checkReturn efx_rc_t efx_tx_qpio_write( __in efx_txq_t *etp, __in_ecount(buf_length) uint8_t *buffer, __in size_t buf_length, __in size_t pio_buf_offset) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_write != NULL) { if ((rc = etxop->etxo_qpio_write(etp, buffer, buf_length, pio_buf_offset)) != 0) goto fail1; return (0); } return (ENOTSUP); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qpio_post( __in efx_txq_t *etp, __in size_t pkt_length, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_post != NULL) { if ((rc = etxop->etxo_qpio_post(etp, pkt_length, completed, addedp)) != 0) goto fail1; return (0); } return (ENOTSUP); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qdesc_post(etp, ed, n, completed, addedp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_dma_create != NULL); etxop->etxo_qdesc_dma_create(etp, addr, size, eop, edp); } void efx_tx_qdesc_tso_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint8_t tcp_flags, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_tso_create != NULL); etxop->etxo_qdesc_tso_create(etp, ipv4_id, tcp_seq, tcp_flags, edp); } void efx_tx_qdesc_tso2_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint16_t mss, __out_ecount(count) efx_desc_t *edp, __in int count) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_tso2_create != NULL); etxop->etxo_qdesc_tso2_create(etp, ipv4_id, tcp_seq, mss, edp, count); } void efx_tx_qdesc_vlantci_create( __in efx_txq_t *etp, __in uint16_t tci, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_vlantci_create != NULL); etxop->etxo_qdesc_vlantci_create(etp, tci, edp); } #if EFSYS_OPT_QSTATS void efx_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) { efx_nic_t *enp = etp->et_enp; const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qstats_update(etp, stat); } #endif #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_tx_init( __in efx_nic_t *enp) { efx_oword_t oword; /* * Disable the timer-based TX DMA backoff and allow TX DMA to be * controlled by the RX FIFO fill level (although always allow a * minimal trickle). */ EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff); /* * Filter all packets less than 14 bytes to avoid parsing * errors. */ EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword); /* * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16 * descriptors (which is bad). */ EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0); EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); return (0); } #define EFX_TX_DESC(_etp, _addr, _size, _eop, _added) \ do { \ unsigned int id; \ size_t offset; \ efx_qword_t qword; \ \ id = (_added)++ & (_etp)->et_mask; \ offset = id * sizeof (efx_qword_t); \ \ EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index, \ unsigned int, id, efsys_dma_addr_t, (_addr), \ size_t, (_size), boolean_t, (_eop)); \ \ EFX_POPULATE_QWORD_4(qword, \ FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1, \ FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size), \ FSF_AZ_TX_KER_BUF_ADDR_DW0, \ (uint32_t)((_addr) & 0xffffffff), \ FSF_AZ_TX_KER_BUF_ADDR_DW1, \ (uint32_t)((_addr) >> 32)); \ EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword); \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) static __checkReturn efx_rc_t falconsiena_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { unsigned int added = *addedp; unsigned int i; int rc = ENOSPC; if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) goto fail1; for (i = 0; i < n; i++) { efx_buffer_t *ebp = &eb[i]; efsys_dma_addr_t start = ebp->eb_addr; size_t size = ebp->eb_size; efsys_dma_addr_t end = start + size; /* Fragments must not span 4k boundaries. */ EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end); EFX_TX_DESC(etp, start, size, ebp->eb_eop, added); } EFX_TX_QSTAT_INCR(etp, TX_POST); *addedp = added; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static void falconsiena_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed) { efx_nic_t *enp = etp->et_enp; uint32_t wptr; efx_dword_t dword; efx_oword_t oword; /* Push the populated descriptors out */ wptr = added & etp->et_mask; EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr); /* Only write the third DWORD */ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3)); /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, pushed & etp->et_mask); EFSYS_PIO_WRITE_BARRIER(); EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0, etp->et_index, &dword, B_FALSE); } #define EFX_MAX_PACE_VALUE 20 #define EFX_TX_PACE_CLOCK_BASE 104 static __checkReturn efx_rc_t falconsiena_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns) { efx_nic_t *enp = etp->et_enp; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_oword_t oword; unsigned int pace_val; unsigned int timer_period; efx_rc_t rc; if (ns == 0) { pace_val = 0; } else { /* * The pace_val to write into the table is s.t * ns <= timer_period * (2 ^ pace_val) */ timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult; for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) { if ((timer_period << pace_val) >= ns) break; } } if (pace_val > EFX_MAX_PACE_VALUE) { rc = EINVAL; goto fail1; } /* Update the pacing table */ EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index, &oword, B_TRUE); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t falconsiena_tx_qflush( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; uint32_t label; efx_tx_qpace(etp, 0); label = etp->et_index; /* Flush the queue */ EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, FRF_AZ_TX_FLUSH_DESCQ, label); EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword); return (0); } static void falconsiena_tx_qenable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index, uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0)); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); } static __checkReturn efx_rc_t falconsiena_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __in efx_txq_t *etp, __out unsigned int *addedp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_oword_t oword; uint32_t size; efx_rc_t rc; EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS == (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH)); EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS); EFSYS_ASSERT(ISP2(EFX_TXQ_MAXNDESCS(encp))); EFX_STATIC_ASSERT(ISP2(EFX_TXQ_MINNDESCS)); if (!ISP2(n) || (n < EFX_TXQ_MINNDESCS) || (n > EFX_EVQ_MAXNEVS)) { rc = EINVAL; goto fail1; } if (index >= encp->enc_txq_limit) { rc = EINVAL; goto fail2; } for (size = 0; (1 << size) <= (EFX_TXQ_MAXNDESCS(encp) / EFX_TXQ_MINNDESCS); size++) if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS)) break; if (id + (1 << size) >= encp->enc_buftbl_limit) { rc = EINVAL; goto fail3; } /* Set up the new descriptor queue */ *addedp = 0; EFX_POPULATE_OWORD_6(oword, FRF_AZ_TX_DESCQ_BUF_BASE_ID, id, FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index, FRF_AZ_TX_DESCQ_OWNER_ID, 0, FRF_AZ_TX_DESCQ_LABEL, label, FRF_AZ_TX_DESCQ_SIZE, size, FRF_AZ_TX_DESCQ_TYPE, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS, (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS, (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t falconsiena_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { unsigned int added = *addedp; unsigned int i; efx_rc_t rc; if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { rc = ENOSPC; goto fail1; } for (i = 0; i < n; i++) { efx_desc_t *edp = &ed[i]; unsigned int id; size_t offset; id = added++ & etp->et_mask; offset = id * sizeof (efx_desc_t); EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq); } EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index, unsigned int, added, unsigned int, n); EFX_TX_QSTAT_INCR(etp, TX_POST); *addedp = added; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void falconsiena_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp) { /* Fragments must not span 4k boundaries. */ EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size); EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index, efsys_dma_addr_t, addr, size_t, size, boolean_t, eop); EFX_POPULATE_QWORD_4(edp->ed_eq, FSF_AZ_TX_KER_CONT, eop ? 0 : 1, FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)size, FSF_AZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), FSF_AZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); } #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_QSTATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 9d8d26a0a5e2c453 */ static const char *__efx_tx_qstat_name[] = { "post", "post_pio", }; /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */ const char * efx_tx_qstat_name( __in efx_nic_t *enp, __in unsigned int id) { _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(id, <, TX_NQSTATS); return (__efx_tx_qstat_name[id]); } #endif /* EFSYS_OPT_NAMES */ #endif /* EFSYS_OPT_QSTATS */ #if EFSYS_OPT_SIENA #if EFSYS_OPT_QSTATS static void falconsiena_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) { unsigned int id; for (id = 0; id < TX_NQSTATS; id++) { efsys_stat_t *essp = &stat[id]; EFSYS_STAT_INCR(essp, etp->et_stat[id]); etp->et_stat[id] = 0; } } #endif /* EFSYS_OPT_QSTATS */ static void falconsiena_tx_qdestroy( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; /* Purge descriptor queue */ EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); } static void falconsiena_tx_fini( __in efx_nic_t *enp) { _NOTE(ARGUNUSED(enp)) } #endif /* EFSYS_OPT_SIENA */ Index: stable/10/sys/dev/sfxge/common/hunt_impl.h =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_impl.h (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_impl.h (revision 301344) @@ -1,1128 +1,1128 @@ /*- * Copyright (c) 2012-2015 Solarflare Communications 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: * * 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 OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. * * $FreeBSD$ */ #ifndef _SYS_HUNT_IMPL_H #define _SYS_HUNT_IMPL_H #include "efx.h" #include "efx_regs.h" #include "efx_regs_ef10.h" #include "efx_mcdi.h" #ifdef __cplusplus extern "C" { #endif /* * FIXME: This is just a power of 2 which fits in an MCDI v1 message, and could * possibly be increased, or the write size reported by newer firmware used * instead. */ #define EF10_NVRAM_CHUNK 0x80 /* Alignment requirement for value written to RX WPTR: * the WPTR must be aligned to an 8 descriptor boundary */ #define EF10_RX_WPTR_ALIGN 8 /* * Max byte offset into the packet the TCP header must start for the hardware * to be able to parse the packet correctly. * FIXME: Move to ef10_impl.h when it is included in all driver builds. */ #define EF10_TCP_HEADER_OFFSET_LIMIT 208 /* Invalid RSS context handle */ #define EF10_RSS_CONTEXT_INVALID (0xffffffff) /* EV */ __checkReturn efx_rc_t ef10_ev_init( __in efx_nic_t *enp); void ef10_ev_fini( __in efx_nic_t *enp); __checkReturn efx_rc_t ef10_ev_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep); void ef10_ev_qdestroy( __in efx_evq_t *eep); __checkReturn efx_rc_t ef10_ev_qprime( __in efx_evq_t *eep, __in unsigned int count); void ef10_ev_qpost( __in efx_evq_t *eep, __in uint16_t data); __checkReturn efx_rc_t ef10_ev_qmoderate( __in efx_evq_t *eep, __in unsigned int us); #if EFSYS_OPT_QSTATS void ef10_ev_qstats_update( __in efx_evq_t *eep, __inout_ecount(EV_NQSTATS) efsys_stat_t *stat); #endif /* EFSYS_OPT_QSTATS */ void ef10_ev_rxlabel_init( __in efx_evq_t *eep, __in efx_rxq_t *erp, __in unsigned int label); void ef10_ev_rxlabel_fini( __in efx_evq_t *eep, __in unsigned int label); /* INTR */ __checkReturn efx_rc_t ef10_intr_init( __in efx_nic_t *enp, __in efx_intr_type_t type, __in efsys_mem_t *esmp); void ef10_intr_enable( __in efx_nic_t *enp); void ef10_intr_disable( __in efx_nic_t *enp); void ef10_intr_disable_unlocked( __in efx_nic_t *enp); __checkReturn efx_rc_t ef10_intr_trigger( __in efx_nic_t *enp, __in unsigned int level); void ef10_intr_status_line( __in efx_nic_t *enp, __out boolean_t *fatalp, __out uint32_t *qmaskp); void ef10_intr_status_message( __in efx_nic_t *enp, __in unsigned int message, __out boolean_t *fatalp); void ef10_intr_fatal( __in efx_nic_t *enp); void ef10_intr_fini( __in efx_nic_t *enp); /* NIC */ extern __checkReturn efx_rc_t ef10_nic_probe( __in efx_nic_t *enp); extern __checkReturn efx_rc_t hunt_board_cfg( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_nic_set_drv_limits( __inout efx_nic_t *enp, __in efx_drv_limits_t *edlp); extern __checkReturn efx_rc_t ef10_nic_get_vi_pool( __in efx_nic_t *enp, __out uint32_t *vi_countp); extern __checkReturn efx_rc_t ef10_nic_get_bar_region( __in efx_nic_t *enp, __in efx_nic_region_t region, __out uint32_t *offsetp, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_nic_reset( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_nic_init( __in efx_nic_t *enp); #if EFSYS_OPT_DIAG extern __checkReturn efx_rc_t ef10_nic_register_test( __in efx_nic_t *enp); #endif /* EFSYS_OPT_DIAG */ extern void ef10_nic_fini( __in efx_nic_t *enp); extern void ef10_nic_unprobe( __in efx_nic_t *enp); /* MAC */ extern __checkReturn efx_rc_t ef10_mac_poll( __in efx_nic_t *enp, __out efx_link_mode_t *link_modep); extern __checkReturn efx_rc_t ef10_mac_up( __in efx_nic_t *enp, __out boolean_t *mac_upp); extern __checkReturn efx_rc_t ef10_mac_addr_set( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_mac_pdu_set( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_mac_reconfigure( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_mac_multicast_list_set( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_mac_filter_default_rxq_set( __in efx_nic_t *enp, __in efx_rxq_t *erp, __in boolean_t using_rss); extern void ef10_mac_filter_default_rxq_clear( __in efx_nic_t *enp); #if EFSYS_OPT_LOOPBACK extern __checkReturn efx_rc_t ef10_mac_loopback_set( __in efx_nic_t *enp, __in efx_link_mode_t link_mode, __in efx_loopback_type_t loopback_type); #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS extern __checkReturn efx_rc_t ef10_mac_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat, __inout_opt uint32_t *generationp); #endif /* EFSYS_OPT_MAC_STATS */ /* MCDI */ #if EFSYS_OPT_MCDI extern __checkReturn efx_rc_t ef10_mcdi_init( __in efx_nic_t *enp, __in const efx_mcdi_transport_t *mtp); extern void ef10_mcdi_fini( __in efx_nic_t *enp); extern void ef10_mcdi_send_request( __in efx_nic_t *enp, __in void *hdrp, __in size_t hdr_len, __in void *sdup, __in size_t sdu_len); extern __checkReturn boolean_t ef10_mcdi_poll_response( __in efx_nic_t *enp); extern void ef10_mcdi_read_response( __in efx_nic_t *enp, __out_bcount(length) void *bufferp, __in size_t offset, __in size_t length); extern efx_rc_t ef10_mcdi_poll_reboot( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_mcdi_feature_supported( __in efx_nic_t *enp, __in efx_mcdi_feature_id_t id, __out boolean_t *supportedp); #endif /* EFSYS_OPT_MCDI */ /* NVRAM */ #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD extern __checkReturn efx_rc_t ef10_nvram_buf_read_tlv( __in efx_nic_t *enp, __in_bcount(max_seg_size) caddr_t seg_data, __in size_t max_seg_size, __in uint32_t tag, __deref_out_bcount_opt(*sizep) caddr_t *datap, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_nvram_buf_write_tlv( __inout_bcount(partn_size) caddr_t partn_data, __in size_t partn_size, __in uint32_t tag, __in_bcount(tag_size) caddr_t tag_data, __in size_t tag_size, __out size_t *total_lengthp); extern __checkReturn efx_rc_t ef10_nvram_partn_read_tlv( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t tag, __deref_out_bcount_opt(*sizep) caddr_t *datap, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_nvram_partn_write_tlv( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t tag, __in_bcount(size) caddr_t data, __in size_t size); extern __checkReturn efx_rc_t ef10_nvram_partn_write_segment_tlv( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t tag, __in_bcount(size) caddr_t data, __in size_t size, __in boolean_t all_segments); extern __checkReturn efx_rc_t ef10_nvram_partn_lock( __in efx_nic_t *enp, __in uint32_t partn); extern void ef10_nvram_partn_unlock( __in efx_nic_t *enp, __in uint32_t partn); #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ #if EFSYS_OPT_NVRAM #if EFSYS_OPT_DIAG extern __checkReturn efx_rc_t ef10_nvram_test( __in efx_nic_t *enp); #endif /* EFSYS_OPT_DIAG */ extern __checkReturn efx_rc_t ef10_nvram_type_to_partn( __in efx_nic_t *enp, __in efx_nvram_type_t type, __out uint32_t *partnp); extern __checkReturn efx_rc_t ef10_nvram_partn_size( __in efx_nic_t *enp, __in uint32_t partn, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_nvram_partn_rw_start( __in efx_nic_t *enp, __in uint32_t partn, __out size_t *chunk_sizep); extern __checkReturn efx_rc_t ef10_nvram_partn_read_mode( __in efx_nic_t *enp, __in uint32_t partn, __in unsigned int offset, __out_bcount(size) caddr_t data, __in size_t size, __in uint32_t mode); extern __checkReturn efx_rc_t ef10_nvram_partn_read( __in efx_nic_t *enp, __in uint32_t partn, __in unsigned int offset, __out_bcount(size) caddr_t data, __in size_t size); extern __checkReturn efx_rc_t ef10_nvram_partn_erase( __in efx_nic_t *enp, __in uint32_t partn, __in unsigned int offset, __in size_t size); extern __checkReturn efx_rc_t ef10_nvram_partn_write( __in efx_nic_t *enp, __in uint32_t partn, __in unsigned int offset, __out_bcount(size) caddr_t data, __in size_t size); extern void ef10_nvram_partn_rw_finish( __in efx_nic_t *enp, __in uint32_t partn); extern __checkReturn efx_rc_t ef10_nvram_partn_get_version( __in efx_nic_t *enp, __in uint32_t partn, __out uint32_t *subtypep, __out_ecount(4) uint16_t version[4]); extern __checkReturn efx_rc_t ef10_nvram_partn_set_version( __in efx_nic_t *enp, __in uint32_t partn, __in_ecount(4) uint16_t version[4]); extern __checkReturn efx_rc_t ef10_nvram_buffer_validate( __in efx_nic_t *enp, __in uint32_t partn, __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size); extern __checkReturn efx_rc_t ef10_nvram_buffer_create( __in efx_nic_t *enp, __in uint16_t partn_type, __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size); extern __checkReturn efx_rc_t ef10_nvram_buffer_find_item_start( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __out uint32_t *startp ); extern __checkReturn efx_rc_t ef10_nvram_buffer_find_end( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __in uint32_t offset, __out uint32_t *endp ); extern __checkReturn __success(return != B_FALSE) boolean_t ef10_nvram_buffer_find_item( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __in uint32_t offset, __out uint32_t *startp, __out uint32_t *lengthp ); extern __checkReturn efx_rc_t ef10_nvram_buffer_get_item( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __in uint32_t offset, __in uint32_t length, __out_bcount_part(item_max_size, *lengthp) caddr_t itemp, __in size_t item_max_size, __out uint32_t *lengthp ); extern __checkReturn efx_rc_t ef10_nvram_buffer_insert_item( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __in uint32_t offset, __in_bcount(length) caddr_t keyp, __in uint32_t length, __out uint32_t *lengthp ); extern __checkReturn efx_rc_t ef10_nvram_buffer_delete_item( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size, __in uint32_t offset, __in uint32_t length, __in uint32_t end ); extern __checkReturn efx_rc_t ef10_nvram_buffer_finish( __in_bcount(buffer_size) caddr_t bufferp, __in size_t buffer_size ); #endif /* EFSYS_OPT_NVRAM */ /* PHY */ typedef struct ef10_link_state_s { uint32_t els_adv_cap_mask; uint32_t els_lp_cap_mask; unsigned int els_fcntl; efx_link_mode_t els_link_mode; #if EFSYS_OPT_LOOPBACK efx_loopback_type_t els_loopback; #endif boolean_t els_mac_up; } ef10_link_state_t; extern void ef10_phy_link_ev( __in efx_nic_t *enp, __in efx_qword_t *eqp, __out efx_link_mode_t *link_modep); extern __checkReturn efx_rc_t ef10_phy_get_link( __in efx_nic_t *enp, __out ef10_link_state_t *elsp); extern __checkReturn efx_rc_t ef10_phy_power( __in efx_nic_t *enp, __in boolean_t on); extern __checkReturn efx_rc_t ef10_phy_reconfigure( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_phy_verify( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip); #if EFSYS_OPT_PHY_STATS extern __checkReturn efx_rc_t ef10_phy_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat); #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_PHY_PROPS #if EFSYS_OPT_NAMES extern const char * ef10_phy_prop_name( __in efx_nic_t *enp, __in unsigned int id); #endif /* EFSYS_OPT_NAMES */ extern __checkReturn efx_rc_t ef10_phy_prop_get( __in efx_nic_t *enp, __in unsigned int id, __in uint32_t flags, __out uint32_t *valp); extern __checkReturn efx_rc_t ef10_phy_prop_set( __in efx_nic_t *enp, __in unsigned int id, __in uint32_t val); #endif /* EFSYS_OPT_PHY_PROPS */ #if EFSYS_OPT_BIST extern __checkReturn efx_rc_t hunt_bist_enable_offline( __in efx_nic_t *enp); extern __checkReturn efx_rc_t hunt_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type); extern __checkReturn efx_rc_t hunt_bist_poll( __in efx_nic_t *enp, __in efx_bist_type_t type, __out efx_bist_result_t *resultp, __out_opt __drv_when(count > 0, __notnull) uint32_t *value_maskp, __out_ecount_opt(count) __drv_when(count > 0, __notnull) unsigned long *valuesp, __in size_t count); extern void hunt_bist_stop( __in efx_nic_t *enp, __in efx_bist_type_t type); #endif /* EFSYS_OPT_BIST */ /* TX */ extern __checkReturn efx_rc_t ef10_tx_init( __in efx_nic_t *enp); extern void ef10_tx_fini( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __in efx_txq_t *etp, __out unsigned int *addedp); extern void ef10_tx_qdestroy( __in efx_txq_t *etp); extern __checkReturn efx_rc_t ef10_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); extern void ef10_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed); extern __checkReturn efx_rc_t ef10_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns); extern __checkReturn efx_rc_t ef10_tx_qflush( __in efx_txq_t *etp); extern void ef10_tx_qenable( __in efx_txq_t *etp); extern __checkReturn efx_rc_t ef10_tx_qpio_enable( __in efx_txq_t *etp); extern void ef10_tx_qpio_disable( __in efx_txq_t *etp); extern __checkReturn efx_rc_t ef10_tx_qpio_write( __in efx_txq_t *etp, __in_ecount(buf_length) uint8_t *buffer, __in size_t buf_length, __in size_t pio_buf_offset); extern __checkReturn efx_rc_t ef10_tx_qpio_post( __in efx_txq_t *etp, __in size_t pkt_length, __in unsigned int completed, __inout unsigned int *addedp); extern __checkReturn efx_rc_t ef10_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); extern void ef10_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp); extern void -hunt_tx_qdesc_tso_create( +ef10_tx_qdesc_tso_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint8_t tcp_flags, __out efx_desc_t *edp); extern void ef10_tx_qdesc_tso2_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint16_t tcp_mss, __out_ecount(count) efx_desc_t *edp, __in int count); extern void ef10_tx_qdesc_vlantci_create( __in efx_txq_t *etp, __in uint16_t vlan_tci, __out efx_desc_t *edp); #if EFSYS_OPT_QSTATS extern void ef10_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat); #endif /* EFSYS_OPT_QSTATS */ /* PIO */ /* Missing register definitions */ #ifndef ER_DZ_TX_PIOBUF_OFST #define ER_DZ_TX_PIOBUF_OFST 0x00001000 #endif #ifndef ER_DZ_TX_PIOBUF_STEP #define ER_DZ_TX_PIOBUF_STEP 8192 #endif #ifndef ER_DZ_TX_PIOBUF_ROWS #define ER_DZ_TX_PIOBUF_ROWS 2048 #endif #ifndef ER_DZ_TX_PIOBUF_SIZE #define ER_DZ_TX_PIOBUF_SIZE 2048 #endif #define HUNT_PIOBUF_NBUFS (16) #define HUNT_PIOBUF_SIZE (ER_DZ_TX_PIOBUF_SIZE) #define HUNT_MIN_PIO_ALLOC_SIZE (HUNT_PIOBUF_SIZE / 32) #define EF10_LEGACY_PF_PRIVILEGE_MASK \ (MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST | \ MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS) #define EF10_LEGACY_VF_PRIVILEGE_MASK 0 typedef uint32_t efx_piobuf_handle_t; #define EFX_PIOBUF_HANDLE_INVALID ((efx_piobuf_handle_t) -1) extern __checkReturn efx_rc_t ef10_nic_pio_alloc( __inout efx_nic_t *enp, __out uint32_t *bufnump, __out efx_piobuf_handle_t *handlep, __out uint32_t *blknump, __out uint32_t *offsetp, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_nic_pio_free( __inout efx_nic_t *enp, __in uint32_t bufnum, __in uint32_t blknum); extern __checkReturn efx_rc_t ef10_nic_pio_link( __inout efx_nic_t *enp, __in uint32_t vi_index, __in efx_piobuf_handle_t handle); extern __checkReturn efx_rc_t ef10_nic_pio_unlink( __inout efx_nic_t *enp, __in uint32_t vi_index); /* VPD */ #if EFSYS_OPT_VPD extern __checkReturn efx_rc_t ef10_vpd_init( __in efx_nic_t *enp); extern __checkReturn efx_rc_t ef10_vpd_size( __in efx_nic_t *enp, __out size_t *sizep); extern __checkReturn efx_rc_t ef10_vpd_read( __in efx_nic_t *enp, __out_bcount(size) caddr_t data, __in size_t size); extern __checkReturn efx_rc_t ef10_vpd_verify( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size); extern __checkReturn efx_rc_t ef10_vpd_reinit( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size); extern __checkReturn efx_rc_t ef10_vpd_get( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size, __inout efx_vpd_value_t *evvp); extern __checkReturn efx_rc_t ef10_vpd_set( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_value_t *evvp); extern __checkReturn efx_rc_t ef10_vpd_next( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size, __out efx_vpd_value_t *evvp, __inout unsigned int *contp); extern __checkReturn efx_rc_t ef10_vpd_write( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size); extern void ef10_vpd_fini( __in efx_nic_t *enp); #endif /* EFSYS_OPT_VPD */ /* RX */ extern __checkReturn efx_rc_t ef10_rx_init( __in efx_nic_t *enp); #if EFSYS_OPT_RX_SCATTER extern __checkReturn efx_rc_t ef10_rx_scatter_enable( __in efx_nic_t *enp, __in unsigned int buf_size); #endif /* EFSYS_OPT_RX_SCATTER */ #if EFSYS_OPT_RX_SCALE extern __checkReturn efx_rc_t ef10_rx_scale_mode_set( __in efx_nic_t *enp, __in efx_rx_hash_alg_t alg, __in efx_rx_hash_type_t type, __in boolean_t insert); extern __checkReturn efx_rc_t ef10_rx_scale_key_set( __in efx_nic_t *enp, __in_ecount(n) uint8_t *key, __in size_t n); extern __checkReturn efx_rc_t ef10_rx_scale_tbl_set( __in efx_nic_t *enp, __in_ecount(n) unsigned int *table, __in size_t n); extern __checkReturn uint32_t ef10_rx_prefix_hash( __in efx_nic_t *enp, __in efx_rx_hash_alg_t func, __in uint8_t *buffer); #endif /* EFSYS_OPT_RX_SCALE */ extern __checkReturn efx_rc_t ef10_rx_prefix_pktlen( __in efx_nic_t *enp, __in uint8_t *buffer, __out uint16_t *lengthp); extern void ef10_rx_qpost( __in efx_rxq_t *erp, __in_ecount(n) efsys_dma_addr_t *addrp, __in size_t size, __in unsigned int n, __in unsigned int completed, __in unsigned int added); extern void ef10_rx_qpush( __in efx_rxq_t *erp, __in unsigned int added, __inout unsigned int *pushedp); extern __checkReturn efx_rc_t ef10_rx_qflush( __in efx_rxq_t *erp); extern void ef10_rx_qenable( __in efx_rxq_t *erp); extern __checkReturn efx_rc_t ef10_rx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efx_rxq_type_t type, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep, __in efx_rxq_t *erp); extern void ef10_rx_qdestroy( __in efx_rxq_t *erp); extern void ef10_rx_fini( __in efx_nic_t *enp); #if EFSYS_OPT_FILTER typedef struct ef10_filter_handle_s { uint32_t efh_lo; uint32_t efh_hi; } ef10_filter_handle_t; typedef struct ef10_filter_entry_s { uintptr_t efe_spec; /* pointer to filter spec plus busy bit */ ef10_filter_handle_t efe_handle; } ef10_filter_entry_t; /* * BUSY flag indicates that an update is in progress. * AUTO_OLD flag is used to mark and sweep MAC packet filters. */ #define EFX_EF10_FILTER_FLAG_BUSY 1U #define EFX_EF10_FILTER_FLAG_AUTO_OLD 2U #define EFX_EF10_FILTER_FLAGS 3U /* * Size of the hash table used by the driver. Doesn't need to be the * same size as the hardware's table. */ #define EFX_EF10_FILTER_TBL_ROWS 8192 /* Only need to allow for one directed and one unknown unicast filter */ #define EFX_EF10_FILTER_UNICAST_FILTERS_MAX 2 /* Allow for the broadcast address to be added to the multicast list */ #define EFX_EF10_FILTER_MULTICAST_FILTERS_MAX (EFX_MAC_MULTICAST_LIST_MAX + 1) typedef struct ef10_filter_table_s { ef10_filter_entry_t eft_entry[EFX_EF10_FILTER_TBL_ROWS]; efx_rxq_t * eft_default_rxq; boolean_t eft_using_rss; uint32_t eft_unicst_filter_indexes[ EFX_EF10_FILTER_UNICAST_FILTERS_MAX]; boolean_t eft_unicst_filter_count; uint32_t eft_mulcst_filter_indexes[ EFX_EF10_FILTER_MULTICAST_FILTERS_MAX]; uint32_t eft_mulcst_filter_count; boolean_t eft_using_all_mulcst; } ef10_filter_table_t; __checkReturn efx_rc_t ef10_filter_init( __in efx_nic_t *enp); void ef10_filter_fini( __in efx_nic_t *enp); __checkReturn efx_rc_t ef10_filter_restore( __in efx_nic_t *enp); __checkReturn efx_rc_t ef10_filter_add( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec, __in boolean_t may_replace); __checkReturn efx_rc_t ef10_filter_delete( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec); extern __checkReturn efx_rc_t ef10_filter_supported_filters( __in efx_nic_t *enp, __out uint32_t *list, __out size_t *length); extern __checkReturn efx_rc_t ef10_filter_reconfigure( __in efx_nic_t *enp, __in_ecount(6) uint8_t const *mac_addr, __in boolean_t all_unicst, __in boolean_t mulcst, __in boolean_t all_mulcst, __in boolean_t brdcst, __in_ecount(6*count) uint8_t const *addrs, __in uint32_t count); extern void ef10_filter_get_default_rxq( __in efx_nic_t *enp, __out efx_rxq_t **erpp, __out boolean_t *using_rss); extern void ef10_filter_default_rxq_set( __in efx_nic_t *enp, __in efx_rxq_t *erp, __in boolean_t using_rss); extern void ef10_filter_default_rxq_clear( __in efx_nic_t *enp); #endif /* EFSYS_OPT_FILTER */ extern __checkReturn efx_rc_t efx_mcdi_get_function_info( __in efx_nic_t *enp, __out uint32_t *pfp, __out_opt uint32_t *vfp); extern __checkReturn efx_rc_t efx_mcdi_privilege_mask( __in efx_nic_t *enp, __in uint32_t pf, __in uint32_t vf, __out uint32_t *maskp); #ifdef __cplusplus } #endif #endif /* _SYS_HUNT_IMPL_H */ Index: stable/10/sys/dev/sfxge/common/hunt_nic.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_nic.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_nic.c (revision 301344) @@ -1,1897 +1,324 @@ /*- * Copyright (c) 2012-2015 Solarflare Communications 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: * * 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 OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_MON_MCDI #include "mcdi_mon.h" #endif #if EFSYS_OPT_HUNTINGTON -#include "ef10_tlv_layout.h" __checkReturn efx_rc_t -efx_mcdi_get_port_assignment( - __in efx_nic_t *enp, - __out uint32_t *portp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, - MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_port_modes( - __in efx_nic_t *enp, - __out uint32_t *modesp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, - MC_CMD_GET_PORT_MODES_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PORT_MODES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - /* - * Require only Modes and DefaultMode fields. - * (CurrentMode field was added for Medford) - */ - if (req.emr_out_length_used < - MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { - rc = EMSGSIZE; - goto fail2; - } - - *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_vadaptor_alloc( - __in efx_nic_t *enp, - __in uint32_t port_id) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, - MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; - - MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); - MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, - VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, - enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_vadaptor_free( - __in efx_nic_t *enp, - __in uint32_t port_id) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, - MC_CMD_VADAPTOR_FREE_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VADAPTOR_FREE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; - - MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_mac_address_pf( - __in efx_nic_t *enp, - __out_ecount_opt(6) uint8_t mac_addrp[6]) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, - MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { - rc = ENOENT; - goto fail3; - } - - if (mac_addrp != NULL) { - uint8_t *addrp; - - addrp = MCDI_OUT2(req, uint8_t, - GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); - - EFX_MAC_ADDR_COPY(mac_addrp, addrp); - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_mac_address_vf( - __in efx_nic_t *enp, - __out_ecount_opt(6) uint8_t mac_addrp[6]) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, - MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; - - MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, - EVB_PORT_ID_ASSIGNED); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < - MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { - rc = EMSGSIZE; - goto fail2; - } - - if (MCDI_OUT_DWORD(req, - VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { - rc = ENOENT; - goto fail3; - } - - if (mac_addrp != NULL) { - uint8_t *addrp; - - addrp = MCDI_OUT2(req, uint8_t, - VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); - - EFX_MAC_ADDR_COPY(mac_addrp, addrp); - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_clock( - __in efx_nic_t *enp, - __out uint32_t *sys_freqp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, - MC_CMD_GET_CLOCK_OUT_LEN)]; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_CLOCK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); - if (*sys_freqp == 0) { - rc = EINVAL; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -efx_mcdi_get_vector_cfg( - __in efx_nic_t *enp, - __out_opt uint32_t *vec_basep, - __out_opt uint32_t *pf_nvecp, - __out_opt uint32_t *vf_nvecp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, - MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_VECTOR_CFG; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - if (vec_basep != NULL) - *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); - if (pf_nvecp != NULL) - *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); - if (vf_nvecp != NULL) - *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_get_capabilities( - __in efx_nic_t *enp, - __out uint32_t *flagsp, - __out uint32_t *flags2p) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, - MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_CAPABILITIES; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); - - if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) - *flags2p = 0; - else - *flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_alloc_vis( - __in efx_nic_t *enp, - __in uint32_t min_vi_count, - __in uint32_t max_vi_count, - __out uint32_t *vi_basep, - __out uint32_t *vi_countp, - __out uint32_t *vi_shiftp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, - MC_CMD_ALLOC_VIS_OUT_LEN)]; - efx_rc_t rc; - - if (vi_countp == NULL) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ALLOC_VIS; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; - - MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); - MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); - *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); - - /* Report VI_SHIFT if available (always zero for Huntington) */ - if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) - *vi_shiftp = 0; - else - *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_free_vis( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - efx_rc_t rc; - - EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); - EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); - - req.emr_cmd = MC_CMD_FREE_VIS; - req.emr_in_buf = NULL; - req.emr_in_length = 0; - req.emr_out_buf = NULL; - req.emr_out_length = 0; - - efx_mcdi_execute_quiet(enp, &req); - - /* Ignore ELREADY (no allocated VIs, so nothing to free) */ - if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -static __checkReturn efx_rc_t -efx_mcdi_alloc_piobuf( - __in efx_nic_t *enp, - __out efx_piobuf_handle_t *handlep) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, - MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - if (handlep == NULL) { - rc = EINVAL; - goto fail1; - } - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ALLOC_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; - - efx_mcdi_execute_quiet(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } - - if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { - rc = EMSGSIZE; - goto fail3; - } - - *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_free_piobuf( - __in efx_nic_t *enp, - __in efx_piobuf_handle_t handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, - MC_CMD_FREE_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_FREE_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); - - efx_mcdi_execute_quiet(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_link_piobuf( - __in efx_nic_t *enp, - __in uint32_t vi_index, - __in efx_piobuf_handle_t handle) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, - MC_CMD_LINK_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_LINK_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); - MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static __checkReturn efx_rc_t -efx_mcdi_unlink_piobuf( - __in efx_nic_t *enp, - __in uint32_t vi_index) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, - MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_UNLINK_PIOBUF; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; - - MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -static void -ef10_nic_alloc_piobufs( - __in efx_nic_t *enp, - __in uint32_t max_piobuf_count) -{ - efx_piobuf_handle_t *handlep; - unsigned int i; - efx_rc_t rc; - - EFSYS_ASSERT3U(max_piobuf_count, <=, - EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); - - enp->en_arch.ef10.ena_piobuf_count = 0; - - for (i = 0; i < max_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) - goto fail1; - - enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; - enp->en_arch.ef10.ena_piobuf_count++; - } - - return; - -fail1: - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - efx_mcdi_free_piobuf(enp, *handlep); - *handlep = EFX_PIOBUF_HANDLE_INVALID; - } - enp->en_arch.ef10.ena_piobuf_count = 0; -} - - -static void -ef10_nic_free_piobufs( - __in efx_nic_t *enp) -{ - efx_piobuf_handle_t *handlep; - unsigned int i; - - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; - - efx_mcdi_free_piobuf(enp, *handlep); - *handlep = EFX_PIOBUF_HANDLE_INVALID; - } - enp->en_arch.ef10.ena_piobuf_count = 0; -} - -/* Sub-allocate a block from a piobuf */ - __checkReturn efx_rc_t -ef10_nic_pio_alloc( - __inout efx_nic_t *enp, - __out uint32_t *bufnump, - __out efx_piobuf_handle_t *handlep, - __out uint32_t *blknump, - __out uint32_t *offsetp, - __out size_t *sizep) -{ - efx_nic_cfg_t *encp = &enp->en_nic_cfg; - efx_drv_cfg_t *edcp = &enp->en_drv_cfg; - uint32_t blk_per_buf; - uint32_t buf, blk; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - EFSYS_ASSERT(bufnump); - EFSYS_ASSERT(handlep); - EFSYS_ASSERT(blknump); - EFSYS_ASSERT(offsetp); - EFSYS_ASSERT(sizep); - - if ((edcp->edc_pio_alloc_size == 0) || - (enp->en_arch.ef10.ena_piobuf_count == 0)) { - rc = ENOMEM; - goto fail1; - } - blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; - - for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { - uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; - - if (~(*map) == 0) - continue; - - EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); - for (blk = 0; blk < blk_per_buf; blk++) { - if ((*map & (1u << blk)) == 0) { - *map |= (1u << blk); - goto done; - } - } - } - rc = ENOMEM; - goto fail2; - -done: - *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; - *bufnump = buf; - *blknump = blk; - *sizep = edcp->edc_pio_alloc_size; - *offsetp = blk * (*sizep); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -/* Free a piobuf sub-allocated block */ - __checkReturn efx_rc_t -ef10_nic_pio_free( - __inout efx_nic_t *enp, - __in uint32_t bufnum, - __in uint32_t blknum) -{ - uint32_t *map; - efx_rc_t rc; - - if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || - (blknum >= (8 * sizeof (*map)))) { - rc = EINVAL; - goto fail1; - } - - map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; - if ((*map & (1u << blknum)) == 0) { - rc = ENOENT; - goto fail2; - } - *map &= ~(1u << blknum); - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_pio_link( - __inout efx_nic_t *enp, - __in uint32_t vi_index, - __in efx_piobuf_handle_t handle) -{ - return (efx_mcdi_link_piobuf(enp, vi_index, handle)); -} - - __checkReturn efx_rc_t -ef10_nic_pio_unlink( - __inout efx_nic_t *enp, - __in uint32_t vi_index) -{ - return (efx_mcdi_unlink_piobuf(enp, vi_index)); -} - - __checkReturn efx_rc_t -ef10_get_datapath_caps( - __in efx_nic_t *enp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t flags; - uint32_t flags2; - efx_rc_t rc; - - if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0) - goto fail1; - -#define CAP_FLAG(flags1, field) \ - ((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) - -#define CAP_FLAG2(flags2, field) \ - ((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) - - /* - * Huntington RXDP firmware inserts a 0 or 14 byte prefix. - * We only support the 14 byte prefix here. - */ - if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) { - rc = ENOTSUP; - goto fail2; - } - encp->enc_rx_prefix_size = 14; - - /* Check if the firmware supports TSO */ - encp->enc_fw_assisted_tso_enabled = - CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports FATSOv2 */ - encp->enc_fw_assisted_tso_v2_enabled = - CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE; - - /* Check if the firmware has vadapter/vport/vswitch support */ - encp->enc_datapath_cap_evb = - CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports VLAN insertion */ - encp->enc_hw_tx_insert_vlan_enabled = - CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports RX event batching */ - encp->enc_rx_batching_enabled = - CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE; - - if (encp->enc_rx_batching_enabled) - encp->enc_rx_batch_max = 16; - - /* Check if the firmware supports disabling scatter on RXQs */ - encp->enc_rx_disable_scatter_supported = - CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; - - /* Check if the firmware supports set mac with running filters */ - encp->enc_allow_set_mac_with_installed_filters = - CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? - B_TRUE : B_FALSE; - - /* - * Check if firmware supports the extended MC_CMD_SET_MAC, which allows - * specifying which parameters to configure. - */ - encp->enc_enhanced_set_mac_supported = - CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; - -#undef CAP_FLAG -#undef CAP_FLAG2 - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - __checkReturn efx_rc_t -ef10_get_privilege_mask( - __in efx_nic_t *enp, - __out uint32_t *maskp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - uint32_t mask; - efx_rc_t rc; - - if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, - &mask)) != 0) { - if (rc != ENOTSUP) - goto fail1; - - /* Fallback for old firmware without privilege mask support */ - if (EFX_PCI_FUNCTION_IS_PF(encp)) { - /* Assume PF has admin privilege */ - mask = EF10_LEGACY_PF_PRIVILEGE_MASK; - } else { - /* VF is always unprivileged by default */ - mask = EF10_LEGACY_VF_PRIVILEGE_MASK; - } - } - - *maskp = mask; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - -/* - * The external port mapping is a one-based numbering of the external - * connectors on the board. It does not distinguish off-board separated - * outputs such as multi-headed cables. - * The number of ports that map to each external port connector - * on the board is determined by the chip family and the port modes to - * which the NIC can be configured. The mapping table lists modes with - * port numbering requirements in increasing order. - */ -static struct { - efx_family_t family; - uint32_t modes_mask; - uint32_t stride; -} __ef10_external_port_mappings[] = { - /* Supported modes requiring 1 output per port */ - { - EFX_FAMILY_HUNTINGTON, - (1 << TLV_PORT_MODE_10G) | - (1 << TLV_PORT_MODE_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G), - 1 - }, - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_10G) | - (1 << TLV_PORT_MODE_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G), - 1 - }, - /* Supported modes requiring 2 outputs per port */ - { - EFX_FAMILY_HUNTINGTON, - (1 << TLV_PORT_MODE_40G) | - (1 << TLV_PORT_MODE_40G_40G) | - (1 << TLV_PORT_MODE_40G_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_40G), - 2 - }, - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_40G) | - (1 << TLV_PORT_MODE_40G_40G) | - (1 << TLV_PORT_MODE_40G_10G_10G) | - (1 << TLV_PORT_MODE_10G_10G_40G), - 2 - }, - /* Supported modes requiring 4 outputs per port */ - { - EFX_FAMILY_MEDFORD, - (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) | - (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2), - 4 - }, -}; - - __checkReturn efx_rc_t -ef10_external_port_mapping( - __in efx_nic_t *enp, - __in uint32_t port, - __out uint8_t *external_portp) -{ - efx_rc_t rc; - int i; - uint32_t port_modes; - uint32_t matches; - uint32_t stride = 1; /* default 1-1 mapping */ - - if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { - /* No port mode information available - use default mapping */ - goto out; - } - - /* - * Infer the internal port -> external port mapping from - * the possible port modes for this NIC. - */ - for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { - if (__ef10_external_port_mappings[i].family != - enp->en_family) - continue; - matches = (__ef10_external_port_mappings[i].modes_mask & - port_modes); - if (matches != 0) { - stride = __ef10_external_port_mappings[i].stride; - port_modes &= ~matches; - } - } - - if (port_modes != 0) { - /* Some advertised modes are not supported */ - rc = ENOTSUP; - goto fail1; - } - -out: - /* - * Scale as required by last matched mode and then convert to - * one-based numbering - */ - *external_portp = (uint8_t)(port / stride) + 1; - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t hunt_board_cfg( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint8_t mac_addr[6]; uint32_t board_type = 0; ef10_link_state_t els; efx_port_t *epp = &(enp->en_port); uint32_t port; uint32_t pf; uint32_t vf; uint32_t mask; uint32_t flags; uint32_t sysclk; uint32_t base, nvec; efx_rc_t rc; if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0) goto fail1; /* * NOTE: The MCDI protocol numbers ports from zero. * The common code MCDI interface numbers ports from one. */ emip->emi_port = port + 1; if ((rc = ef10_external_port_mapping(enp, port, &encp->enc_external_port)) != 0) goto fail2; /* * Get PCIe function number from firmware (used for * per-function privilege and dynamic config info). * - PCIe PF: pf = PF number, vf = 0xffff. * - PCIe VF: pf = parent PF, vf = VF number. */ if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0) goto fail3; encp->enc_pf = pf; encp->enc_vf = vf; /* MAC address for this function */ if (EFX_PCI_FUNCTION_IS_PF(encp)) { rc = efx_mcdi_get_mac_address_pf(enp, mac_addr); if ((rc == 0) && (mac_addr[0] & 0x02)) { /* * If the static config does not include a global MAC * address pool then the board may return a locally * administered MAC address (this should only happen on * incorrectly programmed boards). */ rc = EINVAL; } } else { rc = efx_mcdi_get_mac_address_vf(enp, mac_addr); } if (rc != 0) goto fail4; EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); /* Board configuration */ rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL); if (rc != 0) { /* Unprivileged functions may not be able to read board cfg */ if (rc == EACCES) board_type = 0; else goto fail5; } encp->enc_board_type = board_type; encp->enc_clk_mult = 1; /* not used for Huntington */ /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) goto fail6; /* Obtain the default PHY advertised capabilities */ if ((rc = ef10_phy_get_link(enp, &els)) != 0) goto fail7; epp->ep_default_adv_cap_mask = els.els_adv_cap_mask; epp->ep_adv_cap_mask = els.els_adv_cap_mask; /* * Enable firmware workarounds for hardware errata. * Expected responses are: * - 0 (zero): * Success: workaround enabled or disabled as requested. * - MC_CMD_ERR_ENOSYS (reported as ENOTSUP): * Firmware does not support the MC_CMD_WORKAROUND request. * (assume that the workaround is not supported). * - MC_CMD_ERR_ENOENT (reported as ENOENT): * Firmware does not support the requested workaround. * - MC_CMD_ERR_EPERM (reported as EACCES): * Unprivileged function cannot enable/disable workarounds. * * See efx_mcdi_request_errcode() for MCDI error translations. */ /* * If the bug35388 workaround is enabled, then use an indirect access * method to avoid unsafe EVQ writes. */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE, NULL); if ((rc == 0) || (rc == EACCES)) encp->enc_bug35388_workaround = B_TRUE; else if ((rc == ENOTSUP) || (rc == ENOENT)) encp->enc_bug35388_workaround = B_FALSE; else goto fail8; /* * If the bug41750 workaround is enabled, then do not test interrupts, * as the test will fail (seen with Greenport controllers). */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE, NULL); if (rc == 0) { encp->enc_bug41750_workaround = B_TRUE; } else if (rc == EACCES) { /* Assume a controller with 40G ports needs the workaround. */ if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX) encp->enc_bug41750_workaround = B_TRUE; else encp->enc_bug41750_workaround = B_FALSE; } else if ((rc == ENOTSUP) || (rc == ENOENT)) { encp->enc_bug41750_workaround = B_FALSE; } else { goto fail9; } if (EFX_PCI_FUNCTION_IS_VF(encp)) { /* Interrupt testing does not work for VFs. See bug50084. */ encp->enc_bug41750_workaround = B_TRUE; } /* * If the bug26807 workaround is enabled, then firmware has enabled * support for chained multicast filters. Firmware will reset (FLR) * functions which have filters in the hardware filter table when the * workaround is enabled/disabled. * * We must recheck if the workaround is enabled after inserting the * first hardware filter, in case it has been changed since this check. */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807, B_TRUE, &flags); if (rc == 0) { encp->enc_bug26807_workaround = B_TRUE; if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) { /* * Other functions had installed filters before the * workaround was enabled, and they have been reset * by firmware. */ EFSYS_PROBE(bug26807_workaround_flr_done); /* FIXME: bump MC warm boot count ? */ } } else if (rc == EACCES) { /* * Unprivileged functions cannot enable the workaround in older * firmware. */ encp->enc_bug26807_workaround = B_FALSE; } else if ((rc == ENOTSUP) || (rc == ENOENT)) { encp->enc_bug26807_workaround = B_FALSE; } else { goto fail10; } /* Get sysclk frequency (in MHz). */ if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0) goto fail11; /* * The timer quantum is 1536 sysclk cycles, documented for the * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units. */ encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */ if (encp->enc_bug35388_workaround) { encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000; } else { encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000; } /* Check capabilities of running datapath firmware */ if ((rc = ef10_get_datapath_caps(enp)) != 0) goto fail12; /* Alignment for receive packet DMA buffers */ encp->enc_rx_buf_align_start = 1; encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */ /* Alignment for WPTR updates */ encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN; /* * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available * resources (allocated to this PCIe function), which is zero until * after we have allocated VIs. */ encp->enc_evq_limit = 1024; encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET; encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET; encp->enc_buftbl_limit = 0xFFFFFFFF; encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS; encp->enc_piobuf_size = HUNT_PIOBUF_SIZE; encp->enc_piobuf_min_alloc_size = HUNT_MIN_PIO_ALLOC_SIZE; /* * Get the current privilege mask. Note that this may be modified * dynamically, so this value is informational only. DO NOT use * the privilege mask to check for sufficient privileges, as that * can result in time-of-check/time-of-use bugs. */ if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0) goto fail13; encp->enc_privilege_mask = mask; /* Get interrupt vector limits */ if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) { if (EFX_PCI_FUNCTION_IS_PF(encp)) goto fail14; /* Ignore error (cannot query vector limits from a VF). */ base = 0; nvec = 1024; } encp->enc_intr_vec_base = base; encp->enc_intr_limit = nvec; /* * Maximum number of bytes into the frame the TCP header can start for * firmware assisted TSO to work. */ encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT; return (0); fail14: EFSYS_PROBE(fail14); fail13: EFSYS_PROBE(fail13); fail12: EFSYS_PROBE(fail12); fail11: EFSYS_PROBE(fail11); fail10: EFSYS_PROBE(fail10); fail9: EFSYS_PROBE(fail9); fail8: EFSYS_PROBE(fail8); fail7: EFSYS_PROBE(fail7); fail6: EFSYS_PROBE(fail6); fail5: EFSYS_PROBE(fail5); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } - - - __checkReturn efx_rc_t -ef10_nic_probe( - __in efx_nic_t *enp) -{ - const efx_nic_ops_t *enop = enp->en_enop; - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Read and clear any assertion state */ - if ((rc = efx_mcdi_read_assertion(enp)) != 0) - goto fail1; - - /* Exit the assertion handler */ - if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) - if (rc != EACCES) - goto fail2; - - if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) - goto fail3; - - if ((rc = enop->eno_board_cfg(enp)) != 0) - if (rc != EACCES) - goto fail4; - - /* - * Set default driver config limits (based on board config). - * - * FIXME: For now allocate a fixed number of VIs which is likely to be - * sufficient and small enough to allow multiple functions on the same - * port. - */ - edcp->edc_min_vi_count = edcp->edc_max_vi_count = - MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); - - /* The client driver must configure and enable PIO buffer support */ - edcp->edc_max_piobuf_count = 0; - edcp->edc_pio_alloc_size = 0; - -#if EFSYS_OPT_MAC_STATS - /* Wipe the MAC statistics */ - if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) - goto fail5; -#endif - -#if EFSYS_OPT_LOOPBACK - if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) - goto fail6; -#endif - -#if EFSYS_OPT_MON_STATS - if ((rc = mcdi_mon_cfg_build(enp)) != 0) { - /* Unprivileged functions do not have access to sensors */ - if (rc != EACCES) - goto fail7; - } -#endif - - encp->enc_features = enp->en_features; - - return (0); - -#if EFSYS_OPT_MON_STATS -fail7: - EFSYS_PROBE(fail7); -#endif -#if EFSYS_OPT_LOOPBACK -fail6: - EFSYS_PROBE(fail6); -#endif -#if EFSYS_OPT_MAC_STATS -fail5: - EFSYS_PROBE(fail5); -#endif -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_set_drv_limits( - __inout efx_nic_t *enp, - __in efx_drv_limits_t *edlp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - uint32_t min_evq_count, max_evq_count; - uint32_t min_rxq_count, max_rxq_count; - uint32_t min_txq_count, max_txq_count; - efx_rc_t rc; - - if (edlp == NULL) { - rc = EINVAL; - goto fail1; - } - - /* Get minimum required and maximum usable VI limits */ - min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); - min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); - min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); - - edcp->edc_min_vi_count = - MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); - - max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); - max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); - max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); - - edcp->edc_max_vi_count = - MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); - - /* - * Check limits for sub-allocated piobuf blocks. - * PIO is optional, so don't fail if the limits are incorrect. - */ - if ((encp->enc_piobuf_size == 0) || - (encp->enc_piobuf_limit == 0) || - (edlp->edl_min_pio_alloc_size == 0) || - (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { - /* Disable PIO */ - edcp->edc_max_piobuf_count = 0; - edcp->edc_pio_alloc_size = 0; - } else { - uint32_t blk_size, blk_count, blks_per_piobuf; - - blk_size = - MAX(edlp->edl_min_pio_alloc_size, - encp->enc_piobuf_min_alloc_size); - - blks_per_piobuf = encp->enc_piobuf_size / blk_size; - EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); - - blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); - - /* A zero max pio alloc count means unlimited */ - if ((edlp->edl_max_pio_alloc_count > 0) && - (edlp->edl_max_pio_alloc_count < blk_count)) { - blk_count = edlp->edl_max_pio_alloc_count; - } - - edcp->edc_pio_alloc_size = blk_size; - edcp->edc_max_piobuf_count = - (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - - __checkReturn efx_rc_t -ef10_nic_reset( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, - MC_CMD_ENTITY_RESET_OUT_LEN)]; - efx_rc_t rc; - - /* ef10_nic_reset() is called to recover from BADASSERT failures. */ - if ((rc = efx_mcdi_read_assertion(enp)) != 0) - goto fail1; - if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) - goto fail2; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_ENTITY_RESET; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; - - MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, - ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail3; - } - - /* Clear RX/TX DMA queue errors */ - enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_init( - __in efx_nic_t *enp) -{ - efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); - uint32_t min_vi_count, max_vi_count; - uint32_t vi_count, vi_base, vi_shift; - uint32_t i; - uint32_t retry; - uint32_t delay_us; - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* Enable reporting of some events (e.g. link change) */ - if ((rc = efx_mcdi_log_ctrl(enp)) != 0) - goto fail1; - - /* Allocate (optional) on-chip PIO buffers */ - ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); - - /* - * For best performance, PIO writes should use a write-combined - * (WC) memory mapping. Using a separate WC mapping for the PIO - * aperture of each VI would be a burden to drivers (and not - * possible if the host page size is >4Kbyte). - * - * To avoid this we use a single uncached (UC) mapping for VI - * register access, and a single WC mapping for extra VIs used - * for PIO writes. - * - * Each piobuf must be linked to a VI in the WC mapping, and to - * each VI that is using a sub-allocated block from the piobuf. - */ - min_vi_count = edcp->edc_min_vi_count; - max_vi_count = - edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; - - /* Ensure that the previously attached driver's VIs are freed */ - if ((rc = efx_mcdi_free_vis(enp)) != 0) - goto fail2; - - /* - * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this - * fails then retrying the request for fewer VI resources may succeed. - */ - vi_count = 0; - if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, - &vi_base, &vi_count, &vi_shift)) != 0) - goto fail3; - - EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); - - if (vi_count < min_vi_count) { - rc = ENOMEM; - goto fail4; - } - - enp->en_arch.ef10.ena_vi_base = vi_base; - enp->en_arch.ef10.ena_vi_count = vi_count; - enp->en_arch.ef10.ena_vi_shift = vi_shift; - - if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { - /* Not enough extra VIs to map piobufs */ - ef10_nic_free_piobufs(enp); - } - - enp->en_arch.ef10.ena_pio_write_vi_base = - vi_count - enp->en_arch.ef10.ena_piobuf_count; - - /* Save UC memory mapping details */ - enp->en_arch.ef10.ena_uc_mem_map_offset = 0; - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - enp->en_arch.ef10.ena_uc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_pio_write_vi_base); - } else { - enp->en_arch.ef10.ena_uc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_vi_count); - } - - /* Save WC memory mapping details */ - enp->en_arch.ef10.ena_wc_mem_map_offset = - enp->en_arch.ef10.ena_uc_mem_map_offset + - enp->en_arch.ef10.ena_uc_mem_map_size; - - enp->en_arch.ef10.ena_wc_mem_map_size = - (ER_DZ_TX_PIOBUF_STEP * - enp->en_arch.ef10.ena_piobuf_count); - - /* Link piobufs to extra VIs in WC mapping */ - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - rc = efx_mcdi_link_piobuf(enp, - enp->en_arch.ef10.ena_pio_write_vi_base + i, - enp->en_arch.ef10.ena_piobuf_handle[i]); - if (rc != 0) - break; - } - } - - /* - * Allocate a vAdaptor attached to our upstream vPort/pPort. - * - * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF - * driver has yet to bring up the EVB port. See bug 56147. In this case, - * retry the request several times after waiting a while. The wait time - * between retries starts small (10ms) and exponentially increases. - * Total wait time is a little over two seconds. Retry logic in the - * client driver may mean this whole loop is repeated if it continues to - * fail. - */ - retry = 0; - delay_us = 10000; - while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { - if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || - (rc != ENOENT)) { - /* - * Do not retry alloc for PF, or for other errors on - * a VF. - */ - goto fail5; - } - - /* VF startup before PF is ready. Retry allocation. */ - if (retry > 5) { - /* Too many attempts */ - rc = EINVAL; - goto fail6; - } - EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); - EFSYS_SLEEP(delay_us); - retry++; - if (delay_us < 500000) - delay_us <<= 2; - } - - enp->en_vport_id = EVB_PORT_ID_ASSIGNED; - enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; - - return (0); - -fail6: - EFSYS_PROBE(fail6); -fail5: - EFSYS_PROBE(fail5); -fail4: - EFSYS_PROBE(fail4); -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); - - ef10_nic_free_piobufs(enp); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_nic_get_vi_pool( - __in efx_nic_t *enp, - __out uint32_t *vi_countp) -{ - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * Report VIs that the client driver can use. - * Do not include VIs used for PIO buffer writes. - */ - *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; - - return (0); -} - - __checkReturn efx_rc_t -ef10_nic_get_bar_region( - __in efx_nic_t *enp, - __in efx_nic_region_t region, - __out uint32_t *offsetp, - __out size_t *sizep) -{ - efx_rc_t rc; - - EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || - enp->en_family == EFX_FAMILY_MEDFORD); - - /* - * TODO: Specify host memory mapping alignment and granularity - * in efx_drv_limits_t so that they can be taken into account - * when allocating extra VIs for PIO writes. - */ - switch (region) { - case EFX_REGION_VI: - /* UC mapped memory BAR region for VI registers */ - *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; - *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; - break; - - case EFX_REGION_PIO_WRITE_VI: - /* WC mapped memory BAR region for piobuf writes */ - *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; - *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; - break; - - default: - rc = EINVAL; - goto fail1; - } - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - void -ef10_nic_fini( - __in efx_nic_t *enp) -{ - uint32_t i; - efx_rc_t rc; - - (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); - enp->en_vport_id = 0; - - /* Unlink piobufs from extra VIs in WC mapping */ - if (enp->en_arch.ef10.ena_piobuf_count > 0) { - for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { - rc = efx_mcdi_unlink_piobuf(enp, - enp->en_arch.ef10.ena_pio_write_vi_base + i); - if (rc != 0) - break; - } - } - - ef10_nic_free_piobufs(enp); - - (void) efx_mcdi_free_vis(enp); - enp->en_arch.ef10.ena_vi_count = 0; -} - - void -ef10_nic_unprobe( - __in efx_nic_t *enp) -{ -#if EFSYS_OPT_MON_STATS - mcdi_mon_cfg_free(enp); -#endif /* EFSYS_OPT_MON_STATS */ - (void) efx_mcdi_drv_attach(enp, B_FALSE); -} - -#if EFSYS_OPT_DIAG - - __checkReturn efx_rc_t -ef10_nic_register_test( - __in efx_nic_t *enp) -{ - efx_rc_t rc; - - /* FIXME */ - _NOTE(ARGUNUSED(enp)) - if (B_FALSE) { - rc = ENOTSUP; - goto fail1; - } - /* FIXME */ - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - -#endif /* EFSYS_OPT_DIAG */ - #endif /* EFSYS_OPT_HUNTINGTON */ Index: stable/10/sys/dev/sfxge/common/hunt_phy.c =================================================================== --- stable/10/sys/dev/sfxge/common/hunt_phy.c (revision 301343) +++ stable/10/sys/dev/sfxge/common/hunt_phy.c (revision 301344) @@ -1,669 +1,190 @@ /*- * Copyright (c) 2012-2015 Solarflare Communications 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: * * 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 OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_HUNTINGTON -static void -mcdi_phy_decode_cap( - __in uint32_t mcdi_cap, - __out uint32_t *maskp) -{ - uint32_t mask; - - mask = 0; - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_100HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_100FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) - mask |= (1 << EFX_PHY_CAP_1000HDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_1000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_10000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) - mask |= (1 << EFX_PHY_CAP_40000FDX); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) - mask |= (1 << EFX_PHY_CAP_PAUSE); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) - mask |= (1 << EFX_PHY_CAP_ASYM); - if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) - mask |= (1 << EFX_PHY_CAP_AN); - - *maskp = mask; -} - -static void -mcdi_phy_decode_link_mode( - __in efx_nic_t *enp, - __in uint32_t link_flags, - __in unsigned int speed, - __in unsigned int fcntl, - __out efx_link_mode_t *link_modep, - __out unsigned int *fcntlp) -{ - boolean_t fd = !!(link_flags & - (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); - boolean_t up = !!(link_flags & - (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); - - _NOTE(ARGUNUSED(enp)) - - if (!up) - *link_modep = EFX_LINK_DOWN; - else if (speed == 40000 && fd) - *link_modep = EFX_LINK_40000FDX; - else if (speed == 10000 && fd) - *link_modep = EFX_LINK_10000FDX; - else if (speed == 1000) - *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; - else if (speed == 100) - *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; - else if (speed == 10) - *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; - else - *link_modep = EFX_LINK_UNKNOWN; - - if (fcntl == MC_CMD_FCNTL_OFF) - *fcntlp = 0; - else if (fcntl == MC_CMD_FCNTL_RESPOND) - *fcntlp = EFX_FCNTL_RESPOND; - else if (fcntl == MC_CMD_FCNTL_GENERATE) - *fcntlp = EFX_FCNTL_GENERATE; - else if (fcntl == MC_CMD_FCNTL_BIDIR) - *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; - else { - EFSYS_PROBE1(mc_pcol_error, int, fcntl); - *fcntlp = 0; - } -} - - - void -ef10_phy_link_ev( - __in efx_nic_t *enp, - __in efx_qword_t *eqp, - __out efx_link_mode_t *link_modep) -{ - efx_port_t *epp = &(enp->en_port); - unsigned int link_flags; - unsigned int speed; - unsigned int fcntl; - efx_link_mode_t link_mode; - uint32_t lp_cap_mask; - - /* - * Convert the LINKCHANGE speed enumeration into mbit/s, in the - * same way as GET_LINK encodes the speed - */ - switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { - case MCDI_EVENT_LINKCHANGE_SPEED_100M: - speed = 100; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_1G: - speed = 1000; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_10G: - speed = 10000; - break; - case MCDI_EVENT_LINKCHANGE_SPEED_40G: - speed = 40000; - break; - default: - speed = 0; - break; - } - - link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); - mcdi_phy_decode_link_mode(enp, link_flags, speed, - MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), - &link_mode, &fcntl); - mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), - &lp_cap_mask); - - /* - * It's safe to update ep_lp_cap_mask without the driver's port lock - * because presumably any concurrently running efx_port_poll() is - * only going to arrive at the same value. - * - * ep_fcntl has two meanings. It's either the link common fcntl - * (if the PHY supports AN), or it's the forced link state. If - * the former, it's safe to update the value for the same reason as - * for ep_lp_cap_mask. If the latter, then just ignore the value, - * because we can race with efx_mac_fcntl_set(). - */ - epp->ep_lp_cap_mask = lp_cap_mask; - epp->ep_fcntl = fcntl; - - *link_modep = link_mode; -} - - __checkReturn efx_rc_t -ef10_phy_power( - __in efx_nic_t *enp, - __in boolean_t power) -{ - efx_rc_t rc; - - if (!power) - return (0); - - /* Check if the PHY is a zombie */ - if ((rc = ef10_phy_verify(enp)) != 0) - goto fail1; - - enp->en_reset_flags |= EFX_RESET_PHY; - - return (0); - -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_get_link( - __in efx_nic_t *enp, - __out ef10_link_state_t *elsp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, - MC_CMD_GET_LINK_OUT_LEN)]; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_LINK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), - &elsp->els_adv_cap_mask); - mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), - &elsp->els_lp_cap_mask); - - mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), - MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), - MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), - &elsp->els_link_mode, &elsp->els_fcntl); - -#if EFSYS_OPT_LOOPBACK - /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); - EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); - - elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); -#endif /* EFSYS_OPT_LOOPBACK */ - - elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; - - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_reconfigure( - __in efx_nic_t *enp) -{ - efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_port_t *epp = &(enp->en_port); - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, - MC_CMD_SET_LINK_OUT_LEN)]; - uint32_t cap_mask; - unsigned int led_mode; - unsigned int speed; - efx_rc_t rc; - - if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL) - goto out; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_LINK; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; - - cap_mask = epp->ep_adv_cap_mask; - MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, - PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, - PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, - PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, - PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, - PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, - PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, - PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, - PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, - PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, - PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); - /* Too many fields for for POPULATE macros, so insert this afterwards */ - MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, - PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1); - -#if EFSYS_OPT_LOOPBACK - MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, - epp->ep_loopback_type); - switch (epp->ep_loopback_link_mode) { - case EFX_LINK_100FDX: - speed = 100; - break; - case EFX_LINK_1000FDX: - speed = 1000; - break; - case EFX_LINK_10000FDX: - speed = 10000; - break; - case EFX_LINK_40000FDX: - speed = 40000; - break; - default: - speed = 0; - } -#else - MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); - speed = 0; -#endif /* EFSYS_OPT_LOOPBACK */ - MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); - -#if EFSYS_OPT_PHY_FLAGS - MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); -#else - MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); -#endif /* EFSYS_OPT_PHY_FLAGS */ - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - /* And set the blink mode */ - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_SET_ID_LED; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; - -#if EFSYS_OPT_PHY_LED_CONTROL - switch (epp->ep_phy_led_mode) { - case EFX_PHY_LED_DEFAULT: - led_mode = MC_CMD_LED_DEFAULT; - break; - case EFX_PHY_LED_OFF: - led_mode = MC_CMD_LED_OFF; - break; - case EFX_PHY_LED_ON: - led_mode = MC_CMD_LED_ON; - break; - default: - EFSYS_ASSERT(0); - led_mode = MC_CMD_LED_DEFAULT; - } - - MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); -#else - MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); -#endif /* EFSYS_OPT_PHY_LED_CONTROL */ - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail2; - } -out: - return (0); - -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_verify( - __in efx_nic_t *enp) -{ - efx_mcdi_req_t req; - uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, - MC_CMD_GET_PHY_STATE_OUT_LEN)]; - uint32_t state; - efx_rc_t rc; - - (void) memset(payload, 0, sizeof (payload)); - req.emr_cmd = MC_CMD_GET_PHY_STATE; - req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; - req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; - - efx_mcdi_execute(enp, &req); - - if (req.emr_rc != 0) { - rc = req.emr_rc; - goto fail1; - } - - if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { - rc = EMSGSIZE; - goto fail2; - } - - state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); - if (state != MC_CMD_PHY_STATE_OK) { - if (state != MC_CMD_PHY_STATE_ZOMBIE) - EFSYS_PROBE1(mc_pcol_error, int, state); - rc = ENOTACTIVE; - goto fail3; - } - - return (0); - -fail3: - EFSYS_PROBE(fail3); -fail2: - EFSYS_PROBE(fail2); -fail1: - EFSYS_PROBE1(fail1, efx_rc_t, rc); - - return (rc); -} - - __checkReturn efx_rc_t -ef10_phy_oui_get( - __in efx_nic_t *enp, - __out uint32_t *ouip) -{ - _NOTE(ARGUNUSED(enp, ouip)) - - return (ENOTSUP); -} - -#if EFSYS_OPT_PHY_STATS - - __checkReturn efx_rc_t -ef10_phy_stats_update( - __in efx_nic_t *enp, - __in efsys_mem_t *esmp, - __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) -{ - /* TBD: no stats support in firmware yet */ - _NOTE(ARGUNUSED(enp, esmp)) - memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); - - return (0); -} - -#endif /* EFSYS_OPT_PHY_STATS */ - -#if EFSYS_OPT_PHY_PROPS - -#if EFSYS_OPT_NAMES - - const char * -ef10_phy_prop_name( - __in efx_nic_t *enp, - __in unsigned int id) -{ - _NOTE(ARGUNUSED(enp, id)) - - return (NULL); -} - -#endif /* EFSYS_OPT_NAMES */ - - __checkReturn efx_rc_t -ef10_phy_prop_get( - __in efx_nic_t *enp, - __in unsigned int id, - __in uint32_t flags, - __out uint32_t *valp) -{ - _NOTE(ARGUNUSED(enp, id, flags, valp)) - - return (ENOTSUP); -} - - __checkReturn efx_rc_t -ef10_phy_prop_set( - __in efx_nic_t *enp, - __in unsigned int id, - __in uint32_t val) -{ - _NOTE(ARGUNUSED(enp, id, val)) - - return (ENOTSUP); -} - -#endif /* EFSYS_OPT_PHY_PROPS */ - #if EFSYS_OPT_BIST __checkReturn efx_rc_t hunt_bist_enable_offline( __in efx_nic_t *enp) { efx_rc_t rc; if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t hunt_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_rc_t rc; if ((rc = efx_mcdi_bist_start(enp, type)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t hunt_bist_poll( __in efx_nic_t *enp, __in efx_bist_type_t type, __out efx_bist_result_t *resultp, __out_opt __drv_when(count > 0, __notnull) uint32_t *value_maskp, __out_ecount_opt(count) __drv_when(count > 0, __notnull) unsigned long *valuesp, __in size_t count) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, MCDI_CTL_SDU_LEN_MAX)]; uint32_t value_mask = 0; uint32_t result; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_POLL_BIST; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { rc = EMSGSIZE; goto fail2; } if (count > 0) (void) memset(valuesp, '\0', count * sizeof (unsigned long)); result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); if (result == MC_CMD_POLL_BIST_FAILED && req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN && count > EFX_BIST_MEM_ECC_FATAL) { if (valuesp != NULL) { valuesp[EFX_BIST_MEM_TEST] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST); valuesp[EFX_BIST_MEM_ADDR] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR); valuesp[EFX_BIST_MEM_BUS] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS); valuesp[EFX_BIST_MEM_EXPECT] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT); valuesp[EFX_BIST_MEM_ACTUAL] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL); valuesp[EFX_BIST_MEM_ECC] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC); valuesp[EFX_BIST_MEM_ECC_PARITY] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY); valuesp[EFX_BIST_MEM_ECC_FATAL] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL); } value_mask |= (1 << EFX_BIST_MEM_TEST) | (1 << EFX_BIST_MEM_ADDR) | (1 << EFX_BIST_MEM_BUS) | (1 << EFX_BIST_MEM_EXPECT) | (1 << EFX_BIST_MEM_ACTUAL) | (1 << EFX_BIST_MEM_ECC) | (1 << EFX_BIST_MEM_ECC_PARITY) | (1 << EFX_BIST_MEM_ECC_FATAL); } else if (result == MC_CMD_POLL_BIST_FAILED && encp->enc_phy_type == EFX_PHY_XFI_FARMI && req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && count > EFX_BIST_FAULT_CODE) { if (valuesp != NULL) valuesp[EFX_BIST_FAULT_CODE] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); value_mask |= 1 << EFX_BIST_FAULT_CODE; } if (value_maskp != NULL) *value_maskp = value_mask; EFSYS_ASSERT(resultp != NULL); if (result == MC_CMD_POLL_BIST_RUNNING) *resultp = EFX_BIST_RESULT_RUNNING; else if (result == MC_CMD_POLL_BIST_PASSED) *resultp = EFX_BIST_RESULT_PASSED; else *resultp = EFX_BIST_RESULT_FAILED; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void hunt_bist_stop( __in efx_nic_t *enp, __in efx_bist_type_t type) { /* There is no way to stop BIST on Huntinton. */ _NOTE(ARGUNUSED(enp, type)) } #endif /* EFSYS_OPT_BIST */ #endif /* EFSYS_OPT_HUNTINGTON */ Index: stable/10/sys/modules/sfxge/Makefile =================================================================== --- stable/10/sys/modules/sfxge/Makefile (revision 301343) +++ stable/10/sys/modules/sfxge/Makefile (revision 301344) @@ -1,59 +1,59 @@ # $FreeBSD$ .include KMOD= sfxge SFXGE= ${.CURDIR}/../../dev/sfxge SRCS= device_if.h bus_if.h pci_if.h SRCS+= opt_inet.h opt_inet6.h opt_sched.h .PATH: ${.CURDIR}/../../dev/sfxge SRCS+= sfxge.c sfxge_dma.c sfxge_ev.c SRCS+= sfxge_intr.c sfxge_mcdi.c sfxge_nvram.c SRCS+= sfxge_port.c sfxge_rx.c sfxge_tx.c SRCS+= sfxge.h sfxge_rx.h sfxge_tx.h sfxge_version.h .PATH: ${.CURDIR}/../../dev/sfxge/common SRCS+= efx_bootcfg.c efx_crc32.c efx_ev.c efx_intr.c efx_lic.c efx_mac.c SRCS+= efx_mcdi.c efx_mon.c efx_nic.c SRCS+= efx_nvram.c efx_phy.c efx_port.c efx_rx.c efx_sram.c efx_tx.c SRCS+= efx_vpd.c efx_wol.c efx_filter.c efx_hash.c SRCS+= efsys.h SRCS+= efx.h efx_check.h efx_impl.h efx_mcdi.h efx_regs.h efx_regs_ef10.h SRCS+= efx_regs_mcdi.h efx_regs_pci.h efx_types.h efx_phy_ids.h SRCS+= ef10_tlv_layout.h SRCS+= mcdi_mon.c mcdi_mon.h SRCS+= siena_mac.c siena_mcdi.c siena_nic.c siena_nvram.c siena_phy.c SRCS+= siena_sram.c siena_vpd.c SRCS+= siena_flash.h siena_impl.h +SRCS+= ef10_ev.c ef10_filter.c ef10_intr.c ef10_mac.c ef10_mcdi.c ef10_nic.c +SRCS+= ef10_nvram.c ef10_phy.c ef10_rx.c ef10_tx.c ef10_vpd.c SRCS+= ef10_impl.h -SRCS+= hunt_ev.c hunt_intr.c hunt_mac.c hunt_mcdi.c hunt_nic.c -SRCS+= hunt_nvram.c hunt_rx.c hunt_phy.c hunt_tx.c hunt_vpd.c -SRCS+= hunt_filter.c +SRCS+= hunt_nic.c hunt_phy.c SRCS+= hunt_impl.h SRCS+= medford_nic.c SRCS+= medford_impl.h # Extra debug checks #CFLAGS += -DDEBUG=1 .if !defined(KERNBUILDDIR) .if ${MK_INET_SUPPORT} != "no" opt_inet.h: @echo "#define INET 1" > ${.TARGET} .endif .if ${MK_INET6_SUPPORT} != "no" opt_inet6.h: @echo "#define INET6 1" > ${.TARGET} .endif .endif .include Index: stable/10 =================================================================== --- stable/10 (revision 301343) +++ stable/10 (revision 301344) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r299596-299606,299681,299726,299738