summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/amd64/autoconf.c132
-rw-r--r--sys/amd64/amd64/sys_machdep.c4
-rw-r--r--sys/amd64/amd64/vm_machdep.c7
-rw-r--r--sys/amd64/cloudabi64/cloudabi64_sysvec.c1
-rw-r--r--sys/amd64/conf/GENERIC.hints1
-rw-r--r--sys/amd64/include/intr_machdep.h2
-rw-r--r--sys/amd64/include/md_var.h3
-rw-r--r--sys/amd64/linux32/linux32_dummy.c1
-rw-r--r--sys/amd64/linux32/linux32_proto.h6
-rw-r--r--sys/amd64/linux32/linux32_syscall.h2
-rw-r--r--sys/amd64/linux32/linux32_syscalls.c2
-rw-r--r--sys/amd64/linux32/linux32_sysent.c4
-rw-r--r--sys/amd64/linux32/linux32_systrace_args.c22
-rw-r--r--sys/amd64/linux32/syscalls.master2
-rw-r--r--sys/arm/allwinner/a10_gpio.c12
-rw-r--r--sys/arm/allwinner/a10_hdmi.c49
-rw-r--r--sys/arm/allwinner/a10_mmc.c1
-rw-r--r--sys/arm/allwinner/allwinner_machdep.c17
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_mmc.c1
-rw-r--r--sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c1
-rw-r--r--sys/arm/arm/gic.c508
-rw-r--r--sys/arm/arm/machdep.c120
-rw-r--r--sys/arm/arm/machdep_intr.c176
-rw-r--r--sys/arm/arm/mp_machdep.c24
-rw-r--r--sys/arm/arm/nexus.c18
-rw-r--r--sys/arm/arm/vm_machdep.c6
-rw-r--r--sys/arm/at91/at91.c6
-rw-r--r--sys/arm/at91/at91_mci.c1
-rw-r--r--sys/arm/at91/at91_pinctrl.c4
-rw-r--r--sys/arm/at91/board_tsc4370.c2
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_common.c23
-rw-r--r--sys/arm/broadcom/bcm2835/bcm2835_sdhci.c1
-rw-r--r--sys/arm/broadcom/bcm2835/std.rpi1
-rw-r--r--sys/arm/cavium/cns11xx/econa.c6
-rw-r--r--sys/arm/conf/A102
-rw-r--r--sys/arm/conf/A202
-rw-r--r--sys/arm/conf/ARMADA38X3
-rw-r--r--sys/arm/conf/ATMEL5
-rw-r--r--sys/arm/conf/BEAGLEBONE6
-rw-r--r--sys/arm/conf/CNS11XXNAS5
-rw-r--r--sys/arm/conf/EFIKA_MX3
-rw-r--r--sys/arm/conf/ETHERNUT53
-rw-r--r--sys/arm/conf/IMX533
-rw-r--r--sys/arm/conf/JETSON-TK137
-rw-r--r--sys/arm/conf/NOTES4
-rw-r--r--sys/arm/conf/RK31884
-rw-r--r--sys/arm/conf/SAM9260EK3
-rw-r--r--sys/arm/conf/TEGRA124157
-rw-r--r--sys/arm/conf/std.arm1
-rw-r--r--sys/arm/conf/std.armv62
-rw-r--r--sys/arm/freescale/imx/imx_gpio.c327
-rw-r--r--sys/arm/freescale/imx/imx_sdhci.c1
-rw-r--r--sys/arm/include/atags.h2
-rw-r--r--sys/arm/include/intr.h13
-rw-r--r--sys/arm/include/machdep.h3
-rw-r--r--sys/arm/include/smp.h2
-rw-r--r--sys/arm/lpc/lpc_mmc.c1
-rw-r--r--sys/arm/mv/files.mv1
-rw-r--r--sys/arm/mv/mpic.c166
-rw-r--r--sys/arm/mv/mv_localbus.c4
-rw-r--r--sys/arm/nvidia/as3722.c411
-rw-r--r--sys/arm/nvidia/as3722.h323
-rw-r--r--sys/arm/nvidia/as3722_gpio.c577
-rw-r--r--sys/arm/nvidia/as3722_regulators.c811
-rw-r--r--sys/arm/nvidia/as3722_rtc.c115
-rw-r--r--sys/arm/nvidia/tegra124/files.tegra12457
-rw-r--r--sys/arm/nvidia/tegra124/std.tegra12414
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_car.c613
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_car.h337
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_clk_per.c810
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_clk_pll.c1066
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_clk_super.c265
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_coretemp.c273
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_cpufreq.c583
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_machdep.c173
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_mp.c127
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_mp.h (renamed from sys/compat/cloudabi/cloudabi_syscalldefs.h)27
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_pmc.c566
-rw-r--r--sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c603
-rw-r--r--sys/arm/nvidia/tegra_abpmisc.c194
-rw-r--r--sys/arm/nvidia/tegra_ahci.c627
-rw-r--r--sys/arm/nvidia/tegra_efuse.c368
-rw-r--r--sys/arm/nvidia/tegra_efuse.h61
-rw-r--r--sys/arm/nvidia/tegra_ehci.c322
-rw-r--r--sys/arm/nvidia/tegra_gpio.c480
-rw-r--r--sys/arm/nvidia/tegra_i2c.c804
-rw-r--r--sys/arm/nvidia/tegra_lic.c288
-rw-r--r--sys/arm/nvidia/tegra_pcie.c1691
-rw-r--r--sys/arm/nvidia/tegra_pinmux.c804
-rw-r--r--sys/arm/nvidia/tegra_pmc.h115
-rw-r--r--sys/arm/nvidia/tegra_rtc.c303
-rw-r--r--sys/arm/nvidia/tegra_sdhci.c465
-rw-r--r--sys/arm/nvidia/tegra_soctherm.c696
-rw-r--r--sys/arm/nvidia/tegra_soctherm_if.m42
-rw-r--r--sys/arm/nvidia/tegra_uart.c251
-rw-r--r--sys/arm/nvidia/tegra_usbphy.c839
-rw-r--r--sys/arm/ti/aintc.c178
-rw-r--r--sys/arm/ti/am335x/am335x_prcm.c10
-rw-r--r--sys/arm/ti/cpsw/if_cpsw.c1735
-rw-r--r--sys/arm/ti/cpsw/if_cpswreg.h213
-rw-r--r--sys/arm/ti/cpsw/if_cpswvar.h82
-rw-r--r--sys/arm/ti/files.ti1
-rw-r--r--sys/arm/ti/omap4/omap4_gpio.c1
-rw-r--r--sys/arm/ti/omap4/omap4_wugen.c64
-rw-r--r--sys/arm/ti/ti_adc.c14
-rw-r--r--sys/arm/ti/ti_gpio.c340
-rw-r--r--sys/arm/ti/ti_gpio.h19
-rw-r--r--sys/arm/ti/ti_hwmods.c3
-rw-r--r--sys/arm/ti/ti_prcm.h4
-rw-r--r--sys/arm/ti/ti_sdhci.c1
-rw-r--r--sys/arm/ti/ti_spi.c582
-rw-r--r--sys/arm/ti/ti_spireg.h97
-rw-r--r--sys/arm/ti/ti_spivar.h71
-rw-r--r--sys/arm/xscale/ixp425/avila_ata.c2
-rw-r--r--sys/arm/xscale/ixp425/ixp425.c8
-rw-r--r--sys/arm/xscale/pxa/pxa_obio.c6
-rw-r--r--sys/arm/xscale/pxa/pxa_smi.c4
-rw-r--r--sys/arm64/arm64/bzero.S206
-rw-r--r--sys/arm64/arm64/copyinout.S136
-rw-r--r--sys/arm64/arm64/exception.S4
-rw-r--r--sys/arm64/arm64/genassym.c2
-rw-r--r--sys/arm64/arm64/gic.c46
-rw-r--r--sys/arm64/arm64/intr_machdep.c8
-rw-r--r--sys/arm64/arm64/locore.S52
-rw-r--r--sys/arm64/arm64/machdep.c39
-rw-r--r--sys/arm64/arm64/minidump_machdep.c6
-rw-r--r--sys/arm64/arm64/mp_machdep.c89
-rw-r--r--sys/arm64/arm64/nexus.c12
-rw-r--r--sys/arm64/arm64/pmap.c812
-rw-r--r--sys/arm64/arm64/support.S36
-rw-r--r--sys/arm64/arm64/swtch.S4
-rw-r--r--sys/arm64/arm64/vm_machdep.c4
-rw-r--r--sys/arm64/cloudabi64/cloudabi64_sysvec.c1
-rw-r--r--sys/arm64/include/armreg.h6
-rw-r--r--sys/arm64/include/cpu.h4
-rw-r--r--sys/arm64/include/intr.h10
-rw-r--r--sys/arm64/include/machdep.h2
-rw-r--r--sys/arm64/include/pcb.h2
-rw-r--r--sys/arm64/include/pmap.h6
-rw-r--r--sys/arm64/include/pte.h19
-rw-r--r--sys/arm64/include/smp.h2
-rw-r--r--sys/arm64/include/vmparam.h2
-rw-r--r--sys/boot/Makefile.amd641
-rw-r--r--sys/boot/Makefile.i3861
-rw-r--r--sys/boot/common/dev_net.c6
-rw-r--r--sys/boot/common/disk.c2
-rw-r--r--sys/boot/common/disk.h1
-rw-r--r--sys/boot/common/gpt.c2
-rw-r--r--sys/boot/common/gpt.h2
-rw-r--r--sys/boot/efi/Makefile8
-rw-r--r--sys/boot/fdt/dts/arm/bcm2836.dtsi17
-rw-r--r--sys/boot/fdt/dts/arm/beaglebone-black.dts20
-rw-r--r--sys/boot/fdt/dts/arm/tegra124-jetson-tk1-fbsd.dts (renamed from sys/dev/filemon/filemon_lock.c)51
-rw-r--r--sys/boot/geli/Makefile52
-rw-r--r--sys/boot/geli/Makefile.depend16
-rw-r--r--sys/boot/geli/geliboot.c292
-rw-r--r--sys/boot/geli/geliboot.h86
-rw-r--r--sys/boot/geli/geliboot_crypto.c135
-rw-r--r--sys/boot/geli/pwgets.c83
-rw-r--r--sys/boot/i386/boot0/Makefile1
-rw-r--r--sys/boot/i386/boot2/Makefile1
-rw-r--r--sys/boot/i386/btx/btx/Makefile1
-rw-r--r--sys/boot/i386/btx/btxldr/Makefile1
-rw-r--r--sys/boot/i386/cdboot/Makefile1
-rw-r--r--sys/boot/i386/common/bootargs.h6
-rw-r--r--sys/boot/i386/common/cons.c7
-rw-r--r--sys/boot/i386/common/drv.c2
-rw-r--r--sys/boot/i386/common/drv.h2
-rw-r--r--sys/boot/i386/gptboot/Makefile17
-rw-r--r--sys/boot/i386/gptboot/Makefile.depend4
-rw-r--r--sys/boot/i386/gptboot/gptboot.c221
-rw-r--r--sys/boot/i386/gptzfsboot/Makefile15
-rw-r--r--sys/boot/i386/gptzfsboot/Makefile.depend3
-rw-r--r--sys/boot/i386/libi386/Makefile7
-rw-r--r--sys/boot/i386/libi386/Makefile.depend1
-rw-r--r--sys/boot/i386/libi386/biosdisk.c178
-rw-r--r--sys/boot/i386/libi386/pxe.c5
-rw-r--r--sys/boot/i386/loader/Makefile11
-rw-r--r--sys/boot/i386/loader/Makefile.depend1
-rw-r--r--sys/boot/i386/loader/main.c31
-rw-r--r--sys/boot/i386/pxeldr/Makefile1
-rw-r--r--sys/boot/i386/zfsboot/Makefile1
-rw-r--r--sys/boot/i386/zfsboot/zfsboot.c119
-rw-r--r--sys/boot/i386/zfsloader/Makefile.depend1
-rw-r--r--sys/boot/pc98/boot2/Makefile1
-rw-r--r--sys/boot/pc98/btx/btx/Makefile1
-rw-r--r--sys/boot/pc98/btx/btxldr/Makefile1
-rw-r--r--sys/boot/pc98/cdboot/Makefile1
-rw-r--r--sys/boot/zfs/libzfs.h1
-rw-r--r--sys/cam/ata/ata_da.c15
-rw-r--r--sys/cam/cam_ccb.h7
-rw-r--r--sys/cam/scsi/scsi_ch.c3
-rw-r--r--sys/cam/scsi/scsi_da.c15
-rw-r--r--sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c1
-rw-r--r--sys/cddl/compat/opensolaris/sys/vfs.h11
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c18
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c13
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c33
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c14
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c68
-rw-r--r--sys/cddl/dev/dtrace/aarch64/dtrace_subr.c2
-rw-r--r--sys/cddl/dev/dtrace/amd64/dtrace_subr.c3
-rw-r--r--sys/cddl/dev/dtrace/arm/dtrace_subr.c2
-rw-r--r--sys/cddl/dev/dtrace/i386/dtrace_subr.c2
-rw-r--r--sys/cddl/dev/dtrace/mips/dtrace_subr.c2
-rw-r--r--sys/cddl/dev/dtrace/powerpc/dtrace_subr.c2
-rw-r--r--sys/compat/cloudabi/cloudabi_clock.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_errno.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_fd.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_file.c21
-rw-r--r--sys/compat/cloudabi/cloudabi_futex.c25
-rw-r--r--sys/compat/cloudabi/cloudabi_mem.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_proc.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_proto.h4
-rw-r--r--sys/compat/cloudabi/cloudabi_sock.c20
-rw-r--r--sys/compat/cloudabi/cloudabi_thread.c3
-rw-r--r--sys/compat/cloudabi/cloudabi_util.h8
-rw-r--r--sys/compat/cloudabi64/Makefile6
-rw-r--r--sys/compat/cloudabi64/cloudabi64_fd.c3
-rw-r--r--sys/compat/cloudabi64/cloudabi64_module.c4
-rw-r--r--sys/compat/cloudabi64/cloudabi64_poll.c9
-rw-r--r--sys/compat/cloudabi64/cloudabi64_proto.h44
-rw-r--r--sys/compat/cloudabi64/cloudabi64_sock.c7
-rw-r--r--sys/compat/cloudabi64/cloudabi64_syscall.h2
-rw-r--r--sys/compat/cloudabi64/cloudabi64_syscalls.c2
-rw-r--r--sys/compat/cloudabi64/cloudabi64_sysent.c4
-rw-r--r--sys/compat/cloudabi64/cloudabi64_systrace_args.c80
-rw-r--r--sys/compat/cloudabi64/cloudabi64_thread.c3
-rw-r--r--sys/compat/cloudabi64/cloudabi64_util.h2
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c15
-rw-r--r--sys/compat/linux/linux_event.c21
-rw-r--r--sys/compat/linux/linux_mib.c47
-rw-r--r--sys/compat/linux/linux_misc.c44
-rw-r--r--sys/compat/linux/linux_socket.c40
-rw-r--r--sys/compat/linux/linux_stats.c59
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/list.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h47
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c10
-rw-r--r--sys/compat/ndis/kern_ndis.c4
-rw-r--r--sys/conf/NOTES3
-rw-r--r--sys/conf/files61
-rw-r--r--sys/conf/files.amd646
-rw-r--r--sys/conf/files.arm2
-rw-r--r--sys/conf/files.arm642
-rw-r--r--sys/conf/files.i3867
-rw-r--r--sys/conf/files.mips3
-rw-r--r--sys/conf/files.pc984
-rw-r--r--sys/conf/files.powerpc2
-rw-r--r--sys/conf/files.sparc646
-rw-r--r--sys/conf/kern.opts.mk10
-rw-r--r--sys/conf/kern.post.mk49
-rw-r--r--sys/conf/kern.pre.mk23
-rw-r--r--sys/conf/kmod.mk5
-rw-r--r--sys/contrib/cloudabi/cloudabi64_types.h225
-rw-r--r--sys/contrib/cloudabi/cloudabi_types_common.h463
-rw-r--r--sys/contrib/cloudabi/syscalldefs_md.h255
-rw-r--r--sys/contrib/cloudabi/syscalldefs_mi.h476
-rw-r--r--sys/contrib/cloudabi/syscalls.master (renamed from sys/compat/cloudabi64/syscalls.master)218
-rw-r--r--sys/contrib/rdma/krping/krping.c10
-rw-r--r--sys/ddb/db_ps.c12
-rw-r--r--sys/dev/acpica/acpi.c12
-rw-r--r--sys/dev/acpica/acpi_hpet.c2
-rw-r--r--sys/dev/acpica/acpi_timer.c2
-rw-r--r--sys/dev/advansys/adv_isa.c2
-rw-r--r--sys/dev/ahci/ahci.c2
-rw-r--r--sys/dev/ahci/ahci.h4
-rw-r--r--sys/dev/ahci/ahci_pci.c5
-rw-r--r--sys/dev/amdsbwd/amdsbwd.c20
-rw-r--r--sys/dev/arcmsr/arcmsr.c23
-rw-r--r--sys/dev/ata/ata-lowlevel.c2
-rw-r--r--sys/dev/ath/if_ath_lna_div.c2
-rw-r--r--sys/dev/atkbdc/atkbdc_subr.c2
-rw-r--r--sys/dev/bhnd/bhnd.c4
-rw-r--r--sys/dev/bhnd/bhndb/bhndb.c4
-rw-r--r--sys/dev/bwn/if_bwn.c8
-rw-r--r--sys/dev/bxe/bxe.c94
-rw-r--r--sys/dev/bxe/bxe.h11
-rw-r--r--sys/dev/cardbus/cardbus_cis.c3
-rw-r--r--sys/dev/ctau/if_ct.c6
-rw-r--r--sys/dev/cxgb/cxgb_sge.c6
-rw-r--r--sys/dev/cxgbe/adapter.h22
-rw-r--r--sys/dev/cxgbe/common/t4_hw.c15
-rw-r--r--sys/dev/cxgbe/firmware/t4fw_cfg.txt157
-rw-r--r--sys/dev/cxgbe/firmware/t5fw_cfg.txt197
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/cm.c271
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/cq.c6
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h14
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/mem.c34
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/qp.c16
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/t4.h3
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/user.h1
-rw-r--r--sys/dev/cxgbe/offload.h2
-rw-r--r--sys/dev/cxgbe/t4_main.c46
-rw-r--r--sys/dev/cxgbe/t4_sge.c9
-rw-r--r--sys/dev/drm2/i915/i915_gem.c24
-rw-r--r--sys/dev/drm2/i915/intel_pm.c30
-rw-r--r--sys/dev/drm2/ttm/ttm_bo_vm.c27
-rw-r--r--sys/dev/e1000/if_igb.c60
-rw-r--r--sys/dev/e1000/if_igb.h6
-rw-r--r--sys/dev/ed/if_ed_3c503.c2
-rw-r--r--sys/dev/ed/if_ed_cbus.c22
-rw-r--r--sys/dev/extres/clk/clk.c79
-rw-r--r--sys/dev/extres/clk/clk.h3
-rw-r--r--sys/dev/extres/clk/clk_bus.c93
-rw-r--r--sys/dev/extres/clk/clk_div.c13
-rw-r--r--sys/dev/extres/clk/clk_fixed.c194
-rw-r--r--sys/dev/extres/clk/clk_fixed.h3
-rw-r--r--sys/dev/extres/clk/clk_gate.c13
-rw-r--r--sys/dev/extres/clk/clk_mux.c16
-rw-r--r--sys/dev/extres/clk/clkdev_if.m85
-rw-r--r--sys/dev/extres/phy/phy.c235
-rw-r--r--sys/dev/extres/phy/phy.h63
-rw-r--r--sys/dev/extres/phy/phy_if.m84
-rw-r--r--sys/dev/extres/regulator/regdev_if.m56
-rw-r--r--sys/dev/extres/regulator/regnode_if.m82
-rw-r--r--sys/dev/extres/regulator/regulator.c984
-rw-r--r--sys/dev/extres/regulator/regulator.h127
-rw-r--r--sys/dev/extres/regulator/regulator_bus.c89
-rw-r--r--sys/dev/extres/regulator/regulator_fixed.c456
-rw-r--r--sys/dev/extres/regulator/regulator_fixed.h (renamed from sys/compat/cloudabi64/cloudabi64_syscalldefs.h)29
-rw-r--r--sys/dev/fdt/fdt_common.c13
-rw-r--r--sys/dev/fdt/fdt_common.h1
-rw-r--r--sys/dev/fdt/simplebus.c6
-rw-r--r--sys/dev/filemon/filemon.c356
-rw-r--r--sys/dev/filemon/filemon_wrapper.c423
-rw-r--r--sys/dev/flash/mx25l.c127
-rw-r--r--sys/dev/flash/mx25lreg.h2
-rw-r--r--sys/dev/gpio/gpiobus.c4
-rw-r--r--sys/dev/gpio/ofw_gpiobus.c3
-rw-r--r--sys/dev/hyperv/include/hyperv.h2
-rw-r--r--sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c50
-rw-r--r--sys/dev/hyperv/utilities/hv_heartbeat.c4
-rw-r--r--sys/dev/hyperv/utilities/hv_kvp.c33
-rw-r--r--sys/dev/hyperv/utilities/hv_shutdown.c4
-rw-r--r--sys/dev/hyperv/utilities/hv_timesync.c4
-rw-r--r--sys/dev/hyperv/vmbus/hv_connection.c40
-rw-r--r--sys/dev/hyperv/vmbus/hv_et.c2
-rw-r--r--sys/dev/hyperv/vmbus/hv_hv.c30
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c110
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_priv.h8
-rw-r--r--sys/dev/ichwd/ichwd.c14
-rw-r--r--sys/dev/iicbus/iicbus.c2
-rw-r--r--sys/dev/iir/iir.c6
-rw-r--r--sys/dev/iir/iir_pci.c2
-rw-r--r--sys/dev/ipmi/ipmi.c53
-rw-r--r--sys/dev/isci/isci_controller.c10
-rw-r--r--sys/dev/isci/isci_io_request.c18
-rw-r--r--sys/dev/iscsi/iscsi.c3
-rw-r--r--sys/dev/iwn/if_iwn.c18
-rw-r--r--sys/dev/ixgbe/if_ix.c8
-rw-r--r--sys/dev/ixgbe/ix_txrx.c6
-rw-r--r--sys/dev/ixl/ixl_txrx.c6
-rw-r--r--sys/dev/le/lebuffer_sbus.c4
-rw-r--r--sys/dev/mca/mca_bus.c12
-rw-r--r--sys/dev/mfi/mfi.c4
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_rx.c8
-rw-r--r--sys/dev/mmc/host/dwmmc.c1
-rw-r--r--sys/dev/mmc/mmc.c2
-rw-r--r--sys/dev/mmc/mmcreg.h7
-rw-r--r--sys/dev/mvs/mvs_pci.c2
-rw-r--r--sys/dev/mvs/mvs_soc.c2
-rw-r--r--sys/dev/mxge/if_mxge.c12
-rw-r--r--sys/dev/ncr/ncr.c14
-rw-r--r--sys/dev/nctgpio/nctgpio.c802
-rw-r--r--sys/dev/netmap/netmap_generic.c3
-rw-r--r--sys/dev/oce/oce_if.c6
-rw-r--r--sys/dev/ofw/ofw_iicbus.c6
-rw-r--r--sys/dev/ofw/ofwbus.c4
-rw-r--r--sys/dev/ofw/ofwpci.c628
-rw-r--r--sys/dev/ofw/ofwpci.h83
-rw-r--r--sys/dev/pccard/pccard.c34
-rw-r--r--sys/dev/pccard/pccard_cis.c12
-rw-r--r--sys/dev/pccbb/pccbb.c10
-rw-r--r--sys/dev/pccbb/pccbb_pci.c2
-rw-r--r--sys/dev/pci/pci.c22
-rw-r--r--sys/dev/pci/pci_host_generic.c6
-rw-r--r--sys/dev/pci/pci_pci.c34
-rw-r--r--sys/dev/pci/pci_subr.c8
-rw-r--r--sys/dev/ppbus/vpo.c16
-rw-r--r--sys/dev/ppc/ppc.c4
-rw-r--r--sys/dev/proto/proto_bus_isa.c2
-rw-r--r--sys/dev/qlxgb/qla_isr.c7
-rw-r--r--sys/dev/qlxge/qls_isr.c7
-rw-r--r--sys/dev/random/random_harvestq.c3
-rw-r--r--sys/dev/sdhci/sdhci_fdt.c1
-rw-r--r--sys/dev/sdhci/sdhci_pci.c1
-rw-r--r--sys/dev/sfxge/sfxge_mcdi.c5
-rw-r--r--sys/dev/sfxge/sfxge_nvram.c5
-rw-r--r--sys/dev/siba/siba.c4
-rw-r--r--sys/dev/siis/siis.c2
-rw-r--r--sys/dev/sound/isa/ad1816.c4
-rw-r--r--sys/dev/sound/isa/ess.c6
-rw-r--r--sys/dev/sound/isa/mss.c4
-rw-r--r--sys/dev/sound/isa/sb16.c4
-rw-r--r--sys/dev/sound/isa/sb8.c2
-rw-r--r--sys/dev/sound/pci/als4000.c2
-rw-r--r--sys/dev/sound/pci/atiixp.c2
-rw-r--r--sys/dev/sound/pci/aureal.c2
-rw-r--r--sys/dev/sound/pci/cmi.c2
-rw-r--r--sys/dev/sound/pci/cs4281.c2
-rw-r--r--sys/dev/sound/pci/csapcm.c2
-rw-r--r--sys/dev/sound/pci/ds1.c2
-rw-r--r--sys/dev/sound/pci/emu10k1.c2
-rw-r--r--sys/dev/sound/pci/emu10kx.c2
-rw-r--r--sys/dev/sound/pci/envy24.c2
-rw-r--r--sys/dev/sound/pci/envy24ht.c2
-rw-r--r--sys/dev/sound/pci/es137x.c2
-rw-r--r--sys/dev/sound/pci/fm801.c2
-rw-r--r--sys/dev/sound/pci/hda/hdac.c2
-rw-r--r--sys/dev/sound/pci/hda/hdac.h4
-rw-r--r--sys/dev/sound/pci/hdspe-pcm.c2
-rw-r--r--sys/dev/sound/pci/ich.c2
-rw-r--r--sys/dev/sound/pci/maestro.c2
-rw-r--r--sys/dev/sound/pci/maestro3.c2
-rw-r--r--sys/dev/sound/pci/neomagic.c2
-rw-r--r--sys/dev/sound/pci/solo.c2
-rw-r--r--sys/dev/sound/pci/t4dwave.c2
-rw-r--r--sys/dev/sound/pci/via8233.c2
-rw-r--r--sys/dev/sound/pci/via82c686.c2
-rw-r--r--sys/dev/sound/pci/vibes.c4
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c13
-rw-r--r--sys/dev/uart/uart_dev_snps.c283
-rw-r--r--sys/dev/urtwn/if_urtwn.c (renamed from sys/dev/usb/wlan/if_urtwn.c)137
-rw-r--r--sys/dev/urtwn/if_urtwnreg.h (renamed from sys/dev/usb/wlan/if_urtwnreg.h)0
-rw-r--r--sys/dev/urtwn/if_urtwnvar.h (renamed from sys/dev/usb/wlan/if_urtwnvar.h)0
-rw-r--r--sys/dev/usb/controller/ehci_pci.c6
-rw-r--r--sys/dev/usb/controller/ohci_pci.c3
-rw-r--r--sys/dev/usb/controller/uhci_pci.c6
-rw-r--r--sys/dev/usb/controller/xhci_pci.c5
-rw-r--r--sys/dev/usb/usb_busdma.c27
-rw-r--r--sys/dev/usb/usbdevs1
-rw-r--r--sys/dev/usb/video/udl.c3
-rw-r--r--sys/dev/usb/wlan/if_rum.c275
-rw-r--r--sys/dev/usb/wlan/if_rumreg.h13
-rw-r--r--sys/dev/usb/wlan/if_rumvar.h10
-rw-r--r--sys/dev/vnic/nic_main.c24
-rw-r--r--sys/dev/vnic/nicvf_main.c26
-rw-r--r--sys/dev/vnic/nicvf_queues.c123
-rw-r--r--sys/dev/vnic/nicvf_queues.h2
-rw-r--r--sys/dev/vnic/thunder_bgx_fdt.c22
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c8
-rw-r--r--sys/dev/vxge/vxge.c9
-rw-r--r--sys/dev/wbwd/wbwd.c390
-rw-r--r--sys/dev/wl/if_wl.c2
-rw-r--r--sys/dev/wpi/if_wpi.c53
-rw-r--r--sys/dev/wpi/if_wpivar.h4
-rw-r--r--sys/dev/xe/if_xe.c4
-rw-r--r--sys/dev/xe/if_xe_pccard.c2
-rw-r--r--sys/dev/xen/blkfront/blkfront.c28
-rw-r--r--sys/dev/xen/blkfront/block.h7
-rw-r--r--sys/dev/xen/netfront/netfront.c7
-rw-r--r--sys/fs/autofs/autofs.c10
-rw-r--r--sys/fs/autofs/autofs.h7
-rw-r--r--sys/fs/autofs/autofs_vfsops.c9
-rw-r--r--sys/fs/autofs/autofs_vnops.c40
-rw-r--r--sys/fs/cd9660/cd9660_vnops.c6
-rw-r--r--sys/fs/ext2fs/ext2_alloc.c4
-rw-r--r--sys/fs/ext2fs/ext2_dinode.h1
-rw-r--r--sys/fs/ext2fs/ext2fs.h63
-rw-r--r--sys/geom/sched/g_sched.c3
-rw-r--r--sys/i386/conf/GENERIC.hints1
-rw-r--r--sys/i386/i386/vm_machdep.c7
-rw-r--r--sys/i386/include/intr_machdep.h2
-rw-r--r--sys/i386/include/md_var.h1
-rw-r--r--sys/i386/linux/linux_dummy.c1
-rw-r--r--sys/i386/linux/linux_proto.h6
-rw-r--r--sys/i386/linux/linux_syscall.h2
-rw-r--r--sys/i386/linux/linux_syscalls.c2
-rw-r--r--sys/i386/linux/linux_sysent.c4
-rw-r--r--sys/i386/linux/linux_systrace_args.c22
-rw-r--r--sys/i386/linux/syscalls.master2
-rw-r--r--sys/isa/isa_common.c8
-rw-r--r--sys/kern/imgact_binmisc.c13
-rw-r--r--sys/kern/imgact_elf.c4
-rw-r--r--sys/kern/init_sysent.c2
-rw-r--r--sys/kern/kern_condvar.c48
-rw-r--r--sys/kern/kern_descrip.c4
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_fail.c782
-rw-r--r--sys/kern/kern_linker.c2
-rw-r--r--sys/kern/kern_mbuf.c11
-rw-r--r--sys/kern/kern_osd.c263
-rw-r--r--sys/kern/kern_racct.c149
-rw-r--r--sys/kern/kern_rctl.c75
-rw-r--r--sys/kern/kern_sendfile.c56
-rw-r--r--sys/kern/kern_synch.c25
-rw-r--r--sys/kern/pic_if.m112
-rw-r--r--sys/kern/subr_bus.c32
-rw-r--r--sys/kern/subr_counter.c25
-rw-r--r--sys/kern/subr_intr.c534
-rw-r--r--sys/kern/subr_rman.c50
-rw-r--r--sys/kern/subr_sleepqueue.c121
-rw-r--r--sys/kern/subr_smp.c248
-rw-r--r--sys/kern/sys_generic.c24
-rw-r--r--sys/kern/syscalls.c2
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/kern/systrace_args.c4
-rw-r--r--sys/kern/uipc_mbuf.c47
-rw-r--r--sys/kern/uipc_socket.c2
-rw-r--r--sys/kern/vfs_aio.c49
-rw-r--r--sys/kern/vfs_export.c4
-rw-r--r--sys/kern/vfs_mountroot.c3
-rw-r--r--sys/mips/atheros/apb.c6
-rw-r--r--sys/mips/beri/beri_simplebus.c4
-rw-r--r--sys/mips/mips/mips_pic.c7
-rw-r--r--sys/mips/mips/nexus.c8
-rw-r--r--sys/mips/nlm/xlp_pci.c2
-rw-r--r--sys/mips/nlm/xlp_simplebus.c4
-rw-r--r--sys/mips/rmi/iodi.c6
-rw-r--r--sys/mips/rmi/xlr_pci.c2
-rw-r--r--sys/mips/rt305x/obio.c4
-rw-r--r--sys/modules/Makefile5
-rw-r--r--sys/modules/nctgpio/Makefile8
-rw-r--r--sys/modules/pflog/Makefile5
-rw-r--r--sys/modules/pfsync/Makefile5
-rw-r--r--sys/modules/urtwn/Makefile (renamed from sys/modules/usb/urtwn/Makefile)5
-rw-r--r--sys/modules/urtwnfw/Makefile (renamed from sys/modules/usb/urtwnfw/Makefile)0
-rw-r--r--sys/modules/urtwnfw/Makefile.inc (renamed from sys/modules/usb/urtwnfw/Makefile.inc)2
-rw-r--r--sys/modules/urtwnfw/urtwnrtl8188eu/Makefile (renamed from sys/modules/usb/urtwnfw/urtwnrtl8188eu/Makefile)0
-rw-r--r--sys/modules/urtwnfw/urtwnrtl8192cT/Makefile (renamed from sys/modules/usb/urtwnfw/urtwnrtl8192cT/Makefile)0
-rw-r--r--sys/modules/urtwnfw/urtwnrtl8192cU/Makefile (renamed from sys/modules/usb/urtwnfw/urtwnrtl8192cU/Makefile)0
-rw-r--r--sys/modules/usb/Makefile2
-rw-r--r--sys/modules/wtap/Makefile5
-rw-r--r--sys/net/ethernet.h1
-rw-r--r--sys/net/if_debug.c2
-rw-r--r--sys/net/route.c11
-rw-r--r--sys/net/route.h23
-rw-r--r--sys/net/route_var.h2
-rw-r--r--sys/net/rtsock.c2
-rw-r--r--sys/net80211/ieee80211.h187
-rw-r--r--sys/net80211/ieee80211_amrr.c31
-rw-r--r--sys/net80211/ieee80211_dfs.c2
-rw-r--r--sys/net80211/ieee80211_freebsd.h8
-rw-r--r--sys/net80211/ieee80211_ht.c2
-rw-r--r--sys/net80211/ieee80211_hwmp.c6
-rw-r--r--sys/net80211/ieee80211_input.c5
-rw-r--r--sys/net80211/ieee80211_ioctl.h5
-rw-r--r--sys/net80211/ieee80211_node.c2
-rw-r--r--sys/net80211/ieee80211_power.c2
-rw-r--r--sys/net80211/ieee80211_proto.c7
-rw-r--r--sys/net80211/ieee80211_ratectl.c41
-rw-r--r--sys/net80211/ieee80211_ratectl.h11
-rw-r--r--sys/net80211/ieee80211_scan_sta.c4
-rw-r--r--sys/net80211/ieee80211_scan_sw.c10
-rw-r--r--sys/net80211/ieee80211_sta.c43
-rw-r--r--sys/net80211/ieee80211_wds.c3
-rw-r--r--sys/netinet/in_pcb.c22
-rw-r--r--sys/netinet/in_pcb.h10
-rw-r--r--sys/netinet/in_pcbgroup.c1
-rw-r--r--sys/netinet/ip_output.c29
-rw-r--r--sys/netinet/sctp_cc_functions.c12
-rw-r--r--sys/netinet/sctp_constants.h2
-rw-r--r--sys/netinet/sctp_indata.c20
-rw-r--r--sys/netinet/sctp_input.c10
-rw-r--r--sys/netinet/sctp_output.c68
-rw-r--r--sys/netinet/sctp_pcb.c4
-rw-r--r--sys/netinet/sctp_ss_functions.c2
-rw-r--r--sys/netinet/sctp_timer.c4
-rw-r--r--sys/netinet/sctp_usrreq.c26
-rw-r--r--sys/netinet/sctputil.c70
-rw-r--r--sys/netinet/sctputil.h5
-rw-r--r--sys/netinet/tcp_input.c29
-rw-r--r--sys/netinet/tcp_lro.c68
-rw-r--r--sys/netinet/tcp_lro.h8
-rw-r--r--sys/netinet/tcp_output.c12
-rw-r--r--sys/netinet/tcp_subr.c24
-rw-r--r--sys/netinet/tcp_syncache.c6
-rw-r--r--sys/netinet/tcp_timer.c2
-rw-r--r--sys/netinet/tcp_timewait.c2
-rw-r--r--sys/netinet/tcp_usrreq.c2
-rw-r--r--sys/netinet/tcp_var.h16
-rw-r--r--sys/netinet/udp_usrreq.c42
-rw-r--r--sys/netinet6/in6.c2
-rw-r--r--sys/netinet6/in6_ifattach.c26
-rw-r--r--sys/netinet6/in6_ifattach.h1
-rw-r--r--sys/netinet6/in6_pcb.c15
-rw-r--r--sys/netinet6/in6_pcbgroup.c1
-rw-r--r--sys/netinet6/in6_src.c42
-rw-r--r--sys/netinet6/ip6_input.c35
-rw-r--r--sys/netinet6/ip6_output.c19
-rw-r--r--sys/netinet6/nd6.c62
-rw-r--r--sys/netinet6/nd6.h5
-rw-r--r--sys/netinet6/nd6_nbr.c31
-rw-r--r--sys/netinet6/nd6_rtr.c60
-rw-r--r--sys/netinet6/udp6_usrreq.c4
-rw-r--r--sys/netipsec/ipsec_output.c2
-rw-r--r--sys/netpfil/pf/pf.c10
-rw-r--r--sys/nfs/bootp_subr.c94
-rw-r--r--sys/nfs/nfs_diskless.c1
-rw-r--r--sys/ofed/drivers/infiniband/core/iwcm.c5
-rw-r--r--sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h2
-rw-r--r--sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c5
-rw-r--r--sys/ofed/drivers/net/mlx4/en_port.c5
-rw-r--r--sys/ofed/drivers/net/mlx4/en_rx.c11
-rw-r--r--sys/ofed/drivers/net/mlx4/en_tx.c2
-rw-r--r--sys/pc98/pc98/canbus.c6
-rw-r--r--sys/powerpc/include/bus.h5
-rw-r--r--sys/powerpc/mpc85xx/fsl_sdhc.c2
-rw-r--r--sys/powerpc/mpc85xx/lbc.c8
-rw-r--r--sys/powerpc/mpc85xx/pci_mpc85xx.c3
-rw-r--r--sys/powerpc/ofw/ofw_pci.c8
-rw-r--r--sys/powerpc/powermac/cpcht.c2
-rw-r--r--sys/powerpc/powermac/grackle.c5
-rw-r--r--sys/powerpc/powermac/macgpio.c4
-rw-r--r--sys/powerpc/powermac/macio.c8
-rw-r--r--sys/powerpc/powermac/uninorth.c10
-rw-r--r--sys/powerpc/powermac/uninorthpci.c5
-rw-r--r--sys/powerpc/powermac/uninorthvar.h2
-rw-r--r--sys/powerpc/powerpc/nexus.c2
-rw-r--r--sys/powerpc/ps3/ps3bus.c4
-rw-r--r--sys/powerpc/pseries/rtas_pci.c5
-rw-r--r--sys/powerpc/pseries/vdevice.c2
-rw-r--r--sys/powerpc/psim/iobus.c2
-rw-r--r--sys/rpc/rpc_generic.c8
-rw-r--r--sys/rpc/svc.c2
-rw-r--r--sys/sparc64/central/central.c2
-rw-r--r--sys/sparc64/ebus/ebus.c4
-rw-r--r--sys/sparc64/fhc/fhc.c4
-rw-r--r--sys/sparc64/pci/apb.c10
-rw-r--r--sys/sparc64/sbus/dma_sbus.c4
-rw-r--r--sys/sparc64/sbus/sbus.c4
-rw-r--r--sys/sparc64/sparc64/nexus.c4
-rw-r--r--sys/sparc64/sparc64/upa.c4
-rw-r--r--sys/sys/_types.h2
-rw-r--r--sys/sys/aio.h2
-rw-r--r--sys/sys/bus.h1
-rw-r--r--sys/sys/fail.h246
-rw-r--r--sys/sys/file.h6
-rw-r--r--sys/sys/intr.h131
-rw-r--r--sys/sys/libkern.h10
-rw-r--r--sys/sys/mbuf.h54
-rw-r--r--sys/sys/osd.h8
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/proc.h3
-rw-r--r--sys/sys/racct.h5
-rw-r--r--sys/sys/sleepqueue.h6
-rw-r--r--sys/sys/smp.h68
-rw-r--r--sys/sys/socket.h1
-rw-r--r--sys/sys/syscall.h2
-rw-r--r--sys/sys/syscall.mk2
-rw-r--r--sys/sys/sysctl.h26
-rw-r--r--sys/sys/sysproto.h2
-rw-r--r--sys/sys/systm.h17
-rw-r--r--sys/ufs/ffs/ffs_alloc.c6
-rw-r--r--sys/ufs/ffs/ffs_softdep.c2
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c13
-rw-r--r--sys/ufs/ufs/ufs_extattr.c2
-rw-r--r--sys/ufs/ufs/ufsmount.h9
-rw-r--r--sys/x86/include/apicreg.h5
-rw-r--r--sys/x86/include/specialreg.h4
-rw-r--r--sys/x86/include/x86_var.h7
-rw-r--r--sys/x86/x86/autoconf.c (renamed from sys/i386/i386/autoconf.c)11
-rw-r--r--sys/x86/x86/intr_machdep.c15
-rw-r--r--sys/x86/x86/io_apic.c8
-rw-r--r--sys/x86/x86/local_apic.c275
-rw-r--r--sys/x86/x86/mp_x86.c767
-rw-r--r--sys/x86/x86/nexus.c6
663 files changed, 34942 insertions, 6862 deletions
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c
deleted file mode 100644
index ee32740..0000000
--- a/sys/amd64/amd64/autoconf.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * William Jolitz.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- *
- * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * Setup the system to run on the current machine.
- *
- * Configure() is called at boot time and initializes the vba
- * device tables and the memory controller monitoring. Available
- * devices are determined (from possibilities mentioned in ioconf.c),
- * and the drivers are initialized.
- */
-#include "opt_bootp.h"
-#include "opt_isa.h"
-#include "opt_bus.h"
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/reboot.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/mount.h>
-#include <sys/cons.h>
-
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/if_var.h>
-#include <net/ethernet.h>
-#include <netinet/in.h>
-
-#include <machine/md_var.h>
-
-#ifdef DEV_ISA
-#include <isa/isavar.h>
-
-device_t isa_bus_device = 0;
-#endif
-
-static void configure_first(void *);
-static void configure(void *);
-static void configure_final(void *);
-
-SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);
-/* SI_ORDER_SECOND is hookable */
-SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);
-/* SI_ORDER_MIDDLE is hookable */
-SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);
-
-/*
- * Determine i/o configuration for a machine.
- */
-static void
-configure_first(dummy)
- void *dummy;
-{
-
- /* nexus0 is the top of the amd64 device tree */
- device_add_child(root_bus, "nexus", 0);
-}
-
-static void
-configure(dummy)
- void *dummy;
-{
-
- /*
- * Enable interrupts on the processor. The interrupts are still
- * disabled in the interrupt controllers until interrupt handlers
- * are registered.
- */
- enable_intr();
-
- /* initialize new bus architecture */
- root_bus_configure();
-
-#ifdef DEV_ISA
- /*
- * Explicitly probe and attach ISA last. The isa bus saves
- * it's device node at attach time for us here.
- */
- if (isa_bus_device)
- isa_probe_children(isa_bus_device);
-#endif
-}
-
-static void
-configure_final(dummy)
- void *dummy;
-{
-
- cninit_finish();
- if (bootverbose)
- printf("Device configuration finished.\n");
- cold = 0;
-}
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
index 7d9a748..7f6c50e 100644
--- a/sys/amd64/amd64/sys_machdep.c
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -580,8 +580,8 @@ amd64_set_ldt(td, uap, descs)
struct i386_ldt_args *uap;
struct user_segment_descriptor *descs;
{
- int error = 0, i;
- int largest_ld;
+ int error = 0;
+ unsigned int largest_ld, i;
struct mdproc *mdp = &td->td_proc->p_md;
struct proc_ldt *pldt;
struct user_segment_descriptor *dp;
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 13241ac..ee6dccd 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -102,8 +102,8 @@ get_pcb_user_save_td(struct thread *td)
vm_offset_t p;
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
- cpu_max_ext_state_size;
- KASSERT((p % 64) == 0, ("Unaligned pcb_user_save area"));
+ roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN);
+ KASSERT((p % XSAVE_AREA_ALIGN) == 0, ("Unaligned pcb_user_save area"));
return ((struct savefpu *)p);
}
@@ -122,7 +122,8 @@ get_pcb_td(struct thread *td)
vm_offset_t p;
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
- cpu_max_ext_state_size - sizeof(struct pcb);
+ roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN) -
+ sizeof(struct pcb);
return ((struct pcb *)p);
}
diff --git a/sys/amd64/cloudabi64/cloudabi64_sysvec.c b/sys/amd64/cloudabi64/cloudabi64_sysvec.c
index 7075488..16d3ef9 100644
--- a/sys/amd64/cloudabi64/cloudabi64_sysvec.c
+++ b/sys/amd64/cloudabi64/cloudabi64_sysvec.c
@@ -156,5 +156,6 @@ Elf64_Brandinfo cloudabi64_brand = {
.brand = ELFOSABI_CLOUDABI,
.machine = EM_X86_64,
.sysvec = &cloudabi64_elf_sysvec,
+ .flags = BI_CAN_EXEC_DYN,
.compat_3_brand = "CloudABI",
};
diff --git a/sys/amd64/conf/GENERIC.hints b/sys/amd64/conf/GENERIC.hints
index 39beae1..31311d0 100644
--- a/sys/amd64/conf/GENERIC.hints
+++ b/sys/amd64/conf/GENERIC.hints
@@ -30,6 +30,5 @@ hint.atrtc.0.irq="8"
hint.attimer.0.at="isa"
hint.attimer.0.port="0x40"
hint.attimer.0.irq="0"
-hint.wbwd.0.at="isa"
hint.acpi_throttle.0.disabled="1"
hint.p4tcc.0.disabled="1"
diff --git a/sys/amd64/include/intr_machdep.h b/sys/amd64/include/intr_machdep.h
index d37c795..22f9a49 100644
--- a/sys/amd64/include/intr_machdep.h
+++ b/sys/amd64/include/intr_machdep.h
@@ -83,7 +83,7 @@
#ifndef LOCORE
-typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
+typedef void inthand_t(void);
#define IDTVEC(name) __CONCAT(X,name)
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index ddeb257..e4c50eb 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -36,9 +36,6 @@
extern uint64_t *vm_page_dump;
-/* XXX */
-typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
-
struct savefpu;
void amd64_db_resume_dbreg(void);
diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c
index e4e9f50..1104651 100644
--- a/sys/amd64/linux32/linux32_dummy.c
+++ b/sys/amd64/linux32/linux32_dummy.c
@@ -69,7 +69,6 @@ DUMMY(mincore);
DUMMY(ptrace);
DUMMY(lookup_dcookie);
DUMMY(remap_file_pages);
-DUMMY(fstatfs64);
DUMMY(mbind);
DUMMY(get_mempolicy);
DUMMY(set_mempolicy);
diff --git a/sys/amd64/linux32/linux32_proto.h b/sys/amd64/linux32/linux32_proto.h
index e76384f..fd74495 100644
--- a/sys/amd64/linux32/linux32_proto.h
+++ b/sys/amd64/linux32/linux32_proto.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#ifndef _LINUX32_SYSPROTO_H_
@@ -844,7 +844,9 @@ struct linux_statfs64_args {
char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)];
};
struct linux_fstatfs64_args {
- register_t dummy;
+ char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)];
+ char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)];
+ char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)];
};
struct linux_tgkill_args {
char tgid_l_[PADL_(int)]; int tgid; char tgid_r_[PADR_(int)];
diff --git a/sys/amd64/linux32/linux32_syscall.h b/sys/amd64/linux32/linux32_syscall.h
index 990adf3..f213377 100644
--- a/sys/amd64/linux32/linux32_syscall.h
+++ b/sys/amd64/linux32/linux32_syscall.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#define LINUX32_SYS_linux_exit 1
diff --git a/sys/amd64/linux32/linux32_syscalls.c b/sys/amd64/linux32/linux32_syscalls.c
index 79b96a7..beb6efc 100644
--- a/sys/amd64/linux32/linux32_syscalls.c
+++ b/sys/amd64/linux32/linux32_syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
const char *linux32_syscallnames[] = {
diff --git a/sys/amd64/linux32/linux32_sysent.c b/sys/amd64/linux32/linux32_sysent.c
index 7d6d220..baa9baa 100644
--- a/sys/amd64/linux32/linux32_sysent.c
+++ b/sys/amd64/linux32/linux32_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#include "opt_compat.h"
@@ -288,7 +288,7 @@ struct sysent linux32_sysent[] = {
{ AS(linux_clock_getres_args), (sy_call_t *)linux_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 266 = linux_clock_getres */
{ AS(linux_clock_nanosleep_args), (sy_call_t *)linux_clock_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 267 = linux_clock_nanosleep */
{ AS(linux_statfs64_args), (sy_call_t *)linux_statfs64, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 268 = linux_statfs64 */
- { 0, (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */
+ { AS(linux_fstatfs64_args), (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */
{ AS(linux_tgkill_args), (sy_call_t *)linux_tgkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 270 = linux_tgkill */
{ AS(linux_utimes_args), (sy_call_t *)linux_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 271 = linux_utimes */
{ AS(linux_fadvise64_64_args), (sy_call_t *)linux_fadvise64_64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_fadvise64_64 */
diff --git a/sys/amd64/linux32/linux32_systrace_args.c b/sys/amd64/linux32/linux32_systrace_args.c
index 80889bf..fc4c89a 100644
--- a/sys/amd64/linux32/linux32_systrace_args.c
+++ b/sys/amd64/linux32/linux32_systrace_args.c
@@ -1820,7 +1820,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_fstatfs64 */
case 269: {
- *n_args = 0;
+ struct linux_fstatfs64_args *p = params;
+ iarg[0] = p->fd; /* l_uint */
+ uarg[1] = p->bufsize; /* size_t */
+ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */
+ *n_args = 3;
break;
}
/* linux_tgkill */
@@ -5118,6 +5122,19 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_fstatfs64 */
case 269:
+ switch(ndx) {
+ case 0:
+ p = "l_uint";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "struct l_statfs64_buf *";
+ break;
+ default:
+ break;
+ };
break;
/* linux_tgkill */
case 270:
@@ -6878,6 +6895,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_fstatfs64 */
case 269:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_tgkill */
case 270:
if (ndx == 0 || ndx == 1)
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index 0396b30..e40247e 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -450,7 +450,7 @@
267 AUE_NULL STD { int linux_clock_nanosleep(clockid_t which, int flags, \
struct l_timespec *rqtp, struct l_timespec *rmtp); }
268 AUE_STATFS STD { int linux_statfs64(char *path, size_t bufsize, struct l_statfs64_buf *buf); }
-269 AUE_FSTATFS STD { int linux_fstatfs64(void); }
+269 AUE_FSTATFS STD { int linux_fstatfs64(l_uint fd, size_t bufsize, struct l_statfs64_buf *buf); }
270 AUE_NULL STD { int linux_tgkill(int tgid, int pid, int sig); }
271 AUE_UTIMES STD { int linux_utimes(char *fname, \
struct l_timeval *tptr); }
diff --git a/sys/arm/allwinner/a10_gpio.c b/sys/arm/allwinner/a10_gpio.c
index df774b3..0eae992 100644
--- a/sys/arm/allwinner/a10_gpio.c
+++ b/sys/arm/allwinner/a10_gpio.c
@@ -136,8 +136,6 @@ extern const struct allwinner_padconf a31s_padconf;
#define A10_GPIO_GP_INT_STA 0x214
#define A10_GPIO_GP_INT_DEB 0x218
-static struct a10_gpio_softc *a10_gpio_sc;
-
#define A10_GPIO_WRITE(_sc, _off, _val) \
bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
#define A10_GPIO_READ(_sc, _off) \
@@ -562,12 +560,6 @@ a10_gpio_attach(device_t dev)
/* Node is not a GPIO controller. */
goto fail;
- a10_gpio_sc = sc;
- sc->sc_busdev = gpiobus_attach_bus(dev);
- if (sc->sc_busdev == NULL)
- goto fail;
-
-
/* Use the right pin data for the current SoC */
switch (allwinner_soc_type()) {
#ifdef SOC_ALLWINNER_A10
@@ -594,6 +586,10 @@ a10_gpio_attach(device_t dev)
return (ENOENT);
}
+ sc->sc_busdev = gpiobus_attach_bus(dev);
+ if (sc->sc_busdev == NULL)
+ goto fail;
+
/*
* Register as a pinctrl device
*/
diff --git a/sys/arm/allwinner/a10_hdmi.c b/sys/arm/allwinner/a10_hdmi.c
index 9bb9869..ff86fa0 100644
--- a/sys/arm/allwinner/a10_hdmi.c
+++ b/sys/arm/allwinner/a10_hdmi.c
@@ -195,6 +195,15 @@ __FBSDID("$FreeBSD$");
#define CEA_TAG_ID 0x02
#define CEA_DTD 0x03
#define DTD_BASIC_AUDIO (1 << 6)
+#define CEA_REV 0x02
+#define CEA_DATA_OFF 0x03
+#define CEA_DATA_START 4
+#define BLOCK_TAG(x) (((x) >> 5) & 0x7)
+#define BLOCK_TAG_VSDB 3
+#define BLOCK_LEN(x) ((x) & 0x1f)
+#define HDMI_VSDB_MINLEN 5
+#define HDMI_OUI "\x03\x0c\x00"
+#define HDMI_OUI_LEN 3
struct a10hdmi_softc {
struct resource *res;
@@ -372,6 +381,41 @@ a10hdmi_ddc_read(struct a10hdmi_softc *sc, int block, uint8_t *edid)
return (0);
}
+static int
+a10hdmi_detect_hdmi_vsdb(uint8_t *edid)
+{
+ int off, p, btag, blen;
+
+ if (edid[EXT_TAG] != CEA_TAG_ID)
+ return (0);
+
+ off = edid[CEA_DATA_OFF];
+
+ /* CEA data block collection starts at byte 4 */
+ if (off <= CEA_DATA_START)
+ return (0);
+
+ /* Parse the CEA data blocks */
+ for (p = CEA_DATA_START; p < off;) {
+ btag = BLOCK_TAG(edid[p]);
+ blen = BLOCK_LEN(edid[p]);
+
+ /* Make sure the length is sane */
+ if (p + blen + 1 > off)
+ break;
+
+ /* Look for a VSDB with the HDMI 24-bit IEEE registration ID */
+ if (btag == BLOCK_TAG_VSDB && blen >= HDMI_VSDB_MINLEN &&
+ memcmp(&edid[p + 1], HDMI_OUI, HDMI_OUI_LEN) == 0)
+ return (1);
+
+ /* Next data block */
+ p += (1 + blen);
+ }
+
+ return (0);
+}
+
static void
a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio)
{
@@ -389,7 +433,7 @@ a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio)
if (a10hdmi_ddc_read(sc, block, edid) != 0)
return;
- if (edid[EXT_TAG] == CEA_TAG_ID) {
+ if (a10hdmi_detect_hdmi_vsdb(edid) != 0) {
*phdmi = 1;
*paudio = ((edid[CEA_DTD] & DTD_BASIC_AUDIO) != 0);
return;
@@ -518,6 +562,9 @@ a10hdmi_set_videomode(device_t dev, const struct videomode *mode)
PLLCTRL0_VCO_S);
/* Setup display settings */
+ if (bootverbose)
+ device_printf(dev, "HDMI: %s, Audio: %s\n",
+ sc->has_hdmi ? "yes" : "no", sc->has_audio ? "yes" : "no");
val = 0;
if (sc->has_hdmi)
val |= VID_CTRL_HDMI_MODE;
diff --git a/sys/arm/allwinner/a10_mmc.c b/sys/arm/allwinner/a10_mmc.c
index b236c4b..dc341dd 100644
--- a/sys/arm/allwinner/a10_mmc.c
+++ b/sys/arm/allwinner/a10_mmc.c
@@ -943,3 +943,4 @@ static driver_t a10_mmc_driver = {
DRIVER_MODULE(a10_mmc, simplebus, a10_mmc_driver, a10_mmc_devclass, 0, 0);
DRIVER_MODULE(mmc, a10_mmc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(a10_mmc, mmc, 1, 1, 1);
diff --git a/sys/arm/allwinner/allwinner_machdep.c b/sys/arm/allwinner/allwinner_machdep.c
index 549fdcb..7159acd 100644
--- a/sys/arm/allwinner/allwinner_machdep.c
+++ b/sys/arm/allwinner/allwinner_machdep.c
@@ -140,6 +140,7 @@ cpu_reset()
while (1);
}
+#if defined(SOC_ALLWINNER_A10)
static platform_method_t a10_methods[] = {
PLATFORMMETHOD(platform_attach, a10_attach),
PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr),
@@ -147,7 +148,10 @@ static platform_method_t a10_methods[] = {
PLATFORMMETHOD_END,
};
+FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10");
+#endif
+#if defined(SOC_ALLWINNER_A20)
static platform_method_t a20_methods[] = {
PLATFORMMETHOD(platform_attach, a20_attach),
PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr),
@@ -159,7 +163,10 @@ static platform_method_t a20_methods[] = {
#endif
PLATFORMMETHOD_END,
};
+FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20");
+#endif
+#if defined(SOC_ALLWINNER_A31)
static platform_method_t a31_methods[] = {
PLATFORMMETHOD(platform_attach, a31_attach),
PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr),
@@ -171,7 +178,10 @@ static platform_method_t a31_methods[] = {
#endif
PLATFORMMETHOD_END,
};
+FDT_PLATFORM_DEF(a31, "a31", 0, "allwinner,sun6i-a31");
+#endif
+#if defined(SOC_ALLWINNER_A31S)
static platform_method_t a31s_methods[] = {
PLATFORMMETHOD(platform_attach, a31s_attach),
PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr),
@@ -183,6 +193,8 @@ static platform_method_t a31s_methods[] = {
#endif
PLATFORMMETHOD_END,
};
+FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s");
+#endif
u_int
allwinner_soc_type(void)
@@ -195,8 +207,3 @@ allwinner_soc_family(void)
{
return (soc_family);
}
-
-FDT_PLATFORM_DEF(a10, "a10", 0, "allwinner,sun4i-a10");
-FDT_PLATFORM_DEF(a20, "a20", 0, "allwinner,sun7i-a20");
-FDT_PLATFORM_DEF(a31, "a31", 0, "allwinner,sun6i-a31");
-FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s");
diff --git a/sys/arm/amlogic/aml8726/aml8726_mmc.c b/sys/arm/amlogic/aml8726/aml8726_mmc.c
index a7cc9c1..0e24975 100644
--- a/sys/arm/amlogic/aml8726/aml8726_mmc.c
+++ b/sys/arm/amlogic/aml8726/aml8726_mmc.c
@@ -1099,3 +1099,4 @@ DRIVER_MODULE(aml8726_mmc, simplebus, aml8726_mmc_driver,
aml8726_mmc_devclass, 0, 0);
MODULE_DEPEND(aml8726_mmc, aml8726_gpio, 1, 1, 1);
DRIVER_MODULE(mmc, aml8726_mmc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(aml8726_mmc, mmc, 1, 1, 1);
diff --git a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c
index fc6a66e..3daa99f 100644
--- a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c
+++ b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c
@@ -1378,3 +1378,4 @@ DRIVER_MODULE(aml8726_sdxc, simplebus, aml8726_sdxc_driver,
aml8726_sdxc_devclass, 0, 0);
MODULE_DEPEND(aml8726_sdxc, aml8726_gpio, 1, 1, 1);
DRIVER_MODULE(mmc, aml8726_sdxc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(aml8726_sdxc, mmc, 1, 1, 1);
diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c
index cf72820..23b9577 100644
--- a/sys/arm/arm/gic.c
+++ b/sys/arm/arm/gic.c
@@ -36,8 +36,6 @@ __FBSDID("$FreeBSD$");
#include "opt_platform.h"
-#include "opt_platform.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -86,6 +84,7 @@ __FBSDID("$FreeBSD$");
#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
+#define GICD_SGI_TARGET_SHIFT 16
/* CPU Registers */
#define GICC_CTLR 0x0000 /* v1 ICCICR */
@@ -118,16 +117,28 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef ARM_INTRNG
+struct gic_irqsrc {
+ struct intr_irqsrc gi_isrc;
+ uint32_t gi_irq;
+ enum intr_polarity gi_pol;
+ enum intr_trigger gi_trig;
+};
+
static u_int gic_irq_cpu;
static int arm_gic_intr(void *);
-static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc);
+static int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc);
+
+#ifdef SMP
+u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1];
+u_int sgi_first_unused = GIC_FIRST_SGI;
+#endif
#endif
struct arm_gic_softc {
device_t gic_dev;
#ifdef ARM_INTRNG
void * gic_intrhand;
- struct intr_irqsrc ** gic_irqs;
+ struct gic_irqsrc * gic_irqs;
#endif
struct resource * gic_res[3];
bus_space_tag_t gic_c_bst;
@@ -142,6 +153,10 @@ struct arm_gic_softc {
#endif
};
+#ifdef ARM_INTRNG
+#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc)
+#endif
+
static struct resource_spec arm_gic_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */
@@ -151,6 +166,8 @@ static struct resource_spec arm_gic_spec[] = {
{ -1, 0 }
};
+static u_int arm_gic_map[MAXCPU];
+
static struct arm_gic_softc *gic_sc = NULL;
#define gic_c_read_4(_sc, _reg) \
@@ -210,6 +227,29 @@ gic_irq_mask(struct arm_gic_softc *sc, u_int irq)
}
#endif
+static uint8_t
+gic_cpu_mask(struct arm_gic_softc *sc)
+{
+ uint32_t mask;
+ int i;
+
+ /* Read the current cpuid mask by reading ITARGETSR{0..7} */
+ for (i = 0; i < 8; i++) {
+ mask = gic_d_read_4(sc, GICD_ITARGETSR(i));
+ if (mask != 0)
+ break;
+ }
+ /* No mask found, assume we are on CPU interface 0 */
+ if (mask == 0)
+ return (1);
+
+ /* Collect the mask in the lower byte */
+ mask |= mask >> 16;
+ mask |= mask >> 8;
+
+ return (mask);
+}
+
#ifdef SMP
#ifdef ARM_INTRNG
static void
@@ -219,6 +259,9 @@ arm_gic_init_secondary(device_t dev)
struct intr_irqsrc *isrc;
u_int irq;
+ /* Set the mask so we can find this CPU to send it IPIs */
+ arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
+
for (irq = 0; irq < sc->nirqs; irq += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0);
@@ -238,7 +281,7 @@ arm_gic_init_secondary(device_t dev)
/* Unmask attached SGI interrupts. */
for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) {
- isrc = sc->gic_irqs[irq];
+ isrc = GIC_INTR_ISRC(sc, irq);
if (isrc != NULL && isrc->isrc_handlers != 0) {
CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
gic_irq_unmask(sc, irq);
@@ -247,7 +290,7 @@ arm_gic_init_secondary(device_t dev)
/* Unmask attached PPI interrupts. */
for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) {
- isrc = sc->gic_irqs[irq];
+ isrc = GIC_INTR_ISRC(sc, irq);
if (isrc == NULL || isrc->isrc_handlers == 0)
continue;
if (isrc->isrc_flags & INTR_ISRCF_BOUND) {
@@ -266,6 +309,9 @@ arm_gic_init_secondary(device_t dev)
struct arm_gic_softc *sc = device_get_softc(dev);
int i;
+ /* Set the mask so we can find this CPU to send it IPIs */
+ arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
+
for (i = 0; i < sc->nirqs; i += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
@@ -364,6 +410,46 @@ gic_xref(device_t dev)
return (0);
#endif
}
+
+static int
+arm_gic_register_isrcs(struct arm_gic_softc *sc, uint32_t num)
+{
+ int error;
+ uint32_t irq;
+ struct gic_irqsrc *irqs;
+ struct intr_irqsrc *isrc;
+ const char *name;
+
+ irqs = malloc(num * sizeof(struct gic_irqsrc), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ name = device_get_nameunit(sc->gic_dev);
+ for (irq = 0; irq < num; irq++) {
+ irqs[irq].gi_irq = irq;
+ irqs[irq].gi_pol = INTR_POLARITY_CONFORM;
+ irqs[irq].gi_trig = INTR_TRIGGER_CONFORM;
+
+ isrc = &irqs[irq].gi_isrc;
+ if (irq <= GIC_LAST_SGI) {
+ error = intr_isrc_register(isrc, sc->gic_dev,
+ INTR_ISRCF_IPI, "%s,i%u", name, irq - GIC_FIRST_SGI);
+ } else if (irq <= GIC_LAST_PPI) {
+ error = intr_isrc_register(isrc, sc->gic_dev,
+ INTR_ISRCF_PPI, "%s,p%u", name, irq - GIC_FIRST_PPI);
+ } else {
+ error = intr_isrc_register(isrc, sc->gic_dev, 0,
+ "%s,s%u", name, irq - GIC_FIRST_SPI);
+ }
+ if (error != 0) {
+ /* XXX call intr_isrc_deregister() */
+ free(irqs, M_DEVBUF);
+ return (error);
+ }
+ }
+ sc->gic_irqs = irqs;
+ sc->nirqs = num;
+ return (0);
+}
#endif
static int
@@ -371,7 +457,7 @@ arm_gic_attach(device_t dev)
{
struct arm_gic_softc *sc;
int i;
- uint32_t icciidr;
+ uint32_t icciidr, mask, nirqs;
#ifdef ARM_INTRNG
phandle_t pxref;
intptr_t xref = gic_xref(dev);
@@ -405,13 +491,17 @@ arm_gic_attach(device_t dev)
gic_d_write_4(sc, GICD_CTLR, 0x00);
/* Get the number of interrupts */
- sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
- sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
+ nirqs = gic_d_read_4(sc, GICD_TYPER);
+ nirqs = 32 * ((nirqs & 0x1f) + 1);
#ifdef ARM_INTRNG
- sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF,
- M_WAITOK | M_ZERO);
+ if (arm_gic_register_isrcs(sc, nirqs)) {
+ device_printf(dev, "could not register irqs\n");
+ goto cleanup;
+ }
#else
+ sc->nirqs = nirqs;
+
/* Set up function pointers */
arm_post_filter = gic_post_filter;
arm_config_irq = gic_config_irq;
@@ -432,10 +522,19 @@ arm_gic_attach(device_t dev)
gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
}
+ /* Find the current cpu mask */
+ mask = gic_cpu_mask(sc);
+ /* Set the mask so we can find this CPU to send it IPIs */
+ arm_gic_map[PCPU_GET(cpuid)] = mask;
+ /* Set all four targets to this cpu */
+ mask |= mask << 8;
+ mask |= mask << 16;
+
for (i = 0; i < sc->nirqs; i += 4) {
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
- gic_d_write_4(sc, GICD_ITARGETSR(i >> 2),
- 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
+ if (i > 32) {
+ gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
+ }
}
/* Set all the interrupts to be in Group 0 (secure) */
@@ -473,20 +572,20 @@ arm_gic_attach(device_t dev)
if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc,
GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) {
device_printf(dev, "could not set PIC as a root\n");
- intr_pic_unregister(dev, xref);
+ intr_pic_deregister(dev, xref);
goto cleanup;
}
} else {
if (sc->gic_res[2] == NULL) {
device_printf(dev,
"not root PIC must have defined interrupt\n");
- intr_pic_unregister(dev, xref);
+ intr_pic_deregister(dev, xref);
goto cleanup;
}
if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK,
arm_gic_intr, NULL, sc, &sc->gic_intrhand)) {
device_printf(dev, "could not setup irq handler\n");
- intr_pic_unregister(dev, xref);
+ intr_pic_deregister(dev, xref);
goto cleanup;
}
}
@@ -510,7 +609,7 @@ static int
arm_gic_intr(void *arg)
{
struct arm_gic_softc *sc = arg;
- struct intr_irqsrc *isrc;
+ struct gic_irqsrc *gi;
uint32_t irq_active_reg, irq;
struct trapframe *tf;
@@ -546,14 +645,7 @@ arm_gic_intr(void *arg)
tf = curthread->td_intr_frame;
dispatch_irq:
- isrc = sc->gic_irqs[irq];
- if (isrc == NULL) {
- device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq);
- gic_irq_mask(sc, irq);
- gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
- goto next_irq;
- }
-
+ gi = sc->gic_irqs + irq;
/*
* Note that GIC_FIRST_SGI is zero and is not used in 'if' statement
* as compiler complains that comparing u_int >= 0 is always true.
@@ -562,7 +654,7 @@ dispatch_irq:
#ifdef SMP
/* Call EOI for all IPI before dispatch. */
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
- intr_ipi_dispatch(isrc, tf);
+ intr_ipi_dispatch(sgi_to_ipi[gi->gi_irq], tf);
goto next_irq;
#else
device_printf(sc->gic_dev, "SGI %u on UP system detected\n",
@@ -575,10 +667,15 @@ dispatch_irq:
#ifdef GIC_DEBUG_SPURIOUS
sc->last_irq[PCPU_GET(cpuid)] = irq;
#endif
- if (isrc->isrc_trig == INTR_TRIGGER_EDGE)
+ if (gi->gi_trig == INTR_TRIGGER_EDGE)
gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
- intr_irq_dispatch(isrc, tf);
+ if (intr_isrc_dispatch(&gi->gi_isrc, tf) != 0) {
+ gic_irq_mask(sc, irq);
+ if (gi->gi_trig != INTR_TRIGGER_EDGE)
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ device_printf(sc->gic_dev, "Stray irq %u disabled\n", irq);
+ }
next_irq:
arm_irq_memory_barrier(irq);
@@ -590,52 +687,6 @@ next_irq:
return (FILTER_HANDLED);
}
-static int
-gic_attach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq)
-{
- const char *name;
-
- /*
- * 1. The link between ISRC and controller must be set atomically.
- * 2. Just do things only once in rare case when consumers
- * of shared interrupt came here at the same moment.
- */
- mtx_lock_spin(&sc->mutex);
- if (sc->gic_irqs[irq] != NULL) {
- mtx_unlock_spin(&sc->mutex);
- return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST);
- }
- sc->gic_irqs[irq] = isrc;
- isrc->isrc_data = irq;
- mtx_unlock_spin(&sc->mutex);
-
- name = device_get_nameunit(sc->gic_dev);
- if (irq <= GIC_LAST_SGI)
- intr_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI);
- else if (irq <= GIC_LAST_PPI)
- intr_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI);
- else
- intr_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI);
- return (0);
-}
-
-static int
-gic_detach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq)
-{
-
- mtx_lock_spin(&sc->mutex);
- if (sc->gic_irqs[irq] != isrc) {
- mtx_unlock_spin(&sc->mutex);
- return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL);
- }
- sc->gic_irqs[irq] = NULL;
- isrc->isrc_data = 0;
- mtx_unlock_spin(&sc->mutex);
-
- intr_irq_set_name(isrc, "");
- return (0);
-}
-
static void
gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig,
enum intr_polarity pol)
@@ -693,127 +744,163 @@ gic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus)
return (0);
}
+#ifdef FDT
static int
-gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp)
+gic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp,
+ enum intr_polarity *polp, enum intr_trigger *trigp)
{
- switch (type) {
- case INTR_IRQ_NSPC_PLAIN:
- *irqp = num;
- return (*irqp < sc->nirqs ? 0 : EINVAL);
+ if (ncells == 1) {
+ *irqp = cells[0];
+ *polp = INTR_POLARITY_CONFORM;
+ *trigp = INTR_TRIGGER_CONFORM;
+ return (0);
+ }
+ if (ncells == 3) {
+ u_int irq, tripol;
- case INTR_IRQ_NSPC_IRQ:
- *irqp = num + GIC_FIRST_PPI;
- return (*irqp < sc->nirqs ? 0 : EINVAL);
+ /*
+ * The 1st cell is the interrupt type:
+ * 0 = SPI
+ * 1 = PPI
+ * The 2nd cell contains the interrupt number:
+ * [0 - 987] for SPI
+ * [0 - 15] for PPI
+ * The 3rd cell is the flags, encoded as follows:
+ * bits[3:0] trigger type and level flags
+ * 1 = low-to-high edge triggered
+ * 2 = high-to-low edge triggered
+ * 4 = active high level-sensitive
+ * 8 = active low level-sensitive
+ * bits[15:8] PPI interrupt cpu mask
+ * Each bit corresponds to each of the 8 possible cpus
+ * attached to the GIC. A bit set to '1' indicated
+ * the interrupt is wired to that CPU.
+ */
+ switch (cells[0]) {
+ case 0:
+ irq = GIC_FIRST_SPI + cells[1];
+ /* SPI irq is checked later. */
+ break;
+ case 1:
+ irq = GIC_FIRST_PPI + cells[1];
+ if (irq > GIC_LAST_PPI) {
+ device_printf(dev, "unsupported PPI interrupt "
+ "number %u\n", cells[1]);
+ return (EINVAL);
+ }
+ break;
+ default:
+ device_printf(dev, "unsupported interrupt type "
+ "configuration %u\n", cells[0]);
+ return (EINVAL);
+ }
- case INTR_IRQ_NSPC_IPI:
- *irqp = num + GIC_FIRST_SGI;
- return (*irqp < GIC_LAST_SGI ? 0 : EINVAL);
+ tripol = cells[2] & 0xff;
+ if (tripol & 0xf0 || (tripol & 0x0a && cells[0] == 0))
+ device_printf(dev, "unsupported trigger/polarity "
+ "configuration 0x%02x\n", tripol);
- default:
- return (EINVAL);
+ *irqp = irq;
+ *polp = INTR_POLARITY_CONFORM;
+ *trigp = tripol & 0x03 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL;
+ return (0);
}
+ return (EINVAL);
}
+#endif
static int
-gic_map_nspc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
-{
- int error;
-
- error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num,
- irqp);
- if (error != 0)
- return (error);
- return (gic_attach_isrc(sc, isrc, *irqp));
-}
-
-#ifdef FDT
-static int
-gic_map_fdt(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
+gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
+ enum intr_polarity *polp, enum intr_trigger *trigp)
{
- u_int irq, tripol;
- enum intr_trigger trig;
+ u_int irq;
enum intr_polarity pol;
- int error;
-
- if (isrc->isrc_ncells == 1) {
- irq = isrc->isrc_cells[0];
- pol = INTR_POLARITY_CONFORM;
- trig = INTR_TRIGGER_CONFORM;
- } else if (isrc->isrc_ncells == 3) {
- if (isrc->isrc_cells[0] == 0)
- irq = isrc->isrc_cells[1] + GIC_FIRST_SPI;
- else
- irq = isrc->isrc_cells[1] + GIC_FIRST_PPI;
+ enum intr_trigger trig;
+ struct arm_gic_softc *sc;
- /*
- * In intr[2], bits[3:0] are trigger type and level flags.
- * 1 = low-to-high edge triggered
- * 2 = high-to-low edge triggered
- * 4 = active high level-sensitive
- * 8 = active low level-sensitive
- * The hardware only supports active-high-level or rising-edge.
- */
- tripol = isrc->isrc_cells[2];
- if (tripol & 0x0a && irq >= GIC_FIRST_SPI) {
- device_printf(sc->gic_dev,
- "unsupported trigger/polarity configuration "
- "0x%02x\n", tripol & 0x0f);
- }
- pol = INTR_POLARITY_CONFORM;
- if (tripol & 0x03)
- trig = INTR_TRIGGER_EDGE;
- else
- trig = INTR_TRIGGER_LEVEL;
- } else
+ sc = device_get_softc(dev);
+ switch (data->type) {
+#ifdef FDT
+ case INTR_MAP_DATA_FDT:
+ if (gic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq,
+ &pol, &trig) != 0)
+ return (EINVAL);
+ break;
+#endif
+ default:
return (EINVAL);
+ }
if (irq >= sc->nirqs)
return (EINVAL);
-
- error = gic_attach_isrc(sc, isrc, irq);
- if (error != 0)
- return (error);
-
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN;
- isrc->isrc_nspc_num = irq;
- isrc->isrc_trig = trig;
- isrc->isrc_pol = pol;
+ if (pol != INTR_POLARITY_CONFORM && pol != INTR_POLARITY_LOW &&
+ pol != INTR_POLARITY_HIGH)
+ return (EINVAL);
+ if (trig != INTR_TRIGGER_CONFORM && trig != INTR_TRIGGER_EDGE &&
+ trig != INTR_TRIGGER_LEVEL)
+ return (EINVAL);
*irqp = irq;
+ if (polp != NULL)
+ *polp = pol;
+ if (trigp != NULL)
+ *trigp = trig;
return (0);
}
-#endif
static int
-arm_gic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu)
+arm_gic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
{
- struct arm_gic_softc *sc = device_get_softc(dev);
- u_int irq;
int error;
+ u_int irq;
+ struct arm_gic_softc *sc;
- if (isrc->isrc_type == INTR_ISRCT_NAMESPACE)
- error = gic_map_nspc(sc, isrc, &irq);
-#ifdef FDT
- else if (isrc->isrc_type == INTR_ISRCT_FDT)
- error = gic_map_fdt(sc, isrc, &irq);
-#endif
- else
- return (EINVAL);
-
- if (error == 0)
- *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE;
+ error = gic_map_intr(dev, data, &irq, NULL, NULL);
+ if (error == 0) {
+ sc = device_get_softc(dev);
+ *isrcp = GIC_INTR_ISRC(sc, irq);
+ }
return (error);
}
-static void
-arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+static int
+arm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
struct arm_gic_softc *sc = device_get_softc(dev);
- u_int irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
+ u_int irq;
+ enum intr_trigger trig;
+ enum intr_polarity pol;
- if (isrc->isrc_trig == INTR_TRIGGER_CONFORM)
- isrc->isrc_trig = INTR_TRIGGER_LEVEL;
+ if (data == NULL)
+ return (ENOTSUP);
+
+ /* Get config for resource. */
+ if (gic_map_intr(dev, data, &irq, &pol, &trig))
+ return (EINVAL);
+
+ if (gi->gi_irq != irq)
+ return (EINVAL);
+
+ /* Compare config if this is not first setup. */
+ if (isrc->isrc_handlers != 0) {
+ if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) ||
+ (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig))
+ return (EINVAL);
+ else
+ return (0);
+ }
+
+ if (pol == INTR_POLARITY_CONFORM)
+ pol = INTR_POLARITY_LOW; /* just pick some */
+ if (trig == INTR_TRIGGER_CONFORM)
+ trig = INTR_TRIGGER_EDGE; /* just pick some */
+
+ gi->gi_pol = pol;
+ gi->gi_trig = trig;
/*
* XXX - In case that per CPU interrupt is going to be enabled in time
@@ -822,48 +909,54 @@ arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
* pic_enable_source() and pic_disable_source() should act on
* per CPU basis only. Thus, it should be solved here somehow.
*/
- if (isrc->isrc_flags & INTR_ISRCF_PERCPU)
+ if (isrc->isrc_flags & INTR_ISRCF_PPI)
CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
- gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol);
- arm_gic_bind(dev, isrc);
+ gic_config(sc, gi->gi_irq, trig, pol);
+ arm_gic_bind_intr(dev, isrc);
+ return (0);
}
-static void
-arm_gic_enable_source(device_t dev, struct intr_irqsrc *isrc)
+static int
+arm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
- struct arm_gic_softc *sc = device_get_softc(dev);
- u_int irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
- arm_irq_memory_barrier(irq);
- gic_irq_unmask(sc, irq);
+ if (isrc->isrc_handlers == 0) {
+ gi->gi_pol = INTR_POLARITY_CONFORM;
+ gi->gi_trig = INTR_TRIGGER_CONFORM;
+ }
+ return (0);
}
static void
-arm_gic_disable_source(device_t dev, struct intr_irqsrc *isrc)
+arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct arm_gic_softc *sc = device_get_softc(dev);
- u_int irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
- gic_irq_mask(sc, irq);
+ arm_irq_memory_barrier(gi->gi_irq);
+ gic_irq_unmask(sc, gi->gi_irq);
}
-static int
-arm_gic_unregister(device_t dev, struct intr_irqsrc *isrc)
+static void
+arm_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct arm_gic_softc *sc = device_get_softc(dev);
- u_int irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
- return (gic_detach_isrc(sc, isrc, irq));
+ gic_irq_mask(sc, gi->gi_irq);
}
static void
arm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
{
struct arm_gic_softc *sc = device_get_softc(dev);
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
- arm_gic_disable_source(dev, isrc);
- gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data);
+ arm_gic_disable_intr(dev, isrc);
+ gic_c_write_4(sc, GICC_EOIR, gi->gi_irq);
}
static void
@@ -871,52 +964,66 @@ arm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
{
arm_irq_memory_barrier(0);
- arm_gic_enable_source(dev, isrc);
+ arm_gic_enable_intr(dev, isrc);
}
static void
arm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc)
{
struct arm_gic_softc *sc = device_get_softc(dev);
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
/* EOI for edge-triggered done earlier. */
- if (isrc->isrc_trig == INTR_TRIGGER_EDGE)
+ if (gi->gi_trig == INTR_TRIGGER_EDGE)
return;
arm_irq_memory_barrier(0);
- gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data);
+ gic_c_write_4(sc, GICC_EOIR, gi->gi_irq);
}
static int
-arm_gic_bind(device_t dev, struct intr_irqsrc *isrc)
+arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct arm_gic_softc *sc = device_get_softc(dev);
- uint32_t irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
- if (irq < GIC_FIRST_SPI)
+ if (gi->gi_irq < GIC_FIRST_SPI)
return (EINVAL);
if (CPU_EMPTY(&isrc->isrc_cpu)) {
gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus);
CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu);
}
- return (gic_bind(sc, irq, &isrc->isrc_cpu));
+ return (gic_bind(sc, gi->gi_irq, &isrc->isrc_cpu));
}
#ifdef SMP
static void
-arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus)
+arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
+ u_int ipi)
{
struct arm_gic_softc *sc = device_get_softc(dev);
- uint32_t irq, val = 0, i;
-
- irq = isrc->isrc_data;
+ struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
+ uint32_t val = 0, i;
for (i = 0; i < MAXCPU; i++)
if (CPU_ISSET(i, &cpus))
- val |= 1 << (16 + i);
+ val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
+
+ gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq);
+}
+
+static int
+arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
- gic_d_write_4(sc, GICD_SGIR(0), val | irq);
+ if (sgi_first_unused > GIC_LAST_SGI)
+ return (ENOSPC);
+
+ *isrcp = GIC_INTR_ISRC(sc, sgi_first_unused);
+ sgi_to_ipi[sgi_first_unused++] = ipi;
+ return (0);
}
#endif
#else
@@ -1029,7 +1136,7 @@ arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
for (i = 0; i < MAXCPU; i++)
if (CPU_ISSET(i, &cpus))
- val |= 1 << (16 + i);
+ val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
}
@@ -1134,18 +1241,19 @@ static device_method_t arm_gic_methods[] = {
DEVMETHOD(device_attach, arm_gic_attach),
#ifdef ARM_INTRNG
/* Interrupt controller interface */
- DEVMETHOD(pic_disable_source, arm_gic_disable_source),
+ DEVMETHOD(pic_disable_intr, arm_gic_disable_intr),
DEVMETHOD(pic_enable_intr, arm_gic_enable_intr),
- DEVMETHOD(pic_enable_source, arm_gic_enable_source),
+ DEVMETHOD(pic_map_intr, arm_gic_map_intr),
+ DEVMETHOD(pic_setup_intr, arm_gic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, arm_gic_teardown_intr),
DEVMETHOD(pic_post_filter, arm_gic_post_filter),
DEVMETHOD(pic_post_ithread, arm_gic_post_ithread),
DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread),
- DEVMETHOD(pic_register, arm_gic_register),
- DEVMETHOD(pic_unregister, arm_gic_unregister),
#ifdef SMP
- DEVMETHOD(pic_bind, arm_gic_bind),
+ DEVMETHOD(pic_bind_intr, arm_gic_bind_intr),
DEVMETHOD(pic_init_secondary, arm_gic_init_secondary),
DEVMETHOD(pic_ipi_send, arm_gic_ipi_send),
+ DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup),
#endif
#endif
{ 0, 0 }
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index e2310f1..ad0e699 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/cons.h>
#include <sys/cpu.h>
+#include <sys/ctype.h>
#include <sys/efi.h>
#include <sys/exec.h>
#include <sys/imgact.h>
@@ -74,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pcpu.h>
#include <sys/ptrace.h>
#include <sys/reboot.h>
+#include <sys/boot.h>
#include <sys/rwlock.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
@@ -115,6 +117,7 @@ __FBSDID("$FreeBSD$");
#include <machine/sysarch.h>
#ifdef FDT
+#include <contrib/libfdt/libfdt.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#endif
@@ -178,6 +181,12 @@ DB_SHOW_COMMAND(vtop, db_show_vtop)
#define debugf(fmt, args...)
#endif
+#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
+ defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) || \
+ defined(COMPAT_FREEBSD9)
+#error FreeBSD/arm doesn't provide compatibility with releases prior to 10
+#endif
+
struct pcpu __pcpu[MAXCPU];
struct pcpu *pcpup = &__pcpu[0];
@@ -225,6 +234,7 @@ static struct pv_addr kernelstack;
#if defined(LINUX_BOOT_ABI)
#define LBABI_MAX_BANKS 10
+#define CMDLINE_GUARD "FreeBSD:"
uint32_t board_id;
struct arm_lbabi_tag *atag_list;
char linux_command_line[LBABI_MAX_COMMAND_LINE + 1];
@@ -953,7 +963,8 @@ makectx(struct trapframe *tf, struct pcb *pcb)
* Fake up a boot descriptor table
*/
vm_offset_t
-fake_preload_metadata(struct arm_boot_params *abp __unused)
+fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr,
+ size_t dtb_size)
{
#ifdef DDB
vm_offset_t zstart = 0, zend = 0;
@@ -991,6 +1002,16 @@ fake_preload_metadata(struct arm_boot_params *abp __unused)
} else
#endif
lastaddr = (vm_offset_t)&end;
+ if (dtb_ptr != NULL) {
+ /* Copy DTB to KVA space and insert it into module chain. */
+ lastaddr = roundup(lastaddr, sizeof(int));
+ fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP;
+ fake_preload[i++] = sizeof(uint32_t);
+ fake_preload[i++] = (uint32_t)lastaddr;
+ memmove((void *)lastaddr, dtb_ptr, dtb_size);
+ lastaddr += dtb_size;
+ lastaddr = roundup(lastaddr, sizeof(int));
+ }
fake_preload[i++] = 0;
fake_preload[i] = 0;
preload_metadata = (void *)fake_preload;
@@ -1011,26 +1032,83 @@ pcpu0_init(void)
}
#if defined(LINUX_BOOT_ABI)
+
+/* Convert the U-Boot command line into FreeBSD kenv and boot options. */
+static void
+cmdline_set_env(char *cmdline, const char *guard)
+{
+ char *cmdline_next, *env;
+ size_t size, guard_len;
+ int i;
+
+ size = strlen(cmdline);
+ /* Skip leading spaces. */
+ for (; isspace(*cmdline) && (size > 0); cmdline++)
+ size--;
+
+ /* Test and remove guard. */
+ if (guard != NULL && guard[0] != '\0') {
+ guard_len = strlen(guard);
+ if (strncasecmp(cmdline, guard, guard_len) != 0)
+ return;
+ cmdline += guard_len;
+ size -= guard_len;
+ }
+
+ /* Skip leading spaces. */
+ for (; isspace(*cmdline) && (size > 0); cmdline++)
+ size--;
+
+ /* Replace ',' with '\0'. */
+ /* TODO: implement escaping for ',' character. */
+ cmdline_next = cmdline;
+ while(strsep(&cmdline_next, ",") != NULL)
+ ;
+ init_static_kenv(cmdline, 0);
+ /* Parse boothowto. */
+ for (i = 0; howto_names[i].ev != NULL; i++) {
+ env = kern_getenv(howto_names[i].ev);
+ if (env != NULL) {
+ if (strtoul(env, NULL, 10) != 0)
+ boothowto |= howto_names[i].mask;
+ freeenv(env);
+ }
+ }
+}
+
vm_offset_t
linux_parse_boot_param(struct arm_boot_params *abp)
{
struct arm_lbabi_tag *walker;
uint32_t revision;
uint64_t serial;
+ int size;
+ vm_offset_t lastaddr;
+#ifdef FDT
+ struct fdt_header *dtb_ptr;
+ uint32_t dtb_size;
+#endif
/*
* Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2
* is atags or dtb pointer. If all of these aren't satisfied,
- * then punt.
+ * then punt. Unfortunately, it looks like DT enabled kernels
+ * doesn't uses board type and U-Boot delivers 0 in r1 for them.
*/
- if (!(abp->abp_r0 == 0 && abp->abp_r1 != 0 && abp->abp_r2 != 0))
- return 0;
+ if (abp->abp_r0 != 0 || abp->abp_r2 == 0)
+ return (0);
+#ifdef FDT
+ /* Test if r2 point to valid DTB. */
+ dtb_ptr = (struct fdt_header *)abp->abp_r2;
+ if (fdt_check_header(dtb_ptr) == 0) {
+ dtb_size = fdt_totalsize(dtb_ptr);
+ return (fake_preload_metadata(abp, dtb_ptr, dtb_size));
+ }
+#endif
board_id = abp->abp_r1;
- walker = (struct arm_lbabi_tag *)
- (abp->abp_r2 + KERNVIRTADDR - abp->abp_physaddr);
+ walker = (struct arm_lbabi_tag *)abp->abp_r2;
- /* xxx - Need to also look for binary device tree */
if (ATAG_TAG(walker) != ATAG_CORE)
return 0;
@@ -1046,8 +1124,9 @@ linux_parse_boot_param(struct arm_boot_params *abp)
case ATAG_INITRD2:
break;
case ATAG_SERIAL:
- serial = walker->u.tag_sn.low |
- ((uint64_t)walker->u.tag_sn.high << 32);
+ serial = walker->u.tag_sn.high;
+ serial <<= 32;
+ serial |= walker->u.tag_sn.low;
board_set_serial(serial);
break;
case ATAG_REVISION:
@@ -1055,9 +1134,12 @@ linux_parse_boot_param(struct arm_boot_params *abp)
board_set_revision(revision);
break;
case ATAG_CMDLINE:
- /* XXX open question: Parse this for boothowto? */
- bcopy(walker->u.tag_cmd.command, linux_command_line,
- ATAG_SIZE(walker));
+ size = ATAG_SIZE(walker) -
+ sizeof(struct arm_lbabi_header);
+ size = min(size, LBABI_MAX_COMMAND_LINE);
+ strncpy(linux_command_line, walker->u.tag_cmd.command,
+ size);
+ linux_command_line[size] = '\0';
break;
default:
break;
@@ -1069,9 +1151,9 @@ linux_parse_boot_param(struct arm_boot_params *abp)
bcopy(atag_list, atags,
(char *)walker - (char *)atag_list + ATAG_SIZE(walker));
- init_static_kenv(NULL, 0);
-
- return fake_preload_metadata(abp);
+ lastaddr = fake_preload_metadata(abp, NULL, 0);
+ cmdline_set_env(linux_command_line, CMDLINE_GUARD);
+ return lastaddr;
}
#endif
@@ -1129,7 +1211,7 @@ default_parse_boot_param(struct arm_boot_params *abp)
return lastaddr;
#endif
/* Fall back to hardcoded metadata. */
- lastaddr = fake_preload_metadata(abp);
+ lastaddr = fake_preload_metadata(abp, NULL, 0);
return lastaddr;
}
@@ -1747,6 +1829,12 @@ initarm(struct arm_boot_params *abp)
if (OF_init((void *)dtbp) != 0)
panic("OF_init failed with the found device tree");
+#if defined(LINUX_BOOT_ABI)
+ if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line,
+ LBABI_MAX_COMMAND_LINE) == 0)
+ cmdline_set_env(linux_command_line, CMDLINE_GUARD);
+#endif
+
#ifdef EFI
efihdr = (struct efi_map_header *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_EFI_MAP);
diff --git a/sys/arm/arm/machdep_intr.c b/sys/arm/arm/machdep_intr.c
index 875f05e..504d262 100644
--- a/sys/arm/arm/machdep_intr.c
+++ b/sys/arm/arm/machdep_intr.c
@@ -1,8 +1,6 @@
-/* $NetBSD: intr.c,v 1.12 2003/07/15 00:24:41 lukem Exp $ */
-
/*-
- * Copyright (c) 2004 Olivier Houchard.
- * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 2015-2016 Svatopluk Kraus
+ * Copyright (c) 2015-2016 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -13,27 +11,18 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Mark Brinicombe
- * for the NetBSD Project.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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)
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * Soft interrupt and other generic interrupt functions.
*/
#include "opt_platform.h"
@@ -64,8 +53,18 @@ __FBSDID("$FreeBSD$");
#include "pic_if.h"
#ifdef SMP
-static struct intr_irqsrc ipi_sources[INTR_IPI_COUNT];
-static u_int ipi_next_num;
+#define INTR_IPI_NAMELEN (MAXCOMLEN + 1)
+
+struct intr_ipi {
+ intr_ipi_handler_t * ii_handler;
+ void * ii_handler_arg;
+ intr_ipi_send_t * ii_send;
+ void * ii_send_arg;
+ char ii_name[INTR_IPI_NAMELEN];
+ u_long * ii_count;
+};
+
+static struct intr_ipi ipi_sources[INTR_IPI_COUNT];
#endif
#endif
@@ -134,10 +133,7 @@ arm_irq_memory_barrier(uintptr_t irq)
#ifdef ARM_INTRNG
#ifdef SMP
-/*
- * Lookup IPI source.
- */
-static struct intr_irqsrc *
+static inline struct intr_ipi *
intr_ipi_lookup(u_int ipi)
{
@@ -147,112 +143,90 @@ intr_ipi_lookup(u_int ipi)
return (&ipi_sources[ipi]);
}
-/*
- * interrupt controller dispatch function for IPIs. It should
- * be called straight from the interrupt controller, when associated
- * interrupt source is learned. Or from anybody who has an interrupt
- * source mapped.
- */
void
-intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
+intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
{
void *arg;
+ struct intr_ipi *ii;
- KASSERT(isrc != NULL, ("%s: no source", __func__));
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
- intr_ipi_increment_count(isrc->isrc_count, PCPU_GET(cpuid));
+ intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
/*
* Supply ipi filter with trapframe argument
* if none is registered.
*/
- arg = isrc->isrc_arg != NULL ? isrc->isrc_arg : tf;
- isrc->isrc_ipifilter(arg);
+ arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
+ ii->ii_handler(arg);
}
-/*
- * Map IPI into interrupt controller.
- *
- * Not SMP coherent.
- */
-static int
-ipi_map(struct intr_irqsrc *isrc, u_int ipi)
+void
+intr_ipi_send(cpuset_t cpus, u_int ipi)
{
- boolean_t is_percpu;
- int error;
-
- if (ipi >= INTR_IPI_COUNT)
- panic("%s: no such IPI %u", __func__, ipi);
-
- KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ struct intr_ipi *ii;
- isrc->isrc_type = INTR_ISRCT_NAMESPACE;
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
- isrc->isrc_nspc_num = ipi_next_num;
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
- error = PIC_REGISTER(intr_irq_root_dev, isrc, &is_percpu);
- if (error == 0) {
- isrc->isrc_dev = intr_irq_root_dev;
- ipi_next_num++;
- }
- return (error);
+ ii->ii_send(ii->ii_send_arg, cpus, ipi);
}
-/*
- * Setup IPI handler to interrupt source.
- *
- * Note that there could be more ways how to send and receive IPIs
- * on a platform like fast interrupts for example. In that case,
- * one can call this function with ASIF_NOALLOC flag set and then
- * call intr_ipi_dispatch() when appropriate.
- *
- * Not SMP coherent.
- */
-int
-intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
- void *arg, u_int flags)
+void
+intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+ void *h_arg, intr_ipi_send_t *send, void *s_arg)
{
- struct intr_irqsrc *isrc;
- int error;
+ struct intr_ipi *ii;
- if (filter == NULL)
- return(EINVAL);
+ ii = intr_ipi_lookup(ipi);
- isrc = intr_ipi_lookup(ipi);
- if (isrc->isrc_ipifilter != NULL)
- return (EEXIST);
+ KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
+ KASSERT(send != NULL, ("%s: ipi %u no sender", __func__, ipi));
+ KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
- if ((flags & AISHF_NOALLOC) == 0) {
- error = ipi_map(isrc, ipi);
- if (error != 0)
- return (error);
- }
+ ii->ii_handler = hand;
+ ii->ii_handler_arg = h_arg;
+ ii->ii_send = send;
+ ii->ii_send_arg = s_arg;
+ strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
+ ii->ii_count = intr_ipi_setup_counters(name);
+}
- isrc->isrc_ipifilter = filter;
- isrc->isrc_arg = arg;
- isrc->isrc_handlers = 1;
- isrc->isrc_count = intr_ipi_setup_counters(name);
- isrc->isrc_index = 0; /* it should not be used in IPI case */
+/*
+ * Send IPI thru interrupt controller.
+ */
+static void
+pic_ipi_send(void *arg, cpuset_t cpus, u_int ipi)
+{
- if (isrc->isrc_dev != NULL) {
- PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
- PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
- }
- return (0);
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ PIC_IPI_SEND(intr_irq_root_dev, arg, cpus, ipi);
}
/*
- * Send IPI thru interrupt controller.
+ * Setup IPI handler on interrupt controller.
+ *
+ * Not SMP coherent.
*/
-void
-pic_ipi_send(cpuset_t cpus, u_int ipi)
+int
+intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+ void *arg)
{
+ int error;
struct intr_irqsrc *isrc;
- isrc = intr_ipi_lookup(ipi);
-
KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
- PIC_IPI_SEND(intr_irq_root_dev, isrc, cpus);
+
+ error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc);
+ if (error != 0)
+ return (error);
+
+ isrc->isrc_handlers++;
+ intr_ipi_setup(ipi, name, hand, arg, pic_ipi_send, isrc);
+ return (0);
}
#endif
#endif
diff --git a/sys/arm/arm/mp_machdep.c b/sys/arm/arm/mp_machdep.c
index 41958a8..699881c 100644
--- a/sys/arm/arm/mp_machdep.c
+++ b/sys/arm/arm/mp_machdep.c
@@ -429,12 +429,11 @@ release_aps(void *dummy __unused)
return;
#ifdef ARM_INTRNG
- intr_ipi_set_handler(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL, 0);
- intr_ipi_set_handler(IPI_AST, "ast", ipi_ast, NULL, 0);
- intr_ipi_set_handler(IPI_STOP, "stop", ipi_stop, NULL, 0);
- intr_ipi_set_handler(IPI_PREEMPT, "preempt", ipi_preempt, NULL, 0);
- intr_ipi_set_handler(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL, 0);
-
+ intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
+ intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
+ intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
+ intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
+ intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
#else
#ifdef IPI_IRQ_START
start = IPI_IRQ_START;
@@ -502,7 +501,11 @@ ipi_all_but_self(u_int ipi)
other_cpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &other_cpus);
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(other_cpus, ipi);
+#else
pic_ipi_send(other_cpus, ipi);
+#endif
}
void
@@ -514,7 +517,11 @@ ipi_cpu(int cpu, u_int ipi)
CPU_SET(cpu, &cpus);
CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(cpus, ipi);
+#else
pic_ipi_send(cpus, ipi);
+#endif
}
void
@@ -522,6 +529,9 @@ ipi_selected(cpuset_t cpus, u_int ipi)
{
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+ intr_ipi_send(cpus, ipi);
+#else
pic_ipi_send(cpus, ipi);
+#endif
}
-
diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c
index 035e81f..b718c1d 100644
--- a/sys/arm/arm/nexus.c
+++ b/sys/arm/arm/nexus.c
@@ -281,7 +281,8 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
int ret = ENODEV;
#ifdef ARM_INTRNG
- ret = intr_irq_config(irq, trig, pol);
+ device_printf(dev, "bus_config_intr is obsolete and not supported!\n");
+ ret = EOPNOTSUPP;
#else
if (arm_config_irq)
ret = (*arm_config_irq)(irq, trig, pol);
@@ -293,22 +294,23 @@ static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
{
+#ifndef ARM_INTRNG
int irq;
+#endif
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
- for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) {
#ifdef ARM_INTRNG
- intr_irq_add_handler(child, filt, intr, arg, irq, flags,
- cookiep);
+ return(intr_setup_irq(child, res, filt, intr, arg, flags, cookiep));
#else
+ for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) {
arm_setup_irqhandler(device_get_nameunit(child),
filt, intr, arg, irq, flags, cookiep);
arm_unmask_irq(irq);
-#endif
}
return (0);
+#endif
}
static int
@@ -316,7 +318,7 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
{
#ifdef ARM_INTRNG
- return (intr_irq_remove_handler(child, rman_get_start(r), ih));
+ return (intr_teardown_irq(child, r, ih));
#else
return (arm_remove_irqhandler(rman_get_start(r), ih));
#endif
@@ -328,7 +330,7 @@ nexus_describe_intr(device_t dev, device_t child, struct resource *irq,
void *cookie, const char *descr)
{
- return (intr_irq_describe(rman_get_start(irq), cookie, descr));
+ return (intr_describe_irq(child, irq, cookie, descr));
}
#ifdef SMP
@@ -336,7 +338,7 @@ static int
nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
{
- return (intr_irq_bind(rman_get_start(irq), cpu));
+ return (intr_bind_irq(child, irq, cpu));
}
#endif
#endif
diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c
index 70d6c70..fdab1c6 100644
--- a/sys/arm/arm/vm_machdep.c
+++ b/sys/arm/arm/vm_machdep.c
@@ -191,11 +191,7 @@ cpu_set_syscall_retval(struct thread *td, int error)
register_t code = ap[_QUAD_LOWWORD];
if (td->td_proc->p_sysent->sv_mask)
code &= td->td_proc->p_sysent->sv_mask;
- fixup = (
-#if defined(COMPAT_FREEBSD6) && defined(SYS_freebsd6_lseek)
- code != SYS_freebsd6_lseek &&
-#endif
- code != SYS_lseek) ? 1 : 0;
+ fixup = (code != SYS_lseek);
}
#endif
diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c
index 0947ec7..34c19d7 100644
--- a/sys/arm/at91/at91.c
+++ b/sys/arm/at91/at91.c
@@ -281,9 +281,9 @@ at91_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
if (device_get_flags(dev))
retval += printf(" flags %#x", device_get_flags(dev));
diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c
index 5bab815..ba6040f 100644
--- a/sys/arm/at91/at91_mci.c
+++ b/sys/arm/at91/at91_mci.c
@@ -1412,3 +1412,4 @@ DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, NULL,
NULL);
#endif
DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(at91_mci, mmc, 1, 1, 1);
diff --git a/sys/arm/at91/at91_pinctrl.c b/sys/arm/at91/at91_pinctrl.c
index e5652d1..b795d91 100644
--- a/sys/arm/at91/at91_pinctrl.c
+++ b/sys/arm/at91/at91_pinctrl.c
@@ -330,8 +330,8 @@ pinctrl_print_res(struct pinctrl_devinfo *di)
int rv;
rv = 0;
- rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/arm/at91/board_tsc4370.c b/sys/arm/at91/board_tsc4370.c
index 1bc0426..9c0658b 100644
--- a/sys/arm/at91/board_tsc4370.c
+++ b/sys/arm/at91/board_tsc4370.c
@@ -601,7 +601,7 @@ parse_boot_param(struct arm_boot_params *abp)
inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1);
}
- return fake_preload_metadata(abp);
+ return fake_preload_metadata(abp, NULL, 0);
}
ARM_BOARD(NONE, "TSC4370 Controller Board");
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_common.c b/sys/arm/broadcom/bcm2835/bcm2835_common.c
index 08f01a8..bcb84b7 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_common.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_common.c
@@ -56,14 +56,21 @@ fdt_intc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
int *pol)
{
- if (!fdt_is_compatible(node, "broadcom,bcm2835-armctrl-ic"))
- return (ENXIO);
-
- *interrupt = fdt32_to_cpu(intr[0]);
- *trig = INTR_TRIGGER_CONFORM;
- *pol = INTR_POLARITY_CONFORM;
-
- return (0);
+ if (fdt_is_compatible(node, "broadcom,bcm2835-armctrl-ic")) {
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ return (0);
+ }
+#ifdef SOC_BCM2836
+ if (fdt_is_compatible(node, "brcm,bcm2836-l1-intc")) {
+ *interrupt = fdt32_to_cpu(intr[0]) + 72;
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ return (0);
+ }
+#endif
+ return (ENXIO);
}
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
index 981d73b..700edcc 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c
@@ -672,3 +672,4 @@ static driver_t bcm_sdhci_driver = {
DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
MODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_bcm, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_bcm, mmc, 1, 1, 1);
diff --git a/sys/arm/broadcom/bcm2835/std.rpi b/sys/arm/broadcom/bcm2835/std.rpi
index c53c720..793eab1 100644
--- a/sys/arm/broadcom/bcm2835/std.rpi
+++ b/sys/arm/broadcom/bcm2835/std.rpi
@@ -2,5 +2,4 @@
options KERNVIRTADDR=0xc0100000
makeoptions KERNVIRTADDR=0xc0100000
-options FREEBSD_BOOT_LOADER
options LINUX_BOOT_ABI
diff --git a/sys/arm/cavium/cns11xx/econa.c b/sys/arm/cavium/cns11xx/econa.c
index d3dbf06..df49f1f 100644
--- a/sys/arm/cavium/cns11xx/econa.c
+++ b/sys/arm/cavium/cns11xx/econa.c
@@ -526,9 +526,9 @@ econa_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
if (device_get_flags(dev))
retval += printf(" flags %#x", device_get_flags(dev));
diff --git a/sys/arm/conf/A10 b/sys/arm/conf/A10
index 678b564..31a5e24 100644
--- a/sys/arm/conf/A10
+++ b/sys/arm/conf/A10
@@ -61,7 +61,7 @@ device ahci # AHCI-compatible SATA controllers
# Console and misc
device uart
-device uart_ns8250
+device uart_snps
device pty
device snp
device md
diff --git a/sys/arm/conf/A20 b/sys/arm/conf/A20
index 9c7983c..ad3b29a 100644
--- a/sys/arm/conf/A20
+++ b/sys/arm/conf/A20
@@ -71,7 +71,7 @@ device ahci # AHCI-compatible SATA controllers
# Console and misc
device uart
-device uart_ns8250
+device uart_snps
device pty
device snp
device md
diff --git a/sys/arm/conf/ARMADA38X b/sys/arm/conf/ARMADA38X
index 7cc7702..13c3aa2 100644
--- a/sys/arm/conf/ARMADA38X
+++ b/sys/arm/conf/ARMADA38X
@@ -23,7 +23,6 @@ options SCHED_ULE # ULE scheduler
#options SCHED_4BSD # 4BSD scheduler
options SMP
-options ARM_INTRNG
# Debugging
#options DEBUG
@@ -49,7 +48,7 @@ device md
# Serial ports
device uart
-device uart_ns8250
+device uart_snps
# Network
device ether
diff --git a/sys/arm/conf/ATMEL b/sys/arm/conf/ATMEL
index f86f8e8..63cd785 100644
--- a/sys/arm/conf/ATMEL
+++ b/sys/arm/conf/ATMEL
@@ -57,11 +57,6 @@ options GEOM_PART_BSD # BSD partition scheme
options GEOM_PART_MBR # MBR partition scheme
options GEOM_PART_GPT # GUID Partition Tables.
options GEOM_LABEL # Provides labelization
-options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-options COMPAT_FREEBSD7 # Compatible with FreeBSD7
-options COMPAT_FREEBSD9 # Compatible with FreeBSD9
-options COMPAT_FREEBSD10 # Compatible with FreeBSD10
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
options KTRACE # ktrace(1) support
options STACK # stack(9) support
diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE
index 3950e17..1885c0c 100644
--- a/sys/arm/conf/BEAGLEBONE
+++ b/sys/arm/conf/BEAGLEBONE
@@ -28,6 +28,8 @@ include "../ti/am335x/std.am335x"
makeoptions MODULES_EXTRA="dtb/am335x am335x_dmtpps"
+options ARM_INTRNG
+
options HZ=100
options SCHED_4BSD # 4BSD scheduler
options PLATFORM
@@ -87,6 +89,10 @@ device gpio
device gpioled
device gpiobacklight
+# SPI
+device ti_spi
+device spibus
+
# ADC support
device ti_adc
diff --git a/sys/arm/conf/CNS11XXNAS b/sys/arm/conf/CNS11XXNAS
index 2bb5920..6fc8876 100644
--- a/sys/arm/conf/CNS11XXNAS
+++ b/sys/arm/conf/CNS11XXNAS
@@ -46,11 +46,6 @@ options DDB # Enable the kernel debugger
#options DIAGNOSTIC
-#options COMPAT_FREEBSD5
-#options COMPAT_FREEBSD6
-#options COMPAT_FREEBSD7n
-
-
options SCHED_ULE # ULE scheduler
#options SCHED_4BSD # 4BSD scheduler
options GEOM_PART_BSD # BSD partition scheme
diff --git a/sys/arm/conf/EFIKA_MX b/sys/arm/conf/EFIKA_MX
index 7f978b2..8b4b4aa 100644
--- a/sys/arm/conf/EFIKA_MX
+++ b/sys/arm/conf/EFIKA_MX
@@ -30,9 +30,6 @@ options SOC_IMX51
options SCHED_4BSD # 4BSD scheduler
#options MD_ROOT # MD is a potential root device
#options NFSD # Network Filesystem Server
-#options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-#options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-#options COMPAT_FREEBSD7 # Compatible with FreeBSD7
options PLATFORM
options INCLUDE_CONFIG_FILE # Include this file in kernel
diff --git a/sys/arm/conf/ETHERNUT5 b/sys/arm/conf/ETHERNUT5
index 4604ff2..e54513b 100644
--- a/sys/arm/conf/ETHERNUT5
+++ b/sys/arm/conf/ETHERNUT5
@@ -53,9 +53,6 @@ options GEOM_PART_BSD # BSD partition scheme
options GEOM_PART_MBR # MBR partition scheme
#options GEOM_PART_GPT # GUID Partition Tables.
#options GEOM_LABEL # Provides labelization
-#options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-#options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-#options COMPAT_FREEBSD7 # Compatible with FreeBSD7
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
options KTRACE # ktrace(1) support
#options STACK # stack(9) support
diff --git a/sys/arm/conf/IMX53 b/sys/arm/conf/IMX53
index 9724375..e320562 100644
--- a/sys/arm/conf/IMX53
+++ b/sys/arm/conf/IMX53
@@ -27,9 +27,6 @@ options SOC_IMX53
options SCHED_4BSD # 4BSD scheduler
#options NFSD # Network Filesystem Server
-#options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-#options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-#options COMPAT_FREEBSD7 # Compatible with FreeBSD7
options PLATFORM
options INCLUDE_CONFIG_FILE # Include this file in kernel
diff --git a/sys/arm/conf/JETSON-TK1 b/sys/arm/conf/JETSON-TK1
new file mode 100644
index 0000000..242e835
--- /dev/null
+++ b/sys/arm/conf/JETSON-TK1
@@ -0,0 +1,37 @@
+# Kernel configuration for Jetson TK1 board
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+#NO_UNIVERSE
+
+include "TEGRA124"
+ident JETSON-TK1
+
+# Flattened Device Tree
+options FDT_DTB_STATIC
+makeoptions FDT_DTS_FILE=tegra124-jetson-tk1-fbsd.dts
+
+makeoptions MODULES_OVERRIDE=""
+#options BOOTVERBOSE
+#options BOOTHOWTO=RB_SINGLE
+
+#options ROOTDEVNAME=\"ufs:mmcsd0s2a\"
+options ROOTDEVNAME=\"ufs:ada0s1a\"
+
+# CTF doesn't works yet
+makeoptions WITHOUT_CTF=1
diff --git a/sys/arm/conf/NOTES b/sys/arm/conf/NOTES
index d32e6d6..3cd43af 100644
--- a/sys/arm/conf/NOTES
+++ b/sys/arm/conf/NOTES
@@ -58,6 +58,10 @@ nooptions SMP
nooptions MAXCPU
nooptions COMPAT_FREEBSD4
+nooptions COMPAT_FREEBSD5
+nooptions COMPAT_FREEBSD6
+nooptions COMPAT_FREEBSD7
+nooptions COMPAT_FREEBSD9
nooption PPC_PROBE_CHIPSET
nodevice fdc
diff --git a/sys/arm/conf/RK3188 b/sys/arm/conf/RK3188
index 49c8eae..ec6ddb8 100644
--- a/sys/arm/conf/RK3188
+++ b/sys/arm/conf/RK3188
@@ -59,7 +59,7 @@ device dwmmc
# Console and misc
device uart
-device uart_ns8250
+device uart_snps
device pty
device snp
device md
@@ -101,8 +101,6 @@ device wlan # 802.11 support
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support
device wlan_tkip # 802.11 TKIP support
-device urtwn
-device urtwnfw
device firmware # Used by the above
# USB Ethernet support, requires miibus
diff --git a/sys/arm/conf/SAM9260EK b/sys/arm/conf/SAM9260EK
index 1edee77..7248046 100644
--- a/sys/arm/conf/SAM9260EK
+++ b/sys/arm/conf/SAM9260EK
@@ -64,9 +64,6 @@ options GEOM_PART_BSD # BSD partition scheme
options GEOM_PART_MBR # MBR partition scheme
#options GEOM_PART_GPT # GUID Partition Tables.
#options GEOM_LABEL # Provides labelization
-#options COMPAT_FREEBSD5 # Compatible with FreeBSD5
-#options COMPAT_FREEBSD6 # Compatible with FreeBSD6
-#options COMPAT_FREEBSD7 # Compatible with FreeBSD7
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
options KTRACE # ktrace(1) support
#options STACK # stack(9) support
diff --git a/sys/arm/conf/TEGRA124 b/sys/arm/conf/TEGRA124
new file mode 100644
index 0000000..1b3ec3f
--- /dev/null
+++ b/sys/arm/conf/TEGRA124
@@ -0,0 +1,157 @@
+#
+# Kernel configuration for NVIDIA Tegra124 based boards.
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+include "std.armv6"
+include "../nvidia/tegra124/std.tegra124"
+
+ident TEGRA124
+
+options HZ=100 # Scheduling quantum is 10 milliseconds.
+options SCHED_ULE # ULE scheduler
+options PLATFORM # Platform based SoC
+options PLATFORM_SMP
+options SMP # Enable multiple cores
+options LINUX_BOOT_ABI
+
+# Debugging for use in -current
+makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols
+options BREAK_TO_DEBUGGER
+options ALT_BREAK_TO_DEBUGGER
+#options VERBOSE_SYSINIT # Enable verbose sysinit messages
+options KDB # Enable kernel debugger support
+# For minimum debugger support (stable branch) use:
+#options KDB_TRACE # Print a stack trace for a panic
+# For full debugger support use this instead:
+options DDB # Enable the kernel debugger
+options INVARIANTS # Enable calls of extra sanity checking
+options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS
+options WITNESS # Enable checks to detect deadlocks and cycles
+options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed
+
+# Interrupt controller
+device gic
+
+# ARM Generic Timer
+device generic_timer
+
+# EXT_RESOURCES pseudo devices
+options EXT_RESOURCES
+device clk
+device phy
+device hwreset
+device regulator
+
+# Pseudo devices.
+device loop # Network loopback
+device random # Entropy device
+device vlan # 802.1Q VLAN support
+#device tun # Packet tunnel.
+device md # Memory "disks"
+#device gif # IPv6 and IPv4 tunneling
+#device firmware # firmware assist module
+device ether # Ethernet support
+device miibus # Required for ethernet
+device bpf # Berkeley packet filter (required for DHCP)
+
+
+# General-purpose input/output
+device gpio
+#device gpioled
+
+# I2C support
+device iic
+device iicbus
+device icee
+
+# Serial (COM) ports
+device uart # Multi-uart driver
+device uart_ns8250
+
+# MMC/SD/SDIO Card slot support
+device sdhci # SD controller
+device mmc # SD/MMC protocol
+device mmcsd # SDCard disk device
+
+# ATA controllers
+device ahci # AHCI-compatible SATA controllers
+
+# SCSI peripherals
+device scbus # SCSI bus (required for ATA/SCSI)
+device da # Direct Access (disks)
+device cd # CD
+device pass # Passthrough device (direct ATA/SCSI access)
+
+# USB support
+options USB_HOST_ALIGN=64 # Align usb buffers to cache line size.
+options USB_DEBUG # enable debug msgs
+device ehci # EHCI USB interface
+device usb # USB Bus (required)
+device umass # Disks/Mass storage - Requires scbus and da
+device uhid # "Human Interface Devices"
+#device u3g # USB modems
+device ukbd # Allow keyboard like HIDs to control console
+device ums # USB mouse
+
+# USB Ethernet, requires miibus
+#device aue # ADMtek USB Ethernet
+#device axe # ASIX Electronics USB Ethernet
+#device cdce # Generic USB over Ethernet
+#device cue # CATC USB Ethernet
+#device kue # Kawasaki LSI USB Ethernet
+#device rue # RealTek RTL8150 USB Ethernet
+#device udav # Davicom DM9601E USB
+
+# USB Wireless
+#device rum # Ralink Technology RT2501USB wireless NICs
+
+# Wireless NIC cards
+#device wlan # 802.11 support
+#device wlan_wep # 802.11 WEP support
+#device wlan_ccmp # 802.11 CCMP support
+#device wlan_tkip # 802.11 TKIP support
+#device wlan_amrr # AMRR transmit rate control algorithm
+
+# PCI
+options NEW_PCIB
+device pci
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device re # RealTek 8139C+/8169/8169S/8110S
+
+# DRM2
+#device fbd
+#device vt
+#device splash
+#device kbdmux
+#device drm2
+
+# Sound
+#device sound
+#device snd_hda
+
+# Flattened Device Tree
+options FDT # Configure using FDT/DTB data
+device fdt_pinctrl
+
+# SoC-specific devices
+
+#device hwpmc
+#options HWPMC_HOOKS
diff --git a/sys/arm/conf/std.arm b/sys/arm/conf/std.arm
index 88675f0..b9ac640 100644
--- a/sys/arm/conf/std.arm
+++ b/sys/arm/conf/std.arm
@@ -2,4 +2,5 @@
#
# $FreeBSD$
+options COMPAT_FREEBSD10 # Compatible with FreeBSD10
diff --git a/sys/arm/conf/std.armv6 b/sys/arm/conf/std.armv6
index 142c7d3..4dc4906 100644
--- a/sys/arm/conf/std.armv6
+++ b/sys/arm/conf/std.armv6
@@ -39,6 +39,8 @@ options KBD_INSTALL_CDEV # install a CDEV entry in /dev
options FREEBSD_BOOT_LOADER # Process metadata passed from loader(8)
options VFP # Enable floating point hardware support
+options COMPAT_FREEBSD10 # Compatible with FreeBSD10
+
# DTrace support
options KDTRACE_HOOKS # Kernel DTrace hooks
options DDB_CTF # all architectures - kernel ELF linker loads CTF data
diff --git a/sys/arm/freescale/imx/imx_gpio.c b/sys/arm/freescale/imx/imx_gpio.c
index 3c81e28..cdff020 100644
--- a/sys/arm/freescale/imx/imx_gpio.c
+++ b/sys/arm/freescale/imx/imx_gpio.c
@@ -91,6 +91,15 @@ __FBSDID("$FreeBSD$");
#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
#define NGPIO 32
+#ifdef ARM_INTRNG
+struct gpio_irqsrc {
+ struct intr_irqsrc gi_isrc;
+ u_int gi_irq;
+ enum intr_polarity gi_pol;
+ enum intr_trigger gi_trig;
+};
+#endif
+
struct imx51_gpio_softc {
device_t dev;
device_t sc_busdev;
@@ -101,7 +110,9 @@ struct imx51_gpio_softc {
bus_space_handle_t sc_ioh;
int gpio_npins;
struct gpio_pin gpio_pins[NGPIO];
- struct intr_irqsrc *gpio_pic_irqsrc[NGPIO];
+#ifdef ARM_INTRNG
+ struct gpio_irqsrc gpio_pic_irqsrc[NGPIO];
+#endif
};
static struct ofw_compat_data compat_data[] = {
@@ -145,8 +156,30 @@ static int imx51_gpio_pin_get(device_t, uint32_t, unsigned int *);
static int imx51_gpio_pin_toggle(device_t, uint32_t pin);
#ifdef ARM_INTRNG
+static int
+gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct imx51_gpio_softc *sc;
+ struct gpio_irqsrc *gi;
+
+ sc = device_get_softc(dev);
+ if (isrc->isrc_handlers == 0) {
+ gi = (struct gpio_irqsrc *)isrc;
+ gi->gi_pol = INTR_POLARITY_CONFORM;
+ gi->gi_trig = INTR_TRIGGER_CONFORM;
+
+ // XXX Not sure this is necessary
+ mtx_lock_spin(&sc->sc_mtx);
+ CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << gi->gi_irq));
+ WRITE4(sc, IMX_GPIO_ISR_REG, (1U << gi->gi_irq));
+ mtx_unlock_spin(&sc->sc_mtx);
+ }
+ return (0);
+}
+
/*
- * this is teardown_intr
+ * this is mask_intr
*/
static void
gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
@@ -155,55 +188,143 @@ gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
u_int irq;
sc = device_get_softc(dev);
- irq = isrc->isrc_data;
+ irq = ((struct gpio_irqsrc *)isrc)->gi_irq;
- // XXX Not sure this is necessary
mtx_lock_spin(&sc->sc_mtx);
CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << irq));
- WRITE4(sc, IMX_GPIO_ISR_REG, (1U << irq));
mtx_unlock_spin(&sc->sc_mtx);
}
-/*
- * this is mask_intr
- */
-static void
-gpio_pic_disable_source(device_t dev, struct intr_irqsrc *isrc)
+static int
+gpio_pic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp,
+ enum intr_polarity *polp, enum intr_trigger *trigp)
{
struct imx51_gpio_softc *sc;
+ u_int irq, tripol;
+ enum intr_polarity pol;
+ enum intr_trigger trig;
sc = device_get_softc(dev);
- mtx_lock_spin(&sc->sc_mtx);
- CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << isrc->isrc_data));
- mtx_unlock_spin(&sc->sc_mtx);
+ /*
+ * From devicetree/bindings/gpio/fsl-imx-gpio.txt:
+ * #interrupt-cells: 2. The first cell is the GPIO number. The second
+ * cell bits[3:0] is used to specify trigger type and level flags:
+ * 1 = low-to-high edge triggered.
+ * 2 = high-to-low edge triggered.
+ * 4 = active high level-sensitive.
+ * 8 = active low level-sensitive.
+ * We can do any single one of these modes, but nothing in combo.
+ */
+
+ if (ncells != 2) {
+ device_printf(sc->dev, "Invalid #interrupt-cells");
+ return (EINVAL);
+ }
+
+ irq = cells[0];
+ tripol = cells[1];
+ if (irq >= sc->gpio_npins) {
+ device_printf(sc->dev, "Invalid interrupt number %d", irq);
+ return (EINVAL);
+ }
+ switch (tripol) {
+ case 1:
+ trig = INTR_TRIGGER_EDGE;
+ pol = INTR_POLARITY_HIGH;
+ break;
+ case 2:
+ trig = INTR_TRIGGER_EDGE;
+ pol = INTR_POLARITY_LOW;
+ break;
+ case 4:
+ trig = INTR_TRIGGER_LEVEL;
+ pol = INTR_POLARITY_HIGH;
+ break;
+ case 8:
+ trig = INTR_TRIGGER_LEVEL;
+ pol = INTR_POLARITY_LOW;
+ break;
+ default:
+ device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n",
+ tripol);
+ return (ENOTSUP);
+ }
+ *irqp = irq;
+ if (polp != NULL)
+ *polp = pol;
+ if (trigp != NULL)
+ *trigp = trig;
+ return (0);
}
-/*
- * this is setup_intr
- */
-static void
-gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+static int
+gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ int error;
+ u_int irq;
+ struct imx51_gpio_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+
+ error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq,
+ NULL, NULL);
+ if (error == 0) {
+ sc = device_get_softc(dev);
+ *isrcp = &sc->gpio_pic_irqsrc[irq].gi_isrc;
+ }
+ return (error);
+}
+
+static int
+gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
struct imx51_gpio_softc *sc;
- int icfg;
+ struct gpio_irqsrc *gi;
+ int error, icfg;
u_int irq, reg, shift, wrk;
+ enum intr_trigger trig;
+ enum intr_polarity pol;
sc = device_get_softc(dev);
+ gi = (struct gpio_irqsrc *)isrc;
+
+ /* Get config for interrupt. */
+ if (data == NULL || data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+ error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq,
+ &pol, &trig);
+ if (error != 0)
+ return (error);
+ if (gi->gi_irq != irq)
+ return (EINVAL);
- if (isrc->isrc_trig == INTR_TRIGGER_LEVEL) {
- if (isrc->isrc_pol == INTR_POLARITY_LOW)
+ /* Compare config if this is not first setup. */
+ if (isrc->isrc_handlers != 0) {
+ if (pol != gi->gi_pol || trig != gi->gi_trig)
+ return (EINVAL);
+ else
+ return (0);
+ }
+
+ gi->gi_pol = pol;
+ gi->gi_trig = trig;
+
+ if (trig == INTR_TRIGGER_LEVEL) {
+ if (pol == INTR_POLARITY_LOW)
icfg = GPIO_ICR_COND_LOW;
else
icfg = GPIO_ICR_COND_HIGH;
} else {
- if (isrc->isrc_pol == INTR_POLARITY_HIGH)
+ if (pol == INTR_POLARITY_HIGH)
icfg = GPIO_ICR_COND_FALL;
else
icfg = GPIO_ICR_COND_RISE;
}
- irq = isrc->isrc_data;
if (irq < 16) {
reg = IMX_GPIO_ICR1_REG;
shift = 2 * irq;
@@ -220,20 +341,23 @@ gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
wrk |= icfg << shift;
WRITE4(sc, reg, wrk);
mtx_unlock_spin(&sc->sc_mtx);
+ return (0);
}
/*
* this is unmask_intr
*/
static void
-gpio_pic_enable_source(device_t dev, struct intr_irqsrc *isrc)
+gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct imx51_gpio_softc *sc;
+ u_int irq;
sc = device_get_softc(dev);
+ irq = ((struct gpio_irqsrc *)isrc)->gi_irq;
mtx_lock_spin(&sc->sc_mtx);
- SET4(sc, IMX_GPIO_IMR_REG, (1U << isrc->isrc_data));
+ SET4(sc, IMX_GPIO_IMR_REG, (1U << irq));
mtx_unlock_spin(&sc->sc_mtx);
}
@@ -241,12 +365,14 @@ static void
gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
{
struct imx51_gpio_softc *sc;
+ u_int irq;
sc = device_get_softc(dev);
+ irq = ((struct gpio_irqsrc *)isrc)->gi_irq;
arm_irq_memory_barrier(0);
/* EOI. W1C reg so no r-m-w, no locking needed. */
- WRITE4(sc, IMX_GPIO_ISR_REG, (1U << isrc->isrc_data));
+ WRITE4(sc, IMX_GPIO_ISR_REG, (1U << irq));
}
static void
@@ -254,119 +380,21 @@ gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
{
arm_irq_memory_barrier(0);
- gpio_pic_enable_source(dev, isrc);
+ gpio_pic_enable_intr(dev, isrc);
}
static void
gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
{
- gpio_pic_disable_source(dev, isrc);
-}
-
-/*
- * intrng calls this to make a new isrc known to us.
- */
-static int
-gpio_pic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu)
-{
- struct imx51_gpio_softc *sc;
- u_int irq, tripol;
-
- sc = device_get_softc(dev);
-
- /*
- * From devicetree/bindings/gpio/fsl-imx-gpio.txt:
- * #interrupt-cells: 2. The first cell is the GPIO number. The second
- * cell bits[3:0] is used to specify trigger type and level flags:
- * 1 = low-to-high edge triggered.
- * 2 = high-to-low edge triggered.
- * 4 = active high level-sensitive.
- * 8 = active low level-sensitive.
- * We can do any single one of these modes, but nothing in combo.
- */
-
- if (isrc->isrc_ncells != 2) {
- device_printf(sc->dev, "Invalid #interrupt-cells");
- return (EINVAL);
- }
-
- irq = isrc->isrc_cells[0];
- tripol = isrc->isrc_cells[1];
- if (irq >= sc->gpio_npins) {
- device_printf(sc->dev, "Invalid interrupt number %d", irq);
- return (EINVAL);
- }
- switch (tripol)
- {
- case 1:
- isrc->isrc_trig = INTR_TRIGGER_EDGE;
- isrc->isrc_pol = INTR_POLARITY_HIGH;
- break;
- case 2:
- isrc->isrc_trig = INTR_TRIGGER_EDGE;
- isrc->isrc_pol = INTR_POLARITY_LOW;
- break;
- case 4:
- isrc->isrc_trig = INTR_TRIGGER_LEVEL;
- isrc->isrc_pol = INTR_POLARITY_HIGH;
- break;
- case 8:
- isrc->isrc_trig = INTR_TRIGGER_LEVEL;
- isrc->isrc_pol = INTR_POLARITY_LOW;
- break;
- default:
- device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n",
- tripol);
- return (ENOTSUP);
- }
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN;
- isrc->isrc_nspc_num = irq;
-
- /*
- * 1. The link between ISRC and controller must be set atomically.
- * 2. Just do things only once in rare case when consumers
- * of shared interrupt came here at the same moment.
- */
- mtx_lock_spin(&sc->sc_mtx);
- if (sc->gpio_pic_irqsrc[irq] != NULL) {
- mtx_unlock_spin(&sc->sc_mtx);
- return (sc->gpio_pic_irqsrc[irq] == isrc ? 0 : EEXIST);
- }
- sc->gpio_pic_irqsrc[irq] = isrc;
- isrc->isrc_data = irq;
- mtx_unlock_spin(&sc->sc_mtx);
-
- intr_irq_set_name(isrc, "%s,%u", device_get_nameunit(sc->dev), irq);
- return (0);
-}
-
-static int
-gpio_pic_unregister(device_t dev, struct intr_irqsrc *isrc)
-{
- struct imx51_gpio_softc *sc;
- u_int irq;
-
- sc = device_get_softc(dev);
-
- mtx_lock_spin(&sc->sc_mtx);
- irq = isrc->isrc_data;
- if (sc->gpio_pic_irqsrc[irq] != isrc) {
- mtx_unlock_spin(&sc->sc_mtx);
- return (sc->gpio_pic_irqsrc[irq] == NULL ? 0 : EINVAL);
- }
- sc->gpio_pic_irqsrc[irq] = NULL;
- isrc->isrc_data = 0;
- mtx_unlock_spin(&sc->sc_mtx);
-
- intr_irq_set_name(isrc, "");
- return (0);
+ gpio_pic_disable_intr(dev, isrc);
}
static int
gpio_pic_filter(void *arg)
{
struct imx51_gpio_softc *sc;
+ struct intr_irqsrc *isrc;
uint32_t i, interrupts;
sc = arg;
@@ -377,14 +405,43 @@ gpio_pic_filter(void *arg)
for (i = 0; interrupts != 0; i++, interrupts >>= 1) {
if ((interrupts & 0x1) == 0)
continue;
- if (sc->gpio_pic_irqsrc[i])
- intr_irq_dispatch(sc->gpio_pic_irqsrc[i], curthread->td_intr_frame);
- else
- device_printf(sc->dev, "spurious interrupt %d\n", i);
+ isrc = &sc->gpio_pic_irqsrc[i].gi_isrc;
+ if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) {
+ gpio_pic_disable_intr(sc->dev, isrc);
+ gpio_pic_post_filter(sc->dev, isrc);
+ device_printf(sc->dev, "Stray irq %u disabled\n", i);
+ }
}
return (FILTER_HANDLED);
}
+
+/*
+ * register our isrcs into intrng to make it known about them.
+ */
+static int
+gpio_pic_register_isrcs(struct imx51_gpio_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ const char *name;
+
+ name = device_get_nameunit(sc->dev);
+ for (irq = 0; irq < NGPIO; irq++) {
+ sc->gpio_pic_irqsrc[irq].gi_irq = irq;
+ sc->gpio_pic_irqsrc[irq].gi_pol = INTR_POLARITY_CONFORM;
+ sc->gpio_pic_irqsrc[irq].gi_trig = INTR_TRIGGER_CONFORM;
+
+ error = intr_isrc_register(&sc->gpio_pic_irqsrc[irq].gi_isrc,
+ sc->dev, 0, "%s,%u", name, irq);
+ if (error != 0) {
+ /* XXX call intr_isrc_deregister() */
+ device_printf(sc->dev, "%s failed", __func__);
+ return (error);
+ }
+ }
+ return (0);
+}
#endif
/*
@@ -656,6 +713,7 @@ imx51_gpio_attach(device_t dev)
}
#ifdef ARM_INTRNG
+ gpio_pic_register_isrcs(sc);
intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev)));
#endif
sc->sc_busdev = gpiobus_attach_bus(dev);
@@ -695,14 +753,13 @@ static device_method_t imx51_gpio_methods[] = {
#ifdef ARM_INTRNG
/* Interrupt controller interface */
DEVMETHOD(pic_disable_intr, gpio_pic_disable_intr),
- DEVMETHOD(pic_disable_source, gpio_pic_disable_source),
DEVMETHOD(pic_enable_intr, gpio_pic_enable_intr),
- DEVMETHOD(pic_enable_source, gpio_pic_enable_source),
+ DEVMETHOD(pic_map_intr, gpio_pic_map_intr),
+ DEVMETHOD(pic_setup_intr, gpio_pic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, gpio_pic_teardown_intr),
DEVMETHOD(pic_post_filter, gpio_pic_post_filter),
DEVMETHOD(pic_post_ithread, gpio_pic_post_ithread),
DEVMETHOD(pic_pre_ithread, gpio_pic_pre_ithread),
- DEVMETHOD(pic_register, gpio_pic_register),
- DEVMETHOD(pic_unregister, gpio_pic_unregister),
#endif
/* GPIO protocol */
diff --git a/sys/arm/freescale/imx/imx_sdhci.c b/sys/arm/freescale/imx/imx_sdhci.c
index fa9d8ed..2dc41db 100644
--- a/sys/arm/freescale/imx/imx_sdhci.c
+++ b/sys/arm/freescale/imx/imx_sdhci.c
@@ -836,3 +836,4 @@ static driver_t imx_sdhci_driver = {
DRIVER_MODULE(sdhci_imx, simplebus, imx_sdhci_driver, imx_sdhci_devclass, 0, 0);
MODULE_DEPEND(sdhci_imx, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_imx, mmc, 1, 1, 1);
diff --git a/sys/arm/include/atags.h b/sys/arm/include/atags.h
index 3665890..6d400af 100644
--- a/sys/arm/include/atags.h
+++ b/sys/arm/include/atags.h
@@ -123,7 +123,7 @@ struct arm_lbabi_tag
};
#define ATAG_TAG(a) (a)->tag_hdr.tag
-#define ATAG_SIZE(a) (a)->tag_hdr.size
+#define ATAG_SIZE(a) ((a)->tag_hdr.size * sizeof(uint32_t))
#define ATAG_NEXT(a) (struct arm_lbabi_tag *)((char *)(a) + ATAG_SIZE(a))
#endif /* __MACHINE_ATAGS_H__ */
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index 74d7e4d..e81bc7d 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -52,14 +52,17 @@
#include <sys/intr.h>
#ifdef SMP
-void intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf);
+typedef void intr_ipi_send_t(void *, cpuset_t, u_int);
+typedef void intr_ipi_handler_t(void *);
-#define AISHF_NOALLOC 0x0001
+void intr_ipi_dispatch(u_int, struct trapframe *);
+void intr_ipi_send(cpuset_t, u_int);
-int intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
- void *arg, u_int flags);
-#endif
+void intr_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *,
+ intr_ipi_send_t *, void *);
+int intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *);
+#endif
#else /* ARM_INTRNG */
/* XXX move to std.* files? */
diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h
index 36c2f44..b156efe 100644
--- a/sys/arm/include/machdep.h
+++ b/sys/arm/include/machdep.h
@@ -37,7 +37,8 @@ struct arm_boot_params;
vm_offset_t default_parse_boot_param(struct arm_boot_params *abp);
vm_offset_t freebsd_parse_boot_param(struct arm_boot_params *abp);
vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp);
-vm_offset_t fake_preload_metadata(struct arm_boot_params *abp);
+vm_offset_t fake_preload_metadata(struct arm_boot_params *abp,
+ void *dtb_ptr, size_t dtb_size);
vm_offset_t parse_boot_param(struct arm_boot_params *abp);
void arm_generic_initclocks(void);
diff --git a/sys/arm/include/smp.h b/sys/arm/include/smp.h
index e4d6385..e685cc3 100644
--- a/sys/arm/include/smp.h
+++ b/sys/arm/include/smp.h
@@ -37,8 +37,8 @@ void ipi_cpu(int cpu, u_int ipi);
void ipi_selected(cpuset_t cpus, u_int ipi);
/* PIC interface */
-void pic_ipi_send(cpuset_t cpus, u_int ipi);
#ifndef ARM_INTRNG
+void pic_ipi_send(cpuset_t cpus, u_int ipi);
void pic_ipi_clear(int ipi);
int pic_ipi_read(int arg);
#endif
diff --git a/sys/arm/lpc/lpc_mmc.c b/sys/arm/lpc/lpc_mmc.c
index ad3b6aa..6c33215 100644
--- a/sys/arm/lpc/lpc_mmc.c
+++ b/sys/arm/lpc/lpc_mmc.c
@@ -776,3 +776,4 @@ static driver_t lpc_mmc_driver = {
DRIVER_MODULE(lpcmmc, simplebus, lpc_mmc_driver, lpc_mmc_devclass, 0, 0);
DRIVER_MODULE(mmc, lpcmmc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(lpcmmc, mmc, 1, 1, 1);
diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv
index 635173d..8c303c6 100644
--- a/sys/arm/mv/files.mv
+++ b/sys/arm/mv/files.mv
@@ -26,6 +26,7 @@ dev/mge/if_mge.c optional mge
dev/nand/nfc_mv.c optional nand
dev/mvs/mvs_soc.c optional mvs
dev/uart/uart_dev_ns8250.c optional uart
+dev/uart/uart_dev_snps.c optional uart
dev/usb/controller/ehci_mv.c optional ehci
dev/usb/controller/xhci_mv.c optional xhci
diff --git a/sys/arm/mv/mpic.c b/sys/arm/mv/mpic.c
index e81820c..4f246a4 100644
--- a/sys/arm/mv/mpic.c
+++ b/sys/arm/mv/mpic.c
@@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$");
#define MPIC_INT_ERR 4
#define MPIC_INT_MSI 96
-#define IRQ_MASK 0x3ff
+#define MPIC_IRQ_MASK 0x3ff
#define MPIC_CTRL 0x0
#define MPIC_SOFT_INT 0x4
@@ -98,6 +98,13 @@ __FBSDID("$FreeBSD$");
#define MPIC_PPI 32
+#ifdef ARM_INTRNG
+struct mv_mpic_irqsrc {
+ struct intr_irqsrc mmi_isrc;
+ u_int mmi_irq;
+};
+#endif
+
struct mv_mpic_softc {
device_t sc_dev;
struct resource * mpic_res[4];
@@ -108,8 +115,9 @@ struct mv_mpic_softc {
bus_space_tag_t drbl_bst;
bus_space_handle_t drbl_bsh;
struct mtx mtx;
-
- struct intr_irqsrc ** mpic_isrcs;
+#ifdef ARM_INTRNG
+ struct mv_mpic_irqsrc * mpic_isrcs;
+#endif
int nirqs;
void * intr_hand;
};
@@ -177,6 +185,40 @@ mv_mpic_probe(device_t dev)
return (0);
}
+#ifdef ARM_INTRNG
+static int
+mv_mpic_register_isrcs(struct mv_mpic_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ struct intr_irqsrc *isrc;
+ const char *name;
+
+ sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ name = device_get_nameunit(sc->sc_dev);
+ for (irq = 0; irq < sc->nirqs; irq++) {
+ sc->mpic_isrcs[irq].mmi_irq = irq;
+
+ isrc = &sc->mpic_isrcs[irq].mmi_isrc;
+ if (irq < MPIC_PPI) {
+ error = intr_isrc_register(isrc, sc->sc_dev,
+ INTR_ISRCF_PPI, "%s", name);
+ } else {
+ error = intr_isrc_register(isrc, sc->sc_dev, 0, "%s",
+ name);
+ }
+ if (error != 0) {
+ /* XXX call intr_isrc_deregister() */
+ device_printf(sc->sc_dev, "%s failed", __func__);
+ return (error);
+ }
+ }
+ return (0);
+}
+#endif
+
static int
mv_mpic_attach(device_t dev)
{
@@ -227,9 +269,11 @@ mv_mpic_attach(device_t dev)
sc->nirqs = MPIC_CTRL_NIRQS(val);
#ifdef ARM_INTRNG
- sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF,
- M_WAITOK | M_ZERO);
-
+ if (mv_mpic_register_isrcs(sc) != 0) {
+ device_printf(dev, "could not register PIC ISRCs\n");
+ bus_release_resources(dev, mv_mpic_spec, sc->mpic_res);
+ return (ENXIO);
+ }
if (intr_pic_register(dev, OF_xref_from_device(dev)) != 0) {
device_printf(dev, "could not register PIC\n");
bus_release_resources(dev, mv_mpic_spec, sc->mpic_res);
@@ -247,14 +291,11 @@ static int
mpic_intr(void *arg)
{
struct mv_mpic_softc *sc;
- struct trapframe *tf;
- struct intr_irqsrc *isrc;
uint32_t cause, irqsrc;
unsigned int irq;
u_int cpuid;
sc = arg;
- tf = curthread->td_intr_frame;
cpuid = PCPU_GET(cpuid);
irq = 0;
@@ -264,117 +305,64 @@ mpic_intr(void *arg)
irqsrc = MPIC_READ(sc, MPIC_INT_CTL(irq));
if ((irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid)) == 0)
continue;
- isrc = sc->mpic_isrcs[irq];
- if (isrc == NULL) {
- device_printf(sc->sc_dev, "Stray interrupt %u detected\n", irq);
+ if (intr_isrc_dispatch(&sc->mpic_isrcs[irq].mmi_isrc,
+ curthread->td_intr_frame) != 0) {
mpic_mask_irq(irq);
- continue;
+ device_printf(sc->sc_dev, "Stray irq %u "
+ "disabled\n", irq);
}
- intr_irq_dispatch(isrc, tf);
}
}
return (FILTER_HANDLED);
}
-static int
-mpic_attach_isrc(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int irq)
+static void
+mpic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
{
- const char *name;
-
- mtx_lock_spin(&sc->mtx);
- if (sc->mpic_isrcs[irq] != NULL) {
- mtx_unlock_spin(&sc->mtx);
- return (sc->mpic_isrcs[irq] == isrc ? 0 : EEXIST);
- }
- sc->mpic_isrcs[irq] = isrc;
- isrc->isrc_data = irq;
- mtx_unlock_spin(&sc->mtx);
-
- name = device_get_nameunit(sc->sc_dev);
- intr_irq_set_name(isrc, "%s", name);
+ u_int irq;
- return (0);
+ irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq;
+ mpic_mask_irq(irq);
}
-#ifdef FDT
-static int
-mpic_map_fdt(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
+static void
+mpic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
{
u_int irq;
- int error;
-
- if (isrc->isrc_ncells != 1)
- return (EINVAL);
- irq = isrc->isrc_cells[0];
-
- error = mpic_attach_isrc(sc, isrc, irq);
- if (error != 0)
- return (error);
-
- isrc->isrc_nspc_num = irq;
- isrc->isrc_trig = INTR_TRIGGER_CONFORM;
- isrc->isrc_pol = INTR_POLARITY_CONFORM;
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN;
-
- *irqp = irq;
-
- return (0);
+ irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq;
+ mpic_unmask_irq(irq);
}
-#endif
static int
-mpic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu)
+mpic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
{
struct mv_mpic_softc *sc;
- int error;
- u_int irq = 0;
sc = device_get_softc(dev);
-#ifdef FDT
- if (isrc->isrc_type == INTR_ISRCT_FDT)
- error = mpic_map_fdt(sc, isrc, &irq);
- else
-#endif
- error = EINVAL;
-
- if (error == 0)
- *is_percpu = irq < MPIC_PPI;
-
- return (error);
-}
-
-static void
-mpic_disable_source(device_t dev, struct intr_irqsrc *isrc)
-{
- u_int irq;
+ if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells !=1 ||
+ data->fdt.cells[0] >= sc->nirqs)
+ return (EINVAL);
- irq = isrc->isrc_data;
- mpic_mask_irq(irq);
+ *isrcp = &sc->mpic_isrcs[data->fdt.cells[0]].mmi_isrc;
+ return (0);
}
static void
-mpic_enable_source(device_t dev, struct intr_irqsrc *isrc)
-{
- u_int irq;
-
- irq = isrc->isrc_data;
- mpic_unmask_irq(irq);
-}
-static void
mpic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
{
- mpic_disable_source(dev, isrc);
+ mpic_disable_intr(dev, isrc);
}
static void
mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
{
- mpic_enable_source(dev, isrc);
+ mpic_enable_intr(dev, isrc);
}
#endif
@@ -383,9 +371,9 @@ static device_method_t mv_mpic_methods[] = {
DEVMETHOD(device_attach, mv_mpic_attach),
#ifdef ARM_INTRNG
- DEVMETHOD(pic_register, mpic_register),
- DEVMETHOD(pic_disable_source, mpic_disable_source),
- DEVMETHOD(pic_enable_source, mpic_enable_source),
+ DEVMETHOD(pic_disable_intr, mpic_disable_intr),
+ DEVMETHOD(pic_enable_intr, mpic_enable_intr),
+ DEVMETHOD(pic_map_intr, mpic_map_intr),
DEVMETHOD(pic_post_ithread, mpic_post_ithread),
DEVMETHOD(pic_pre_ithread, mpic_pre_ithread),
#endif
@@ -409,10 +397,10 @@ arm_get_next_irq(int last)
{
u_int irq, next = -1;
- irq = mv_mpic_get_cause() & IRQ_MASK;
+ irq = mv_mpic_get_cause() & MPIC_IRQ_MASK;
CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq);
- if (irq != IRQ_MASK) {
+ if (irq != MPIC_IRQ_MASK) {
if (irq == MPIC_INT_ERR)
irq = mv_mpic_get_cause_err();
if (irq == MPIC_INT_MSI)
diff --git a/sys/arm/mv/mv_localbus.c b/sys/arm/mv/mv_localbus.c
index 936bc18..fabb694 100644
--- a/sys/arm/mv/mv_localbus.c
+++ b/sys/arm/mv/mv_localbus.c
@@ -323,8 +323,8 @@ localbus_print_child(device_t dev, device_t child)
rv = 0;
rv += bus_print_child_header(dev, child);
- rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
rv += bus_print_child_footer(dev, child);
return (rv);
diff --git a/sys/arm/nvidia/as3722.c b/sys/arm/nvidia/as3722.c
new file mode 100644
index 0000000..3a03322
--- /dev/null
+++ b/sys/arm/nvidia/as3722.c
@@ -0,0 +1,411 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AS3722 PMIC driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <gnu/dts/include/dt-bindings/mfd/as3722.h>
+
+#include "clock_if.h"
+#include "regdev_if.h"
+
+#include "as3722.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"ams,as3722", 1},
+ {NULL, 0},
+};
+
+#define LOCK(_sc) sx_xlock(&(_sc)->lock)
+#define UNLOCK(_sc) sx_xunlock(&(_sc)->lock)
+#define LOCK_INIT(_sc) sx_init(&(_sc)->lock, "as3722")
+#define LOCK_DESTROY(_sc) sx_destroy(&(_sc)->lock);
+#define ASSERT_LOCKED(_sc) sx_assert(&(_sc)->lock, SA_XLOCKED);
+#define ASSERT_UNLOCKED(_sc) sx_assert(&(_sc)->lock, SA_UNLOCKED);
+
+#define AS3722_DEVICE_ID 0x0C
+
+/*
+ * Raw register access function.
+ */
+int
+as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val)
+{
+ uint8_t addr;
+ int rv;
+ struct iic_msg msgs[2] = {
+ {0, IIC_M_WR, 1, &addr},
+ {0, IIC_M_RD, 1, val},
+ };
+
+ msgs[0].slave = sc->bus_addr;
+ msgs[1].slave = sc->bus_addr;
+ addr = reg;
+
+ rv = iicbus_transfer(sc->dev, msgs, 2);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Error when reading reg 0x%02X, rv: %d\n", reg, rv);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+int as3722_read_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
+ size_t size)
+{
+ uint8_t addr;
+ int rv;
+ struct iic_msg msgs[2] = {
+ {0, IIC_M_WR, 1, &addr},
+ {0, IIC_M_RD, size, buf},
+ };
+
+ msgs[0].slave = sc->bus_addr;
+ msgs[1].slave = sc->bus_addr;
+ addr = reg;
+
+ rv = iicbus_transfer(sc->dev, msgs, 2);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Error when reading reg 0x%02X, rv: %d\n", reg, rv);
+ return (EIO);
+ }
+
+ return (0);
+}
+
+int
+as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val)
+{
+ uint8_t data[2];
+ int rv;
+
+ struct iic_msg msgs[1] = {
+ {0, IIC_M_WR, 2, data},
+ };
+
+ msgs[0].slave = sc->bus_addr;
+ data[0] = reg;
+ data[1] = val;
+
+ rv = iicbus_transfer(sc->dev, msgs, 1);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
+ return (EIO);
+ }
+ return (0);
+}
+
+int as3722_write_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
+ size_t size)
+{
+ uint8_t data[1];
+ int rv;
+ struct iic_msg msgs[2] = {
+ {0, IIC_M_WR, 1, data},
+ {0, IIC_M_WR | IIC_M_NOSTART, size, buf},
+ };
+
+ msgs[0].slave = sc->bus_addr;
+ msgs[1].slave = sc->bus_addr;
+ data[0] = reg;
+
+ rv = iicbus_transfer(sc->dev, msgs, 2);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
+ return (EIO);
+ }
+ return (0);
+}
+
+int
+as3722_modify(struct as3722_softc *sc, uint8_t reg, uint8_t clear, uint8_t set)
+{
+ uint8_t val;
+ int rv;
+
+ rv = as3722_read(sc, reg, &val);
+ if (rv != 0)
+ return (rv);
+
+ val &= ~clear;
+ val |= set;
+
+ rv = as3722_write(sc, reg, val);
+ if (rv != 0)
+ return (rv);
+
+ return (0);
+}
+
+static int
+as3722_get_version(struct as3722_softc *sc)
+{
+ uint8_t reg;
+ int rv;
+
+ /* Verify AS3722 ID and version. */
+ rv = RD1(sc, AS3722_ASIC_ID1, &reg);
+ if (rv != 0)
+ return (ENXIO);
+
+ if (reg != AS3722_DEVICE_ID) {
+ device_printf(sc->dev, "Invalid chip ID is 0x%x\n", reg);
+ return (ENXIO);
+ }
+
+ rv = RD1(sc, AS3722_ASIC_ID2, &sc->chip_rev);
+ if (rv != 0)
+ return (ENXIO);
+
+ if (bootverbose)
+ device_printf(sc->dev, "AS3722 rev: 0x%x\n", sc->chip_rev);
+ return (0);
+}
+
+static int
+as3722_init(struct as3722_softc *sc)
+{
+ uint32_t reg;
+ int rv;
+
+ reg = 0;
+ if (sc->int_pullup)
+ reg |= AS3722_INT_PULL_UP;
+ if (sc->i2c_pullup)
+ reg |= AS3722_I2C_PULL_UP;
+
+ rv = RM1(sc, AS3722_IO_VOLTAGE,
+ AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, reg);
+ if (rv != 0)
+ return (ENXIO);
+
+ /* mask interrupts */
+ rv = WR1(sc, AS3722_INTERRUPT_MASK1, 0);
+ if (rv != 0)
+ return (ENXIO);
+ rv = WR1(sc, AS3722_INTERRUPT_MASK2, 0);
+ if (rv != 0)
+ return (ENXIO);
+ rv = WR1(sc, AS3722_INTERRUPT_MASK3, 0);
+ if (rv != 0)
+ return (ENXIO);
+ rv = WR1(sc, AS3722_INTERRUPT_MASK4, 0);
+ if (rv != 0)
+ return (ENXIO);
+ return (0);
+}
+
+static int
+as3722_parse_fdt(struct as3722_softc *sc, phandle_t node)
+{
+
+ sc->int_pullup =
+ OF_hasprop(node, "ams,enable-internal-int-pullup") ? 1 : 0;
+ sc->i2c_pullup =
+ OF_hasprop(node, "ams,enable-internal-i2c-pullup") ? 1 : 0;
+ return 0;
+}
+
+static void
+as3722_intr(void *arg)
+{
+ struct as3722_softc *sc;
+
+ sc = (struct as3722_softc *)arg;
+ /* XXX Finish temperature alarms. */
+}
+
+static int
+as3722_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "AS3722 PMIC");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+as3722_attach(device_t dev)
+{
+ struct as3722_softc *sc;
+ const char *dname;
+ int dunit, rv, rid;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->bus_addr = iicbus_get_addr(dev);
+ node = ofw_bus_get_node(sc->dev);
+ dname = device_get_name(dev);
+ dunit = device_get_unit(dev);
+ rv = 0;
+ LOCK_INIT(sc);
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate interrupt.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rv = as3722_parse_fdt(sc, node);
+ if (rv != 0)
+ goto fail;
+ rv = as3722_get_version(sc);
+ if (rv != 0)
+ goto fail;
+ rv = as3722_init(sc);
+ if (rv != 0)
+ goto fail;
+ rv = as3722_regulator_attach(sc, node);
+ if (rv != 0)
+ goto fail;
+ rv = as3722_gpio_attach(sc, node);
+ if (rv != 0)
+ goto fail;
+ rv = as3722_rtc_attach(sc, node);
+ if (rv != 0)
+ goto fail;
+
+ fdt_pinctrl_register(dev, NULL);
+ fdt_pinctrl_configure_by_name(dev, "default");
+
+ /* Setup interrupt. */
+ rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, as3722_intr, sc, &sc->irq_h);
+ if (rv) {
+ device_printf(dev, "Cannot setup interrupt.\n");
+ goto fail;
+ }
+ return (bus_generic_attach(dev));
+
+fail:
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ LOCK_DESTROY(sc);
+ return (rv);
+}
+
+static int
+as3722_detach(device_t dev)
+{
+ struct as3722_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ LOCK_DESTROY(sc);
+
+ return (bus_generic_detach(dev));
+}
+
+static phandle_t
+as3722_gpio_get_node(device_t bus, device_t dev)
+{
+
+ /* We only have one child, the GPIO bus, which needs our own node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t as3722_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, as3722_probe),
+ DEVMETHOD(device_attach, as3722_attach),
+ DEVMETHOD(device_detach, as3722_detach),
+
+ /* Regdev interface */
+ DEVMETHOD(regdev_map, as3722_regulator_map),
+
+ /* RTC interface */
+ DEVMETHOD(clock_gettime, as3722_rtc_gettime),
+ DEVMETHOD(clock_settime, as3722_rtc_settime),
+
+ /* GPIO protocol interface */
+ DEVMETHOD(gpio_get_bus, as3722_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, as3722_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, as3722_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, as3722_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, as3722_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, as3722_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, as3722_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, as3722_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, as3722_gpio_pin_toggle),
+ DEVMETHOD(gpio_map_gpios, as3722_gpio_map_gpios),
+
+ /* fdt_pinctrl interface */
+ DEVMETHOD(fdt_pinctrl_configure, as3722_pinmux_configure),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, as3722_gpio_get_node),
+
+ DEVMETHOD_END
+};
+
+static devclass_t as3722_devclass;
+DEFINE_CLASS_0(gpio, as3722_driver, as3722_methods,
+ sizeof(struct as3722_softc));
+EARLY_DRIVER_MODULE(as3722, iicbus, as3722_driver, as3722_devclass,
+ 0, 0, 74);
diff --git a/sys/arm/nvidia/as3722.h b/sys/arm/nvidia/as3722.h
new file mode 100644
index 0000000..c559a8a
--- /dev/null
+++ b/sys/arm/nvidia/as3722.h
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AS3722_H_
+
+#include <sys/clock.h>
+
+#define AS3722_SD0_VOLTAGE 0x00
+#define AS3722_SD_VSEL_MASK 0x7F /* For all SD */
+#define AS3722_SD0_VSEL_MIN 0x01
+#define AS3722_SD0_VSEL_MAX 0x5A
+#define AS3722_SD0_VSEL_LOW_VOL_MAX 0x6E
+
+#define AS3722_SD1_VOLTAGE 0x01
+#define AS3722_SD2_VOLTAGE 0x02
+#define AS3722_SD2_VSEL_MIN 0x01
+#define AS3722_SD2_VSEL_MAX 0x7F
+#define AS3722_SD3_VOLTAGE 0x03
+#define AS3722_SD4_VOLTAGE 0x04
+#define AS3722_SD5_VOLTAGE 0x05
+#define AS3722_SD6_VOLTAGE 0x06
+#define AS3722_GPIO0_CONTROL 0x08
+#define AS3722_GPIO_INVERT 0x80
+#define AS3722_GPIO_IOSF_MASK 0x0F
+#define AS3722_GPIO_IOSF_SHIFT 3
+#define AS3722_GPIO_MODE_MASK 0x07
+#define AS3722_GPIO_MODE_SHIFT 0
+
+#define AS3722_GPIO1_CONTROL 0x09
+#define AS3722_GPIO2_CONTROL 0x0A
+#define AS3722_GPIO3_CONTROL 0x0B
+#define AS3722_GPIO4_CONTROL 0x0C
+#define AS3722_GPIO5_CONTROL 0x0D
+#define AS3722_GPIO6_CONTROL 0x0E
+#define AS3722_GPIO7_CONTROL 0x0F
+#define AS3722_LDO0_VOLTAGE 0x10
+#define AS3722_LDO0_VSEL_MASK 0x1F
+#define AS3722_LDO0_VSEL_MIN 0x01
+#define AS3722_LDO0_VSEL_MAX 0x12
+#define AS3722_LDO0_NUM_VOLT 0x12
+
+#define AS3722_LDO1_VOLTAGE 0x11
+#define AS3722_LDO_VSEL_MASK 0x7F
+#define AS3722_LDO_VSEL_MIN 0x01
+#define AS3722_LDO_VSEL_MAX 0x7F
+#define AS3722_LDO_VSEL_DNU_MIN 0x25
+#define AS3722_LDO_VSEL_DNU_MAX 0x3F
+#define AS3722_LDO_NUM_VOLT 0x80
+
+#define AS3722_LDO2_VOLTAGE 0x12
+#define AS3722_LDO3_VOLTAGE 0x13
+#define AS3722_LDO3_VSEL_MASK 0x3F
+#define AS3722_LDO3_VSEL_MIN 0x01
+#define AS3722_LDO3_VSEL_MAX 0x2D
+#define AS3722_LDO3_NUM_VOLT 0x2D
+#define AS3722_LDO3_MODE_MASK (0x3 << 6)
+#define AS3722_LDO3_MODE_GET(x) (((x) >> 6) & 0x3)
+#define AS3722_LDO3_MODE(x) (((x) & 0x3) << 6)
+#define AS3722_LDO3_MODE_PMOS AS3722_LDO3_MODE(0)
+#define AS3722_LDO3_MODE_PMOS_TRACKING AS3722_LDO3_MODE(1)
+#define AS3722_LDO3_MODE_NMOS AS3722_LDO3_MODE(2)
+#define AS3722_LDO3_MODE_SWITCH AS3722_LDO3_MODE(3)
+
+#define AS3722_LDO4_VOLTAGE 0x14
+#define AS3722_LDO5_VOLTAGE 0x15
+#define AS3722_LDO6_VOLTAGE 0x16
+#define AS3722_LDO6_SEL_BYPASS 0x3F
+#define AS3722_LDO7_VOLTAGE 0x17
+#define AS3722_LDO9_VOLTAGE 0x19
+#define AS3722_LDO10_VOLTAGE 0x1A
+#define AS3722_LDO11_VOLTAGE 0x1B
+#define AS3722_LDO3_SETTINGS 0x1D
+#define AS3722_GPIO_DEB1 0x1E
+#define AS3722_GPIO_DEB2 0x1F
+#define AS3722_GPIO_SIGNAL_OUT 0x20
+#define AS3722_GPIO_SIGNAL_IN 0x21
+#define AS3722_REG_SEQU_MOD1 0x22
+#define AS3722_REG_SEQU_MOD2 0x23
+#define AS3722_REG_SEQU_MOD3 0x24
+#define AS3722_SD_PHSW_CTRL 0x27
+#define AS3722_SD_PHSW_STATUS 0x28
+
+#define AS3722_SD0_CONTROL 0x29
+#define AS3722_SD0_MODE_FAST (1 << 4)
+
+#define AS3722_SD1_CONTROL 0x2A
+#define AS3722_SD1_MODE_FAST (1 << 4)
+
+#define AS3722_SDMPH_CONTROL 0x2B
+#define AS3722_SD23_CONTROL 0x2C
+#define AS3722_SD3_MODE_FAST (1 << 6)
+#define AS3722_SD2_MODE_FAST (1 << 2)
+
+#define AS3722_SD4_CONTROL 0x2D
+#define AS3722_SD4_MODE_FAST (1 << 2)
+
+#define AS3722_SD5_CONTROL 0x2E
+#define AS3722_SD5_MODE_FAST (1 << 2)
+
+#define AS3722_SD6_CONTROL 0x2F
+#define AS3722_SD6_MODE_FAST (1 << 4)
+
+#define AS3722_SD_DVM 0x30
+#define AS3722_RESET_REASON 0x31
+#define AS3722_BATTERY_VOLTAGE_MONITOR 0x32
+#define AS3722_STARTUP_CONTROL 0x33
+#define AS3722_RESET_TIMER 0x34
+#define AS3722_REFERENCE_CONTROL 0x35
+#define AS3722_RESET_CONTROL 0x36
+#define AS3722_OVERTEMPERATURE_CONTROL 0x37
+#define AS3722_WATCHDOG_CONTROL 0x38
+#define AS3722_REG_STANDBY_MOD1 0x39
+#define AS3722_REG_STANDBY_MOD2 0x3A
+#define AS3722_REG_STANDBY_MOD3 0x3B
+#define AS3722_ENABLE_CTRL1 0x3C
+#define AS3722_SD3_EXT_ENABLE_MASK 0xC0
+#define AS3722_SD2_EXT_ENABLE_MASK 0x30
+#define AS3722_SD1_EXT_ENABLE_MASK 0x0C
+#define AS3722_SD0_EXT_ENABLE_MASK 0x03
+
+#define AS3722_ENABLE_CTRL2 0x3D
+#define AS3722_SD6_EXT_ENABLE_MASK 0x30
+#define AS3722_SD5_EXT_ENABLE_MASK 0x0C
+#define AS3722_SD4_EXT_ENABLE_MASK 0x03
+
+#define AS3722_ENABLE_CTRL3 0x3E
+#define AS3722_LDO3_EXT_ENABLE_MASK 0xC0
+#define AS3722_LDO2_EXT_ENABLE_MASK 0x30
+#define AS3722_LDO1_EXT_ENABLE_MASK 0x0C
+#define AS3722_LDO0_EXT_ENABLE_MASK 0x03
+
+#define AS3722_ENABLE_CTRL4 0x3F
+#define AS3722_LDO7_EXT_ENABLE_MASK 0xC0
+#define AS3722_LDO6_EXT_ENABLE_MASK 0x30
+#define AS3722_LDO5_EXT_ENABLE_MASK 0x0C
+#define AS3722_LDO4_EXT_ENABLE_MASK 0x03
+
+#define AS3722_ENABLE_CTRL5 0x40
+#define AS3722_LDO11_EXT_ENABLE_MASK 0xC0
+#define AS3722_LDO10_EXT_ENABLE_MASK 0x30
+#define AS3722_LDO9_EXT_ENABLE_MASK 0x0C
+
+#define AS3722_PWM_CONTROL_L 0x41
+#define AS3722_PWM_CONTROL_H 0x42
+#define AS3722_WATCHDOG_TIMER 0x46
+#define AS3722_WATCHDOG_SOFTWARE_SIGNAL 0x48
+#define AS3722_IO_VOLTAGE 0x49
+#define AS3722_I2C_PULL_UP (1 << 4)
+#define AS3722_INT_PULL_UP (1 << 5)
+
+#define AS3722_BATTERY_VOLTAGE_MONITOR2 0x4A
+#define AS3722_SD_CONTROL 0x4D
+#define AS3722_SDN_CTRL(x) (1 << (x))
+
+#define AS3722_LDO_CONTROL0 0x4E
+#define AS3722_LDO7_CTRL (1 << 7)
+#define AS3722_LDO6_CTRL (1 << 6)
+#define AS3722_LDO5_CTRL (1 << 5)
+#define AS3722_LDO4_CTRL (1 << 4)
+#define AS3722_LDO3_CTRL (1 << 3)
+#define AS3722_LDO2_CTRL (1 << 2)
+#define AS3722_LDO1_CTRL (1 << 1)
+#define AS3722_LDO0_CTRL (1 << 0)
+
+#define AS3722_LDO_CONTROL1 0x4F
+#define AS3722_LDO11_CTRL (1 << 3)
+#define AS3722_LDO10_CTRL (1 << 2)
+#define AS3722_LDO9_CTRL (1 << 1)
+
+#define AS3722_SD0_PROTECT 0x50
+#define AS3722_SD6_PROTECT 0x51
+#define AS3722_PWM_VCONTROL1 0x52
+#define AS3722_PWM_VCONTROL2 0x53
+#define AS3722_PWM_VCONTROL3 0x54
+#define AS3722_PWM_VCONTROL4 0x55
+#define AS3722_BB_CHARGER 0x57
+#define AS3722_CTRL_SEQU1 0x58
+#define AS3722_CTRL_SEQU2 0x59
+#define AS3722_OV_CURRENT 0x5A
+#define AS3722_OV_CURRENT_DEB 0x5B
+#define AS3722_SDLV_DEB 0x5C
+#define AS3722_OC_PG_CTRL 0x5D
+#define AS3722_OC_PG_CTRL2 0x5E
+#define AS3722_CTRL_STATUS 0x5F
+#define AS3722_RTC_CONTROL 0x60
+#define AS3722_RTC_AM_PM_MODE (1 << 7)
+#define AS3722_RTC_CLK32K_OUT_EN (1 << 5)
+#define AS3722_RTC_IRQ_MODE (1 << 3)
+#define AS3722_RTC_ON (1 << 2)
+#define AS3722_RTC_ALARM_WAKEUP_EN (1 << 1)
+#define AS3722_RTC_REP_WAKEUP_EN (1 << 0)
+
+#define AS3722_RTC_SECOND 0x61
+#define AS3722_RTC_MINUTE 0x62
+#define AS3722_RTC_HOUR 0x63
+#define AS3722_RTC_DAY 0x64
+#define AS3722_RTC_MONTH 0x65
+#define AS3722_RTC_YEAR 0x66
+#define AS3722_RTC_ALARM_SECOND 0x67
+#define AS3722_RTC_ALARM_MINUTE 0x68
+#define AS3722_RTC_ALARM_HOUR 0x69
+#define AS3722_RTC_ALARM_DAY 0x6A
+#define AS3722_RTC_ALARM_MONTH 0x6B
+#define AS3722_RTC_ALARM_YEAR 0x6C
+#define AS3722_SRAM 0x6D
+#define AS3722_RTC_ACCESS 0x6F
+#define AS3722_REG_STATUS 0x73
+#define AS3722_INTERRUPT_MASK1 0x74
+#define AS3722_INTERRUPT_MASK2 0x75
+#define AS3722_INTERRUPT_MASK3 0x76
+#define AS3722_INTERRUPT_MASK4 0x77
+#define AS3722_INTERRUPT_STATUS1 0x78
+#define AS3722_INTERRUPT_STATUS2 0x79
+#define AS3722_INTERRUPT_STATUS3 0x7A
+#define AS3722_INTERRUPT_STATUS4 0x7B
+#define AS3722_TEMP_STATUS 0x7D
+#define AS3722_ADC0_CONTROL 0x80
+#define AS3722_ADC1_CONTROL 0x81
+#define AS3722_ADC0_MSB_RESULT 0x82
+#define AS3722_ADC0_LSB_RESULT 0x83
+#define AS3722_ADC1_MSB_RESULT 0x84
+#define AS3722_ADC1_LSB_RESULT 0x85
+#define AS3722_ADC1_THRESHOLD_HI_MSB 0x86
+#define AS3722_ADC1_THRESHOLD_HI_LSB 0x87
+#define AS3722_ADC1_THRESHOLD_LO_MSB 0x88
+#define AS3722_ADC1_THRESHOLD_LO_LSB 0x89
+#define AS3722_ADC_CONFIGURATION 0x8A
+#define AS3722_ASIC_ID1 0x90
+#define AS3722_ASIC_ID2 0x91
+#define AS3722_LOCK 0x9E
+#define AS3722_FUSE7 0x9E
+#define AS3722_FUSE7_SD0_LOW_VOLTAGE (1 << 4)
+
+struct as3722_reg_sc;
+struct as3722_gpio_pin;
+
+struct as3722_softc {
+ device_t dev;
+ struct sx lock;
+ int bus_addr;
+ struct resource *irq_res;
+ void *irq_h;
+
+ uint8_t chip_rev;
+ int int_pullup;
+ int i2c_pullup;
+
+ /* Regulators. */
+ struct as3722_reg_sc **regs;
+ int nregs;
+
+ /* GPIO */
+ device_t gpio_busdev;
+ struct as3722_gpio_pin **gpio_pins;
+ int gpio_npins;
+ struct sx gpio_lock;
+
+};
+
+#define RD1(sc, reg, val) as3722_read(sc, reg, val)
+#define WR1(sc, reg, val) as3722_write(sc, reg, val)
+#define RM1(sc, reg, clr, set) as3722_modify(sc, reg, clr, set)
+
+int as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val);
+int as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val);
+int as3722_modify(struct as3722_softc *sc, uint8_t reg, uint8_t clear,
+ uint8_t set);
+int as3722_read_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
+ size_t size);
+int as3722_write_buf(struct as3722_softc *sc, uint8_t reg, uint8_t *buf,
+ size_t size);
+
+/* Regulators */
+int as3722_regulator_attach(struct as3722_softc *sc, phandle_t node);
+int as3722_regulator_map(device_t dev, phandle_t xref, int ncells,
+ pcell_t *cells, int *num);
+
+/* RTC */
+int as3722_rtc_attach(struct as3722_softc *sc, phandle_t node);
+int as3722_rtc_gettime(device_t dev, struct timespec *ts);
+int as3722_rtc_settime(device_t dev, struct timespec *ts);
+
+/* GPIO */
+device_t as3722_gpio_get_bus(device_t dev);
+int as3722_gpio_pin_max(device_t dev, int *maxpin);
+int as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
+int as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags);
+int as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
+int as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
+int as3722_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+int as3722_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
+int as3722_gpio_pin_toggle(device_t dev, uint32_t pin);
+int as3722_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
+ int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags);
+int as3722_gpio_attach(struct as3722_softc *sc, phandle_t node);
+int as3722_pinmux_configure(device_t dev, phandle_t cfgxref);
+
+#endif /* _AS3722_H_ */
diff --git a/sys/arm/nvidia/as3722_gpio.c b/sys/arm/nvidia/as3722_gpio.c
new file mode 100644
index 0000000..8e53bce
--- /dev/null
+++ b/sys/arm/nvidia/as3722_gpio.c
@@ -0,0 +1,577 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include "as3722.h"
+
+MALLOC_DEFINE(M_AS3722_GPIO, "AS3722 gpio", "AS3722 GPIO");
+
+/* AS3722_GPIOx_CONTROL MODE and IOSF definition. */
+#define AS3722_IOSF_GPIO 0x00
+#define AS3722_IOSF_INTERRUPT_OUT 0x01
+#define AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT 0x02
+#define AS3722_IOSF_GPIO_IN_INTERRUPT 0x03
+#define AS3722_IOSF_PWM_IN 0x04
+#define AS3722_IOSF_VOLTAGE_IN_STANDBY 0x05
+#define AS3722_IOSF_OC_PG_SD0 0x06
+#define AS3722_IOSF_POWERGOOD_OUT 0x07
+#define AS3722_IOSF_CLK32K_OUT 0x08
+#define AS3722_IOSF_WATCHDOG_IN 0x09
+#define AS3722_IOSF_SOFT_RESET_IN 0x0b
+#define AS3722_IOSF_PWM_OUT 0x0c
+#define AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT 0x0d
+#define AS3722_IOSF_OC_PG_SD6 0x0e
+
+#define AS3722_MODE_INPUT 0
+#define AS3722_MODE_PUSH_PULL 1
+#define AS3722_MODE_OPEN_DRAIN 2
+#define AS3722_MODE_TRISTATE 3
+#define AS3722_MODE_INPUT_PULL_UP_LV 4
+#define AS3722_MODE_INPUT_PULL_DOWN 5
+#define AS3722_MODE_OPEN_DRAIN_LV 6
+#define AS3722_MODE_PUSH_PULL_LV 7
+
+#define NGPIO 8
+
+#define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock)
+#define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock)
+#define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED)
+
+#define AS3722_CFG_BIAS_DISABLE 0x0001
+#define AS3722_CFG_BIAS_PULL_UP 0x0002
+#define AS3722_CFG_BIAS_PULL_DOWN 0x0004
+#define AS3722_CFG_BIAS_HIGH_IMPEDANCE 0x0008
+#define AS3722_CFG_OPEN_DRAIN 0x0010
+
+static const struct {
+ const char *name;
+ int config; /* AS3722_CFG_ */
+} as3722_cfg_names[] = {
+ {"bias-disable", AS3722_CFG_BIAS_DISABLE},
+ {"bias-pull-up", AS3722_CFG_BIAS_PULL_UP},
+ {"bias-pull-down", AS3722_CFG_BIAS_PULL_DOWN},
+ {"bias-high-impedance", AS3722_CFG_BIAS_HIGH_IMPEDANCE},
+ {"drive-open-drain", AS3722_CFG_OPEN_DRAIN},
+};
+
+static struct {
+ const char *name;
+ int fnc_val;
+} as3722_fnc_table[] = {
+ {"gpio", AS3722_IOSF_GPIO},
+ {"interrupt-out", AS3722_IOSF_INTERRUPT_OUT},
+ {"vsup-vbat-low-undebounce-out", AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT},
+ {"gpio-in-interrupt", AS3722_IOSF_GPIO_IN_INTERRUPT},
+ {"pwm-in", AS3722_IOSF_PWM_IN},
+ {"voltage-in-standby", AS3722_IOSF_VOLTAGE_IN_STANDBY},
+ {"oc-pg-sd0", AS3722_IOSF_OC_PG_SD0},
+ {"powergood-out", AS3722_IOSF_POWERGOOD_OUT},
+ {"clk32k-out", AS3722_IOSF_CLK32K_OUT},
+ {"watchdog-in", AS3722_IOSF_WATCHDOG_IN},
+ {"soft-reset-in", AS3722_IOSF_SOFT_RESET_IN},
+ {"pwm-out", AS3722_IOSF_PWM_OUT},
+ {"vsup-vbat-low-debounce-out", AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT},
+ {"oc-pg-sd6", AS3722_IOSF_OC_PG_SD6},
+};
+
+struct as3722_pincfg {
+ char *function;
+ int flags;
+};
+
+struct as3722_gpio_pin {
+ int pin_caps;
+ uint8_t pin_ctrl_reg;
+ char pin_name[GPIOMAXNAME];
+ int pin_cfg_flags;
+};
+
+
+/* --------------------------------------------------------------------------
+ *
+ * Pinmux functions.
+ */
+static int
+as3722_pinmux_get_function(struct as3722_softc *sc, char *name)
+{
+ int i;
+
+ for (i = 0; i < nitems(as3722_fnc_table); i++) {
+ if (strcmp(as3722_fnc_table[i].name, name) == 0)
+ return (as3722_fnc_table[i].fnc_val);
+ }
+ return (-1);
+}
+
+
+
+static int
+as3722_pinmux_config_node(struct as3722_softc *sc, char *pin_name,
+ struct as3722_pincfg *cfg)
+{
+ uint8_t ctrl;
+ int rv, fnc, pin;
+
+ for (pin = 0; pin < sc->gpio_npins; pin++) {
+ if (strcmp(sc->gpio_pins[pin]->pin_name, pin_name) == 0)
+ break;
+ }
+ if (pin >= sc->gpio_npins) {
+ device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
+ return (ENXIO);
+ }
+
+ ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
+ sc->gpio_pins[pin]->pin_cfg_flags = cfg->flags;
+ if (cfg->function != NULL) {
+ fnc = as3722_pinmux_get_function(sc, cfg->function);
+ if (fnc == -1) {
+ device_printf(sc->dev,
+ "Unknown function %s for pin %s\n", cfg->function,
+ sc->gpio_pins[pin]->pin_name);
+ return (ENXIO);
+ }
+ switch (fnc) {
+ case AS3722_IOSF_INTERRUPT_OUT:
+ case AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT:
+ case AS3722_IOSF_OC_PG_SD0:
+ case AS3722_IOSF_POWERGOOD_OUT:
+ case AS3722_IOSF_CLK32K_OUT:
+ case AS3722_IOSF_PWM_OUT:
+ case AS3722_IOSF_OC_PG_SD6:
+ ctrl &= ~(AS3722_GPIO_MODE_MASK <<
+ AS3722_GPIO_MODE_SHIFT);
+ ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
+ /* XXX Handle flags (OC + pullup) */
+ break;
+ case AS3722_IOSF_GPIO_IN_INTERRUPT:
+ case AS3722_IOSF_PWM_IN:
+ case AS3722_IOSF_VOLTAGE_IN_STANDBY:
+ case AS3722_IOSF_WATCHDOG_IN:
+ case AS3722_IOSF_SOFT_RESET_IN:
+ ctrl &= ~(AS3722_GPIO_MODE_MASK <<
+ AS3722_GPIO_MODE_SHIFT);
+ ctrl |= AS3722_MODE_INPUT << AS3722_GPIO_MODE_SHIFT;
+ /* XXX Handle flags (pulldown + pullup) */
+
+ default:
+ break;
+ }
+ ctrl &= ~(AS3722_GPIO_IOSF_MASK << AS3722_GPIO_IOSF_SHIFT);
+ ctrl |= fnc << AS3722_GPIO_IOSF_SHIFT;
+ }
+ rv = 0;
+ if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
+ rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
+ sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
+ }
+ return (rv);
+}
+
+static int
+as3722_pinmux_read_node(struct as3722_softc *sc, phandle_t node,
+ struct as3722_pincfg *cfg, char **pins, int *lpins)
+{
+ int rv, i;
+
+ *lpins = OF_getprop_alloc(node, "pins", 1, (void **)pins);
+ if (*lpins <= 0)
+ return (ENOENT);
+
+ /* Read function (mux) settings. */
+ rv = OF_getprop_alloc(node, "function", 1, (void **)&cfg->function);
+ if (rv <= 0)
+ cfg->function = NULL;
+
+ /* Read boolean properties. */
+ for (i = 0; i < nitems(as3722_cfg_names); i++) {
+ if (OF_hasprop(node, as3722_cfg_names[i].name))
+ cfg->flags |= as3722_cfg_names[i].config;
+ }
+ return (0);
+}
+
+static int
+as3722_pinmux_process_node(struct as3722_softc *sc, phandle_t node)
+{
+ struct as3722_pincfg cfg;
+ char *pins, *pname;
+ int i, len, lpins, rv;
+
+ rv = as3722_pinmux_read_node(sc, node, &cfg, &pins, &lpins);
+ if (rv != 0)
+ return (rv);
+
+ len = 0;
+ pname = pins;
+ do {
+ i = strlen(pname) + 1;
+ rv = as3722_pinmux_config_node(sc, pname, &cfg);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot configure pin: %s: %d\n", pname, rv);
+ }
+ len += i;
+ pname += i;
+ } while (len < lpins);
+
+ if (pins != NULL)
+ free(pins, M_OFWPROP);
+ if (cfg.function != NULL)
+ free(cfg.function, M_OFWPROP);
+
+ return (rv);
+}
+
+int as3722_pinmux_configure(device_t dev, phandle_t cfgxref)
+{
+ struct as3722_softc *sc;
+ phandle_t node, cfgnode;
+ int rv;
+
+ sc = device_get_softc(dev);
+ cfgnode = OF_node_from_xref(cfgxref);
+
+ for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
+ if (!fdt_is_enabled(node))
+ continue;
+ rv = as3722_pinmux_process_node(sc, node);
+ if (rv != 0)
+ device_printf(dev, "Failed to process pinmux");
+
+ }
+ return (0);
+}
+
+/* --------------------------------------------------------------------------
+ *
+ * GPIO
+ */
+device_t
+as3722_gpio_get_bus(device_t dev)
+{
+ struct as3722_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->gpio_busdev);
+}
+
+int
+as3722_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = NGPIO - 1;
+ return (0);
+}
+
+int
+as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct as3722_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+ GPIO_LOCK(sc);
+ *caps = sc->gpio_pins[pin]->pin_caps;
+ GPIO_UNLOCK(sc);
+ return (0);
+}
+
+int
+as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct as3722_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+ GPIO_LOCK(sc);
+ memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME);
+ GPIO_UNLOCK(sc);
+ return (0);
+}
+
+int
+as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags)
+{
+ struct as3722_softc *sc;
+ uint8_t tmp, mode, iosf;
+ uint32_t flags;
+ bool inverted;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ tmp = sc->gpio_pins[pin]->pin_ctrl_reg;
+ GPIO_UNLOCK(sc);
+ iosf = (tmp >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
+ mode = (tmp >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
+ inverted = (tmp & AS3722_GPIO_INVERT) != 0;
+ /* Is pin in GPIO mode ? */
+ if (iosf != AS3722_IOSF_GPIO)
+ return (ENXIO);
+
+ flags = 0;
+ switch (mode) {
+ case AS3722_MODE_INPUT:
+ flags = GPIO_PIN_INPUT;
+ break;
+ case AS3722_MODE_PUSH_PULL:
+ case AS3722_MODE_PUSH_PULL_LV:
+ flags = GPIO_PIN_OUTPUT;
+ break;
+ case AS3722_MODE_OPEN_DRAIN:
+ case AS3722_MODE_OPEN_DRAIN_LV:
+ flags = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN;
+ break;
+ case AS3722_MODE_TRISTATE:
+ flags = GPIO_PIN_TRISTATE;
+ break;
+ case AS3722_MODE_INPUT_PULL_UP_LV:
+ flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+ break;
+
+ case AS3722_MODE_INPUT_PULL_DOWN:
+ flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLDOWN;
+ break;
+ }
+ if (inverted)
+ flags |= GPIO_PIN_INVIN | GPIO_PIN_INVOUT;
+ *out_flags = flags;
+ return (0);
+}
+
+static int
+as3722_gpio_get_mode(struct as3722_softc *sc, uint32_t pin, uint32_t gpio_flags)
+{
+ uint8_t ctrl;
+ int flags;
+
+ ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
+ flags = sc->gpio_pins[pin]->pin_cfg_flags;
+
+ /* Tristate mode. */
+ if (flags & AS3722_CFG_BIAS_HIGH_IMPEDANCE ||
+ gpio_flags & GPIO_PIN_TRISTATE)
+ return (AS3722_MODE_TRISTATE);
+
+ /* Open drain modes. */
+ if (flags & AS3722_CFG_OPEN_DRAIN || gpio_flags & GPIO_PIN_OPENDRAIN) {
+ /* Only pull up have effect */
+ if (flags & AS3722_CFG_BIAS_PULL_UP ||
+ gpio_flags & GPIO_PIN_PULLUP)
+ return (AS3722_MODE_OPEN_DRAIN_LV);
+ return (AS3722_MODE_OPEN_DRAIN);
+ }
+ /* Input modes. */
+ if (gpio_flags & GPIO_PIN_INPUT) {
+ /* Accept pull up or pull down. */
+ if (flags & AS3722_CFG_BIAS_PULL_UP ||
+ gpio_flags & GPIO_PIN_PULLUP)
+ return (AS3722_MODE_INPUT_PULL_UP_LV);
+
+ if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
+ gpio_flags & GPIO_PIN_PULLDOWN)
+ return (AS3722_MODE_INPUT_PULL_DOWN);
+ return (AS3722_MODE_INPUT);
+ }
+ /*
+ * Output modes.
+ * Pull down is used as indicator of low voltage output.
+ */
+ if (flags & AS3722_CFG_BIAS_PULL_DOWN ||
+ gpio_flags & GPIO_PIN_PULLDOWN)
+ return (AS3722_MODE_PUSH_PULL_LV);
+ return (AS3722_MODE_PUSH_PULL);
+}
+
+int
+as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct as3722_softc *sc;
+ uint8_t ctrl, mode, iosf;
+ int rv;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
+ iosf = (ctrl >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK;
+ /* Is pin in GPIO mode ? */
+ if (iosf != AS3722_IOSF_GPIO) {
+ GPIO_UNLOCK(sc);
+ return (ENXIO);
+ }
+ mode = as3722_gpio_get_mode(sc, pin, flags);
+ ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT);
+ ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT;
+ rv = 0;
+ if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) {
+ rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl);
+ sc->gpio_pins[pin]->pin_ctrl_reg = ctrl;
+ }
+ GPIO_UNLOCK(sc);
+ return (rv);
+}
+
+int
+as3722_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)
+{
+ struct as3722_softc *sc;
+ uint8_t tmp;
+ int rv;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ tmp = (val != 0) ? 1 : 0;
+ if (sc->gpio_pins[pin]->pin_ctrl_reg & AS3722_GPIO_INVERT)
+ tmp ^= 1;
+
+ GPIO_LOCK(sc);
+ rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), (tmp << pin));
+ GPIO_UNLOCK(sc);
+ return (rv);
+}
+
+int
+as3722_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)
+{
+ struct as3722_softc *sc;
+ uint8_t tmp, mode, ctrl;
+ int rv;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ ctrl = sc->gpio_pins[pin]->pin_ctrl_reg;
+ mode = (ctrl >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK;
+ if ((mode == AS3722_MODE_PUSH_PULL) ||
+ (mode == AS3722_MODE_PUSH_PULL_LV))
+ rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
+ else
+ rv = RD1(sc, AS3722_GPIO_SIGNAL_IN, &tmp);
+ GPIO_UNLOCK(sc);
+ if (rv != 0)
+ return (rv);
+
+ *val = tmp & (1 << pin) ? 1 : 0;
+ if (ctrl & AS3722_GPIO_INVERT)
+ *val ^= 1;
+ return (0);
+}
+
+int
+as3722_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct as3722_softc *sc;
+ uint8_t tmp;
+ int rv;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp);
+ if (rv != 0) {
+ GPIO_UNLOCK(sc);
+ return (rv);
+ }
+ tmp ^= (1 <<pin);
+ rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), tmp);
+ GPIO_UNLOCK(sc);
+ return (0);
+}
+
+int
+as3722_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
+ int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+
+ if (gcells != 2)
+ return (ERANGE);
+ *pin = gpios[0];
+ *flags= gpios[1];
+ return (0);
+}
+
+int
+as3722_gpio_attach(struct as3722_softc *sc, phandle_t node)
+{
+ struct as3722_gpio_pin *pin;
+ int i, rv;
+
+ sx_init(&sc->gpio_lock, "AS3722 GPIO lock");
+ sc->gpio_npins = NGPIO;
+ sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) *
+ sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO);
+
+
+ sc->gpio_busdev = gpiobus_attach_bus(sc->dev);
+ if (sc->gpio_busdev == NULL)
+ return (ENXIO);
+ for (i = 0; i < sc->gpio_npins; i++) {
+ sc->gpio_pins[i] = malloc(sizeof(struct as3722_gpio_pin),
+ M_AS3722_GPIO, M_WAITOK | M_ZERO);
+ pin = sc->gpio_pins[i];
+ sprintf(pin->pin_name, "gpio%d", i);
+ pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
+ GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE |
+ GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN |
+ GPIO_PIN_INVOUT;
+ rv = RD1(sc, AS3722_GPIO0_CONTROL + i, &pin->pin_ctrl_reg);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot read configuration for pin %s\n",
+ sc->gpio_pins[i]->pin_name);
+ }
+ }
+ return (0);
+}
diff --git a/sys/arm/nvidia/as3722_regulators.c b/sys/arm/nvidia/as3722_regulators.c
new file mode 100644
index 0000000..0bca8e1
--- /dev/null
+++ b/sys/arm/nvidia/as3722_regulators.c
@@ -0,0 +1,811 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sx.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/regulator/regulator.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include <gnu/dts/include/dt-bindings/mfd/as3722.h>
+
+#include "as3722.h"
+
+MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator");
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+enum as3722_reg_id {
+ AS3722_REG_ID_SD0,
+ AS3722_REG_ID_SD1,
+ AS3722_REG_ID_SD2,
+ AS3722_REG_ID_SD3,
+ AS3722_REG_ID_SD4,
+ AS3722_REG_ID_SD5,
+ AS3722_REG_ID_SD6,
+ AS3722_REG_ID_LDO0,
+ AS3722_REG_ID_LDO1,
+ AS3722_REG_ID_LDO2,
+ AS3722_REG_ID_LDO3,
+ AS3722_REG_ID_LDO4,
+ AS3722_REG_ID_LDO5,
+ AS3722_REG_ID_LDO6,
+ AS3722_REG_ID_LDO7,
+ AS3722_REG_ID_LDO9,
+ AS3722_REG_ID_LDO10,
+ AS3722_REG_ID_LDO11,
+};
+
+struct regulator_range {
+ u_int min_uvolt;
+ u_int step_uvolt;
+ u_int min_sel;
+ u_int max_sel;
+};
+
+
+/* Regulator HW definition. */
+struct reg_def {
+ intptr_t id; /* ID */
+ char *name; /* Regulator name */
+ char *supply_name; /* Source property name */
+ uint8_t volt_reg;
+ uint8_t volt_vsel_mask;
+ uint8_t enable_reg;
+ uint8_t enable_mask;
+ uint8_t ext_enable_reg;
+ uint8_t ext_enable_mask;
+ struct regulator_range *ranges;
+ int nranges;
+};
+
+struct as3722_reg_sc {
+ struct regnode *regnode;
+ struct as3722_softc *base_sc;
+ struct reg_def *def;
+ phandle_t xref;
+
+ struct regnode_std_param *param;
+ int ext_control;
+ int enable_tracking;
+
+ int enable_usec;
+};
+
+#define RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) \
+{ \
+ .min_sel = _min_sel, \
+ .max_sel = _max_sel, \
+ .min_uvolt = _min_uvolt, \
+ .step_uvolt = _step_uvolt, \
+}
+
+static struct regulator_range as3722_sd016_ranges[] = {
+ RANGE_INIT(0x00, 0x00, 0, 0),
+ RANGE_INIT(0x01, 0x5A, 610000, 10000),
+};
+
+static struct regulator_range as3722_sd0_lv_ranges[] = {
+ RANGE_INIT(0x00, 0x00, 0, 0),
+ RANGE_INIT(0x01, 0x6E, 410000, 10000),
+};
+
+static struct regulator_range as3722_sd_ranges[] = {
+ RANGE_INIT(0x00, 0x00, 0, 0),
+ RANGE_INIT(0x01, 0x40, 612500, 12500),
+ RANGE_INIT(0x41, 0x70, 1425000, 25000),
+ RANGE_INIT(0x71, 0x7F, 2650000, 50000),
+};
+
+static struct regulator_range as3722_ldo3_ranges[] = {
+ RANGE_INIT(0x00, 0x00, 0, 0),
+ RANGE_INIT(0x01, 0x2D, 620000, 20000),
+};
+
+static struct regulator_range as3722_ldo_ranges[] = {
+ RANGE_INIT(0x00, 0x00, 0, 0),
+ RANGE_INIT(0x01, 0x24, 825000, 25000),
+ RANGE_INIT(0x40, 0x7F, 1725000, 25000),
+};
+
+static struct reg_def as3722s_def[] = {
+ {
+ .id = AS3722_REG_ID_SD0,
+ .name = "sd0",
+ .volt_reg = AS3722_SD0_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(0),
+ .ext_enable_reg = AS3722_ENABLE_CTRL1,
+ .ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK,
+ .ranges = as3722_sd016_ranges,
+ .nranges = nitems(as3722_sd016_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD1,
+ .name = "sd1",
+ .volt_reg = AS3722_SD1_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(1),
+ .ext_enable_reg = AS3722_ENABLE_CTRL1,
+ .ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK,
+ .ranges = as3722_sd_ranges,
+ .nranges = nitems(as3722_sd_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD2,
+ .name = "sd2",
+ .supply_name = "vsup-sd2",
+ .volt_reg = AS3722_SD2_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(2),
+ .ext_enable_reg = AS3722_ENABLE_CTRL1,
+ .ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK,
+ .ranges = as3722_sd_ranges,
+ .nranges = nitems(as3722_sd_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD3,
+ .name = "sd3",
+ .supply_name = "vsup-sd3",
+ .volt_reg = AS3722_SD3_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(3),
+ .ext_enable_reg = AS3722_ENABLE_CTRL1,
+ .ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK,
+ .ranges = as3722_sd_ranges,
+ .nranges = nitems(as3722_sd_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD4,
+ .name = "sd4",
+ .supply_name = "vsup-sd4",
+ .volt_reg = AS3722_SD4_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(4),
+ .ext_enable_reg = AS3722_ENABLE_CTRL2,
+ .ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK,
+ .ranges = as3722_sd_ranges,
+ .nranges = nitems(as3722_sd_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD5,
+ .name = "sd5",
+ .supply_name = "vsup-sd5",
+ .volt_reg = AS3722_SD5_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(5),
+ .ext_enable_reg = AS3722_ENABLE_CTRL2,
+ .ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK,
+ .ranges = as3722_sd_ranges,
+ .nranges = nitems(as3722_sd_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_SD6,
+ .name = "sd6",
+ .volt_reg = AS3722_SD6_VOLTAGE,
+ .volt_vsel_mask = AS3722_SD_VSEL_MASK,
+ .enable_reg = AS3722_SD_CONTROL,
+ .enable_mask = AS3722_SDN_CTRL(6),
+ .ext_enable_reg = AS3722_ENABLE_CTRL2,
+ .ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK,
+ .ranges = as3722_sd016_ranges,
+ .nranges = nitems(as3722_sd016_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO0,
+ .name = "ldo0",
+ .supply_name = "vin-ldo0",
+ .volt_reg = AS3722_LDO0_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO0_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO0_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL3,
+ .ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO1,
+ .name = "ldo1",
+ .supply_name = "vin-ldo1-6",
+ .volt_reg = AS3722_LDO1_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO1_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL3,
+ .ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO2,
+ .name = "ldo2",
+ .supply_name = "vin-ldo2-5-7",
+ .volt_reg = AS3722_LDO2_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO2_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL3,
+ .ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO3,
+ .name = "ldo3",
+ .supply_name = "vin-ldo3-4",
+ .volt_reg = AS3722_LDO3_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO3_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO3_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL3,
+ .ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo3_ranges,
+ .nranges = nitems(as3722_ldo3_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO4,
+ .name = "ldo4",
+ .supply_name = "vin-ldo3-4",
+ .volt_reg = AS3722_LDO4_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO4_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL4,
+ .ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO5,
+ .name = "ldo5",
+ .supply_name = "vin-ldo2-5-7",
+ .volt_reg = AS3722_LDO5_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO5_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL4,
+ .ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO6,
+ .name = "ldo6",
+ .supply_name = "vin-ldo1-6",
+ .volt_reg = AS3722_LDO6_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO6_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL4,
+ .ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO7,
+ .name = "ldo7",
+ .supply_name = "vin-ldo2-5-7",
+ .volt_reg = AS3722_LDO7_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL0,
+ .enable_mask = AS3722_LDO7_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL4,
+ .ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO9,
+ .name = "ldo9",
+ .supply_name = "vin-ldo9-10",
+ .volt_reg = AS3722_LDO9_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL1,
+ .enable_mask = AS3722_LDO9_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL5,
+ .ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO10,
+ .name = "ldo10",
+ .supply_name = "vin-ldo9-10",
+ .volt_reg = AS3722_LDO10_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL1,
+ .enable_mask = AS3722_LDO10_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL5,
+ .ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+ {
+ .id = AS3722_REG_ID_LDO11,
+ .name = "ldo11",
+ .supply_name = "vin-ldo11",
+ .volt_reg = AS3722_LDO11_VOLTAGE,
+ .volt_vsel_mask = AS3722_LDO_VSEL_MASK,
+ .enable_reg = AS3722_LDO_CONTROL1,
+ .enable_mask = AS3722_LDO11_CTRL,
+ .ext_enable_reg = AS3722_ENABLE_CTRL5,
+ .ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK,
+ .ranges = as3722_ldo_ranges,
+ .nranges = nitems(as3722_ldo_ranges),
+ },
+};
+
+
+struct as3722_regnode_init_def {
+ struct regnode_init_def reg_init_def;
+ int ext_control;
+ int enable_tracking;
+};
+
+static int as3722_regnode_init(struct regnode *regnode);
+static int as3722_regnode_enable(struct regnode *regnode, bool enable,
+ int *udelay);
+static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt,
+ int max_uvolt, int *udelay);
+static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt);
+static regnode_method_t as3722_regnode_methods[] = {
+ /* Regulator interface */
+ REGNODEMETHOD(regnode_init, as3722_regnode_init),
+ REGNODEMETHOD(regnode_enable, as3722_regnode_enable),
+ REGNODEMETHOD(regnode_set_voltage, as3722_regnode_set_volt),
+ REGNODEMETHOD(regnode_get_voltage, as3722_regnode_get_volt),
+ REGNODEMETHOD_END
+};
+DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods,
+ sizeof(struct as3722_reg_sc), regnode_class);
+
+static int
+regulator_range_sel_to_volt(struct as3722_reg_sc *sc, uint8_t sel, int *volt)
+{
+ struct regulator_range *range;
+ struct reg_def *def;
+ int i;
+
+ def = sc->def;
+ if (def->nranges == 0)
+ panic("Voltage regulator have zero ranges\n");
+
+ for (i = 0; i < def->nranges ; i++) {
+ range = def->ranges + i;
+
+ if (!(sel >= range->min_sel &&
+ sel <= range->max_sel))
+ continue;
+
+ sel -= range->min_sel;
+
+ *volt = range->min_uvolt + sel * range->step_uvolt;
+ return (0);
+ }
+
+ return (ERANGE);
+}
+
+static int
+regulator_range_volt_to_sel(struct as3722_reg_sc *sc, int min_uvolt,
+ int max_uvolt, uint8_t *out_sel)
+{
+ struct regulator_range *range;
+ struct reg_def *def;
+ uint8_t sel;
+ int uvolt;
+ int rv, i;
+
+ def = sc->def;
+ if (def->nranges == 0)
+ panic("Voltage regulator have zero ranges\n");
+
+ for (i = 0; i < def->nranges; i++) {
+ range = def->ranges + i;
+ uvolt = range->min_uvolt +
+ (range->max_sel - range->min_sel) * range->step_uvolt;
+
+ if ((min_uvolt > uvolt) ||
+ (max_uvolt < range->min_uvolt))
+ continue;
+
+ if (min_uvolt <= range->min_uvolt)
+ min_uvolt = range->min_uvolt;
+
+ /* If step is zero then range is fixed voltage range. */
+ if (range->step_uvolt == 0)
+ sel = 0;
+ else
+ sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt,
+ range->step_uvolt);
+
+
+ sel += range->min_sel;
+
+ break;
+ }
+
+ if (i >= def->nranges)
+ return (ERANGE);
+
+ /* Verify new settings. */
+ rv = regulator_range_sel_to_volt(sc, sel, &uvolt);
+ if (rv != 0)
+ return (rv);
+ if ((uvolt < min_uvolt) || (uvolt > max_uvolt))
+ return (ERANGE);
+
+ *out_sel = sel;
+ return (0);
+}
+
+
+static int
+as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel)
+{
+ int rv;
+
+ rv = RD1(sc->base_sc, sc->def->volt_reg, sel);
+ if (rv != 0)
+ return (rv);
+ *sel &= sc->def->volt_vsel_mask;
+ *sel >>= ffs(sc->def->volt_vsel_mask) - 1;
+ return (0);
+}
+
+static int
+as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel)
+{
+ int rv;
+
+ sel <<= ffs(sc->def->volt_vsel_mask) - 1;
+ sel &= sc->def->volt_vsel_mask;
+
+ rv = RM1(sc->base_sc, sc->def->volt_reg,
+ sc->def->volt_vsel_mask, sel);
+ if (rv != 0)
+ return (rv);
+ return (rv);
+}
+
+static bool
+as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc)
+{
+ uint8_t val;
+ int rv;
+
+ rv = RD1(sc->base_sc, AS3722_FUSE7, &val);
+ if (rv != 0)
+ return (rv);
+ return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false);
+}
+
+static int
+as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl)
+{
+ uint8_t val;
+ int rv;
+
+ val = ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1);
+ rv = RM1(sc->base_sc, sc->def->ext_enable_reg,
+ sc->def->ext_enable_mask, val);
+ return (rv);
+}
+
+static int
+as3722_reg_enable(struct as3722_reg_sc *sc)
+{
+ int rv;
+
+ rv = RM1(sc->base_sc, sc->def->enable_reg,
+ sc->def->enable_mask, sc->def->enable_mask);
+ return (rv);
+}
+
+static int
+as3722_reg_disable(struct as3722_reg_sc *sc)
+{
+ int rv;
+
+ rv = RM1(sc->base_sc, sc->def->enable_reg,
+ sc->def->enable_mask, 0);
+ return (rv);
+}
+
+static int
+as3722_regnode_init(struct regnode *regnode)
+{
+ struct as3722_reg_sc *sc;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+
+ sc->enable_usec = 500;
+ if (sc->def->id == AS3722_REG_ID_SD0) {
+ if (as3722_sd0_is_low_voltage(sc)) {
+ sc->def->ranges = as3722_sd0_lv_ranges;
+ sc->def->nranges = nitems(as3722_sd0_lv_ranges);
+ }
+ sc->enable_usec = 600;
+ } else if (sc->def->id == AS3722_REG_ID_LDO3) {
+ if (sc->enable_tracking) {
+ rv = RM1(sc->base_sc, sc->def->volt_reg,
+ AS3722_LDO3_MODE_MASK,
+ AS3722_LDO3_MODE_PMOS_TRACKING);
+ if (rv < 0) {
+ device_printf(sc->base_sc->dev,
+ "LDO3 tracking failed: %d\n", rv);
+ return (rv);
+ }
+ }
+ }
+
+ if (sc->ext_control) {
+
+ rv = as3722_reg_enable(sc);
+ if (rv < 0) {
+ device_printf(sc->base_sc->dev,
+ "Failed to enable %s regulator: %d\n",
+ sc->def->name, rv);
+ return (rv);
+ }
+ rv = as3722_reg_extreg_setup(sc, sc->ext_control);
+ if (rv < 0) {
+ device_printf(sc->base_sc->dev,
+ "%s ext control failed: %d", sc->def->name, rv);
+ return (rv);
+ }
+ }
+ return (0);
+}
+
+static void
+as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def,
+struct as3722_regnode_init_def *init_def)
+{
+ int rv;
+ phandle_t parent, supply_node;
+ char prop_name[64]; /* Maximum OFW property name length. */
+
+ rv = regulator_parse_ofw_stdparam(sc->dev, node,
+ &init_def->reg_init_def);
+
+ rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control,
+ sizeof(init_def->ext_control));
+ if (rv <= 0)
+ init_def->ext_control = 0;
+ if (init_def->ext_control > 3) {
+ device_printf(sc->dev,
+ "Invalid value for ams,ext-control property: %d\n",
+ init_def->ext_control);
+ init_def->ext_control = 0;
+ }
+ if (OF_hasprop(node, "ams,enable-tracking"))
+ init_def->enable_tracking = 1;
+
+
+ /* Get parent supply. */
+ if (def->supply_name == NULL)
+ return;
+
+ parent = OF_parent(node);
+ snprintf(prop_name, sizeof(prop_name), "%s-supply",
+ def->supply_name);
+ rv = OF_getencprop(parent, prop_name, &supply_node,
+ sizeof(supply_node));
+ if (rv <= 0)
+ return;
+ supply_node = OF_node_from_xref(supply_node);
+ rv = OF_getprop_alloc(supply_node, "regulator-name", 1,
+ (void **)&init_def->reg_init_def.parent_name);
+ if (rv <= 0)
+ init_def->reg_init_def.parent_name = NULL;
+}
+
+static struct as3722_reg_sc *
+as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def)
+{
+ struct as3722_reg_sc *reg_sc;
+ struct as3722_regnode_init_def init_def;
+ struct regnode *regnode;
+
+ bzero(&init_def, sizeof(init_def));
+
+ as3722_fdt_parse(sc, node, def, &init_def);
+ init_def.reg_init_def.id = def->id;
+ init_def.reg_init_def.ofw_node = node;
+ regnode = regnode_create(sc->dev, &as3722_regnode_class,
+ &init_def.reg_init_def);
+ if (regnode == NULL) {
+ device_printf(sc->dev, "Cannot create regulator.\n");
+ return (NULL);
+ }
+ reg_sc = regnode_get_softc(regnode);
+
+ /* Init regulator softc. */
+ reg_sc->regnode = regnode;
+ reg_sc->base_sc = sc;
+ reg_sc->def = def;
+ reg_sc->xref = OF_xref_from_node(node);
+
+ reg_sc->param = regnode_get_stdparam(regnode);
+ reg_sc->ext_control = init_def.ext_control;
+ reg_sc->enable_tracking = init_def.enable_tracking;
+
+ regnode_register(regnode);
+ if (bootverbose) {
+ int volt, rv;
+ regnode_topo_slock();
+ rv = regnode_get_voltage(regnode, &volt);
+ if (rv == ENODEV) {
+ device_printf(sc->dev,
+ " Regulator %s: parent doesn't exist yet.\n",
+ regnode_get_name(regnode));
+ } else if (rv != 0) {
+ device_printf(sc->dev,
+ " Regulator %s: voltage: INVALID!!!\n",
+ regnode_get_name(regnode));
+ } else {
+ device_printf(sc->dev,
+ " Regulator %s: voltage: %d uV\n",
+ regnode_get_name(regnode), volt);
+ }
+ regnode_topo_unlock();
+ }
+
+ return (reg_sc);
+}
+
+int
+as3722_regulator_attach(struct as3722_softc *sc, phandle_t node)
+{
+ struct as3722_reg_sc *reg;
+ phandle_t child, rnode;
+ int i;
+
+ rnode = ofw_bus_find_child(node, "regulators");
+ if (rnode <= 0) {
+ device_printf(sc->dev, " Cannot find regulators subnode\n");
+ return (ENXIO);
+ }
+
+ sc->nregs = nitems(as3722s_def);
+ sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs,
+ M_AS3722_REG, M_WAITOK | M_ZERO);
+
+
+ /* Attach all known regulators if exist in DT. */
+ for (i = 0; i < sc->nregs; i++) {
+ child = ofw_bus_find_child(rnode, as3722s_def[i].name);
+ if (child == 0) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "Regulator %s missing in DT\n",
+ as3722s_def[i].name);
+ continue;
+ }
+ reg = as3722_attach(sc, child, as3722s_def + i);
+ if (reg == NULL) {
+ device_printf(sc->dev, "Cannot attach regulator: %s\n",
+ as3722s_def[i].name);
+ return (ENXIO);
+ }
+ sc->regs[i] = reg;
+ }
+ return (0);
+}
+
+int
+as3722_regulator_map(device_t dev, phandle_t xref, int ncells,
+ pcell_t *cells, int *num)
+{
+ struct as3722_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+ for (i = 0; i < sc->nregs; i++) {
+ if (sc->regs[i] == NULL)
+ continue;
+ if (sc->regs[i]->xref == xref) {
+ *num = sc->regs[i]->def->id;
+ return (0);
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay)
+{
+ struct as3722_reg_sc *sc;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+
+ if (val)
+ rv = as3722_reg_enable(sc);
+ else
+ rv = as3722_reg_disable(sc);
+ *udelay = sc->enable_usec;
+ return (rv);
+}
+
+static int
+as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt,
+ int *udelay)
+{
+ struct as3722_reg_sc *sc;
+ uint8_t sel;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+
+ *udelay = 0;
+ rv = regulator_range_volt_to_sel(sc, min_uvolt, max_uvolt, &sel);
+ if (rv != 0)
+ return (rv);
+ rv = as3722_write_sel(sc, sel);
+ return (rv);
+
+}
+
+static int
+as3722_regnode_get_volt(struct regnode *regnode, int *uvolt)
+{
+ struct as3722_reg_sc *sc;
+ uint8_t sel;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+ rv = as3722_read_sel(sc, &sel);
+ if (rv != 0)
+ return (rv);
+
+ /* LDO6 have bypass. */
+ if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS)
+ return (ENOENT);
+ rv = regulator_range_sel_to_volt(sc, sel, uvolt);
+ return (rv);
+}
diff --git a/sys/arm/nvidia/as3722_rtc.c b/sys/arm/nvidia/as3722_rtc.c
new file mode 100644
index 0000000..8f13104
--- /dev/null
+++ b/sys/arm/nvidia/as3722_rtc.c
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+#include <sys/kernel.h>
+
+#include <dev/ofw/ofw_bus.h>
+
+#include "clock_if.h"
+#include "as3722.h"
+
+#define AS3722_RTC_START_YEAR 2000
+
+int
+as3722_rtc_gettime(device_t dev, struct timespec *ts)
+{
+ struct as3722_softc *sc;
+ struct clocktime ct;
+ uint8_t buf[6];
+ int rv;
+
+ sc = device_get_softc(dev);
+
+ rv = as3722_read_buf(sc, AS3722_RTC_SECOND, buf, 6);
+ if (rv != 0) {
+ device_printf(sc->dev, "Failed to read RTC data\n");
+ return (rv);
+ }
+ ct.nsec = 0;
+ ct.sec = bcd2bin(buf[0] & 0x7F);
+ ct.min = bcd2bin(buf[1] & 0x7F);
+ ct.hour = bcd2bin(buf[2] & 0x3F);
+ ct.day = bcd2bin(buf[3] & 0x3F);
+ ct.mon = bcd2bin(buf[4] & 0x1F);
+ ct.year = bcd2bin(buf[5] & 0x7F) + AS3722_RTC_START_YEAR;
+ ct.dow = -1;
+
+ return clock_ct_to_ts(&ct, ts);
+}
+
+int
+as3722_rtc_settime(device_t dev, struct timespec *ts)
+{
+ struct as3722_softc *sc;
+ struct clocktime ct;
+ uint8_t buf[6];
+ int rv;
+
+ sc = device_get_softc(dev);
+ clock_ts_to_ct(ts, &ct);
+
+ if (ct.year < AS3722_RTC_START_YEAR)
+ return (EINVAL);
+
+ buf[0] = bin2bcd(ct.sec);
+ buf[1] = bin2bcd(ct.min);
+ buf[2] = bin2bcd(ct.hour);
+ buf[3] = bin2bcd(ct.day);
+ buf[4] = bin2bcd(ct.mon);
+ buf[5] = bin2bcd(ct.year - AS3722_RTC_START_YEAR);
+
+ rv = as3722_write_buf(sc, AS3722_RTC_SECOND, buf, 6);
+ if (rv != 0) {
+ device_printf(sc->dev, "Failed to write RTC data\n");
+ return (rv);
+ }
+ return (0);
+}
+
+int
+as3722_rtc_attach(struct as3722_softc *sc, phandle_t node)
+{
+ int rv;
+
+ /* Enable RTC, set 24 hours mode and alarms */
+ rv = RM1(sc, AS3722_RTC_CONTROL,
+ AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN | AS3722_RTC_AM_PM_MODE,
+ AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN);
+ if (rv < 0) {
+ device_printf(sc->dev, "Failed to initialize RTC controller\n");
+ return (ENXIO);
+ }
+ clock_register(sc->dev, 1000000);
+
+ return (0);
+}
diff --git a/sys/arm/nvidia/tegra124/files.tegra124 b/sys/arm/nvidia/tegra124/files.tegra124
new file mode 100644
index 0000000..d4d38f7
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/files.tegra124
@@ -0,0 +1,57 @@
+# $FreeBSD$
+
+#
+# Standard ARM support.
+#
+kern/kern_clocksource.c standard
+dev/ofw/ofw_cpu.c optional fdt
+
+#
+# Standard tegra124 devices and support.
+#
+arm/nvidia/tegra124/tegra124_machdep.c standard
+arm/nvidia/tegra124/tegra124_mp.c optional smp
+arm/nvidia/tegra124/tegra124_car.c standard
+arm/nvidia/tegra124/tegra124_clk_pll.c standard
+arm/nvidia/tegra124/tegra124_clk_per.c standard
+arm/nvidia/tegra124/tegra124_clk_super.c standard
+arm/nvidia/tegra124/tegra124_xusbpadctl.c standard
+arm/nvidia/tegra124/tegra124_pmc.c standard
+arm/nvidia/tegra124/tegra124_cpufreq.c standard
+arm/nvidia/tegra124/tegra124_coretemp.c standard
+arm/nvidia/tegra_usbphy.c standard
+arm/nvidia/tegra_pinmux.c standard
+arm/nvidia/tegra_uart.c optional uart
+arm/nvidia/tegra_sdhci.c optional sdhci
+arm/nvidia/tegra_gpio.c optional gpio
+arm/nvidia/tegra_ehci.c optional ehci
+arm/nvidia/tegra_ahci.c optional ahci
+arm/nvidia/tegra_pcie.c optional pci
+arm/nvidia/tegra_i2c.c optional iic
+arm/nvidia/tegra_rtc.c standard
+arm/nvidia/tegra_abpmisc.c standard
+arm/nvidia/tegra_efuse.c standard
+arm/nvidia/tegra_soctherm_if.m standard
+arm/nvidia/tegra_soctherm.c standard
+arm/nvidia/tegra_lic.c standard
+#arm/nvidia/tegra_hda.c optional snd_hda
+#arm/nvidia/drm2/hdmi.c optional drm2
+#arm/nvidia/drm2/tegra_drm_if.m optional drm2
+#arm/nvidia/drm2/tegra_drm_subr.c optional drm2
+#arm/nvidia/drm2/tegra_host1x.c optional drm2
+#arm/nvidia/drm2/tegra_hdmi.c optional drm2
+#arm/nvidia/drm2/tegra_dc_if.m optional drm2
+#arm/nvidia/drm2/tegra_dc.c optional drm2
+#arm/nvidia/drm2/tegra_fb.c optional drm2
+#arm/nvidia/drm2/tegra_bo.c optional drm2
+#
+# Optional devices.
+#
+
+#
+# Temporary/ to be moved stuff
+#
+arm/nvidia/as3722.c optional iic
+arm/nvidia/as3722_regulators.c optional iic
+arm/nvidia/as3722_rtc.c optional iic
+arm/nvidia/as3722_gpio.c optional iic
diff --git a/sys/arm/nvidia/tegra124/std.tegra124 b/sys/arm/nvidia/tegra124/std.tegra124
new file mode 100644
index 0000000..127b001
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/std.tegra124
@@ -0,0 +1,14 @@
+# $FreeBSD$
+cpu CPU_CORTEXA
+machine arm armv6
+makeoptions CONF_CFLAGS="-march=armv7a"
+
+options KERNVIRTADDR = 0xc0200000
+makeoptions KERNVIRTADDR = 0xc0200000
+
+options ARM_INTRNG
+
+options IPI_IRQ_START=0
+options IPI_IRQ_END=15
+
+files "../nvidia/tegra124/files.tegra124"
diff --git a/sys/arm/nvidia/tegra124/tegra124_car.c b/sys/arm/nvidia/tegra124/tegra124_car.c
new file mode 100644
index 0000000..c0e93c7
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_car.c
@@ -0,0 +1,613 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/extres/clk/clk_div.h>
+#include <dev/extres/clk/clk_fixed.h>
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/extres/clk/clk_mux.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h>
+
+#include "clkdev_if.h"
+#include "hwreset_if.h"
+#include "tegra124_car.h"
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-car", 1},
+ {NULL, 0},
+};
+
+#define PLIST(x) static const char *x[]
+
+/* Pure multiplexer. */
+#define MUX(_id, cname, plists, o, s, w) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = plists, \
+ .clkdef.parent_cnt = nitems(plists), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .width = w, \
+}
+
+/* Fractional divider (7.1). */
+#define DIV7_1(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .i_shift = (s) + 1, \
+ .i_width = 7, \
+ .f_shift = s, \
+ .f_width = 1, \
+}
+
+/* Integer divider. */
+#define DIV(_id, cname, plist, o, s, w, f) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .i_shift = s, \
+ .i_width = w, \
+ .div_flags = f, \
+}
+
+/* Gate in PLL block. */
+#define GATE_PLL(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 3, \
+ .on_value = 3, \
+ .off_value = 0, \
+}
+
+/* Standard gate. */
+#define GATE(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 1, \
+ .on_value = 1, \
+ .off_value = 0, \
+}
+
+/* Inverted gate. */
+#define GATE_INV(_id, cname, plist, o, s) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .offset = o, \
+ .shift = s, \
+ .mask = 1, \
+ .on_value = 0, \
+ .off_value = 1, \
+}
+
+/* Fixed rate clock. */
+#define FRATE(_id, cname, _freq) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = NULL, \
+ .clkdef.parent_cnt = 0, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .freq = _freq, \
+}
+
+/* Fixed rate multipier/divider. */
+#define FACT(_id, cname, pname, _mult, _div) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .mult = _mult, \
+ .div = _div, \
+}
+
+static uint32_t osc_freqs[16] = {
+ [0] = 13000000,
+ [1] = 16800000,
+ [4] = 19200000,
+ [5] = 38400000,
+ [8] = 12000000,
+ [9] = 48000000,
+ [12] = 260000000,
+};
+
+
+/* Parent lists. */
+PLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */
+PLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"};
+PLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"};
+PLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"};
+PLIST(mux_pllmcp_clkm) = {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m",
+ "pllM_UD", "pllC2_out0", "pllC3_out0", "pllC_UD"};
+PLIST(mux_xusb_hs) = {"pc_xusb_ss", "pllU_60"};
+PLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"};
+
+
+/* Clocks ajusted online. */
+static struct clk_fixed_def fixed_clk_m =
+ FRATE(0, "clk_m", 12000000);
+static struct clk_fixed_def fixed_osc_div_clk =
+ FACT(0, "osc_div_clk", "clk_m", 1, 1);
+
+static struct clk_fixed_def tegra124_fixed_clks[] = {
+ /* Core clocks. */
+ FRATE(0, "clk_s", 32768),
+ FACT(0, "clk_m_div2", "clk_m", 1, 2),
+ FACT(0, "clk_m_div4", "clk_m", 1, 3),
+ FACT(0, "pllU_60", "pllU_out", 1, 8),
+ FACT(0, "pllU_48", "pllU_out", 1, 10),
+ FACT(0, "pllU_12", "pllU_out", 1, 40),
+ FACT(TEGRA124_CLK_PLL_D_OUT0, "pllD_out0", "pllD_out", 1, 2),
+ FACT(TEGRA124_CLK_PLL_D2_OUT0, "pllD2_out0", "pllD2_out", 1, 1),
+ FACT(0, "pllX_out0", "pllX_out", 1, 2),
+ FACT(0, "pllC_UD", "pllC_out0", 1, 1),
+ FACT(0, "pllM_UD", "pllM_out0", 1, 1),
+
+ /* Audio clocks. */
+ FRATE(0, "audio0", 10000000),
+ FRATE(0, "audio1", 10000000),
+ FRATE(0, "audio2", 10000000),
+ FRATE(0, "audio3", 10000000),
+ FRATE(0, "audio4", 10000000),
+ FRATE(0, "ext_vimclk", 10000000),
+};
+
+
+static struct clk_mux_def tegra124_mux_clks[] = {
+ /* Core clocks. */
+ MUX(0, "pllD2_src", mux_pll_srcs, PLLD2_BASE, 25, 2),
+ MUX(0, "pllDP_src", mux_pll_srcs, PLLDP_BASE, 25, 2),
+ MUX(0, "pllC4_src", mux_pll_srcs, PLLC4_BASE, 25, 2),
+ MUX(0, "pllE_src1", mux_plle_src1, PLLE_AUX, 2, 1),
+ MUX(0, "pllE_src", mux_plle_src, PLLE_AUX, 28, 1),
+
+ /* Base peripheral clocks. */
+ MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1),
+ MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1),
+ MUX(0, "emc_mux", mux_pllmcp_clkm, CLK_SOURCE_EMC, 29, 3),
+
+ /* USB. */
+ MUX(0, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1),
+ MUX(0, "xusb_ss_mux", mux_xusb_ss, CLK_SOURCE_XUSB_SS, 24, 1),
+
+};
+
+
+static struct clk_gate_def tegra124_gate_clks[] = {
+ /* Core clocks. */
+ GATE_PLL(0, "pllC_out1", "pllC_out1_div", PLLC_OUT, 0),
+ GATE_PLL(0, "pllM_out1", "pllM_out1_div", PLLM_OUT, 0),
+ GATE_PLL(0, "pllU_480", "pllU_out", PLLU_BASE, 22),
+ GATE_PLL(0, "pllP_outX0", "pllP_outX0_div", PLLP_RESHIFT, 0),
+ GATE_PLL(0, "pllP_out1", "pllP_out1_div", PLLP_OUTA, 0),
+ GATE_PLL(0, "pllP_out2", "pllP_out2_div", PLLP_OUTA, 16),
+ GATE_PLL(0, "pllP_out3", "pllP_out3_div", PLLP_OUTB, 0),
+ GATE_PLL(0, "pllP_out4", "pllP_out4_div", PLLP_OUTB, 16),
+ GATE_PLL(0, "pllP_out5", "pllP_out5_div", PLLP_OUTC, 16),
+ GATE_PLL(0, "pllA_out0", "pllA_out1_div", PLLA_OUT, 0),
+
+ /* Base peripheral clocks. */
+ GATE(TEGRA124_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0),
+ GATE(TEGRA124_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1),
+ GATE_INV(TEGRA124_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7),
+ GATE_INV(TEGRA124_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3),
+};
+
+static struct clk_div_def tegra124_div_clks[] = {
+ /* Core clocks. */
+ DIV7_1(0, "pllC_out1_div", "pllC_out0", PLLC_OUT, 2),
+ DIV7_1(0, "pllM_out1_div", "pllM_out0", PLLM_OUT, 8),
+ DIV7_1(0, "pllP_outX0_div", "pllP_out0", PLLP_RESHIFT, 2),
+ DIV7_1(0, "pllP_out1_div", "pllP_out0", PLLP_OUTA, 8),
+ DIV7_1(0, "pllP_out2_div", "pllP_out0", PLLP_OUTA, 24),
+ DIV7_1(0, "pllP_out3_div", "pllP_out0", PLLP_OUTB, 8),
+ DIV7_1(0, "pllP_out4_div", "pllP_out0", PLLP_OUTB, 24),
+ DIV7_1(0, "pllP_out5_div", "pllP_out0", PLLP_OUTC, 24),
+ DIV7_1(0, "pllA_out1_div", "pllA_out", PLLA_OUT, 8),
+
+ /* Base peripheral clocks. */
+ DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0),
+ DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0),
+};
+
+/* Initial setup table. */
+static struct tegra124_init_item clk_init_table[] = {
+ /* clock, partent, frequency, enable */
+ {"uarta", "pllP_out0", 408000000, 0},
+ {"uartb", "pllP_out0", 408000000, 0},
+ {"uartc", "pllP_out0", 408000000, 0},
+ {"uartd", "pllP_out0", 408000000, 0},
+ {"pllA_out", NULL, 282240000, 1},
+ {"pllA_out0", NULL, 11289600, 1},
+ {"extperiph1", "pllA_out0", 0, 1},
+ {"i2s0", "pllA_out0", 11289600, 0},
+ {"i2s1", "pllA_out0", 11289600, 0},
+ {"i2s2", "pllA_out0", 11289600, 0},
+ {"i2s3", "pllA_out0", 11289600, 0},
+ {"i2s4", "pllA_out0", 11289600, 0},
+ {"vde", "pllP_out0", 0, 0},
+ {"host1x", "pllP_out0", 136000000, 1},
+ {"sclk", "pllP_out2", 102000000, 1},
+ {"dvfs_soc", "pllP_out0", 51000000, 1},
+ {"dvfs_ref", "pllP_out0", 51000000, 1},
+ {"pllC_out0", NULL, 600000000, 0},
+ {"pllC_out1", NULL, 100000000, 0},
+ {"spi4", "pllP_out0", 12000000, 1},
+ {"tsec", "pllC3_out0", 0, 0},
+ {"msenc", "pllC3_out0", 0, 0},
+ {"pllREFE_out", NULL, 672000000, 0},
+ {"pc_xusb_ss", "pllU_480", 120000000, 0},
+ {"xusb_ss", "pc_xusb_ss", 120000000, 0},
+ {"pc_xusb_fs", "pllU_48", 48000000, 0},
+ {"xusb_hs", "pllU_60", 60000000, 0},
+ {"pc_xusb_falcon", "pllREFE_out", 224000000, 0},
+ {"xusb_core_host", "pllREFE_out", 112000000, 0},
+ {"sata", "pllP_out0", 102000000, 0},
+ {"sata_oob", "pllP_out0", 204000000, 0},
+ {"sata_cold", NULL, 0, 1},
+ {"emc", NULL, 0, 1},
+ {"mselect", NULL, 0, 1},
+ {"csite", NULL, 0, 1},
+ {"tsensor", "clk_m", 400000, 0},
+
+ /* tegra124 only*/
+ {"soc_therm", "pllP_out0", 51000000, 0},
+ {"cclk_g", NULL, 0, 1},
+ {"hda", "pllP_out0", 102000000, 0},
+ {"hda2codec_2x", "pllP_out0", 48000000, 0},
+};
+
+static void
+init_divs(struct tegra124_car_softc *sc, struct clk_div_def *clks, int nclks)
+{
+ int i, rv;
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_div_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clk_div_register failed");
+ }
+}
+
+static void
+init_gates(struct tegra124_car_softc *sc, struct clk_gate_def *clks, int nclks)
+{
+ int i, rv;
+
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_gate_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clk_gate_register failed");
+ }
+}
+
+static void
+init_muxes(struct tegra124_car_softc *sc, struct clk_mux_def *clks, int nclks)
+{
+ int i, rv;
+
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_mux_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clk_mux_register failed");
+ }
+}
+
+static void
+init_fixeds(struct tegra124_car_softc *sc, struct clk_fixed_def *clks,
+ int nclks)
+{
+ int i, rv;
+ uint32_t val;
+ int osc_idx;
+
+ CLKDEV_READ_4(sc->dev, OSC_CTRL, &val);
+ osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
+ fixed_clk_m.freq = osc_freqs[osc_idx];
+ if (fixed_clk_m.freq == 0)
+ panic("Undefined input frequency");
+ rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m);
+ if (rv != 0) panic("clk_fixed_register failed");
+
+ val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
+ fixed_osc_div_clk.div = 1 << val;
+ rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div_clk);
+ if (rv != 0) panic("clk_fixed_register failed");
+
+ for (i = 0; i < nclks; i++) {
+ rv = clknode_fixed_register(sc->clkdom, clks + i);
+ if (rv != 0)
+ panic("clk_fixed_register failed");
+ }
+}
+
+static void
+postinit_clock(struct tegra124_car_softc *sc)
+{
+ int i;
+ struct tegra124_init_item *tbl;
+ struct clknode *clknode;
+ int rv;
+
+ for (i = 0; i < nitems(clk_init_table); i++) {
+ tbl = &clk_init_table[i];
+
+ clknode = clknode_find_by_name(tbl->name);
+ if (clknode == NULL) {
+ device_printf(sc->dev, "Cannot find clock %s\n",
+ tbl->name);
+ continue;
+ }
+ if (tbl->parent != NULL) {
+ rv = clknode_set_parent_by_name(clknode, tbl->parent);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot set parent for %s (to %s): %d\n",
+ tbl->name, tbl->parent, rv);
+ continue;
+ }
+ }
+ if (tbl->frequency != 0) {
+ rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot set frequency for %s: %d\n",
+ tbl->name, rv);
+ continue;
+ }
+ }
+ if (tbl->enable!= 0) {
+ rv = clknode_enable(clknode);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable %s: %d\n", tbl->name, rv);
+ continue;
+ }
+ }
+ }
+}
+
+static void
+register_clocks(device_t dev)
+{
+ struct tegra124_car_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->clkdom = clkdom_create(dev);
+ if (sc->clkdom == NULL)
+ panic("clkdom == NULL");
+
+ tegra124_init_plls(sc);
+ init_fixeds(sc, tegra124_fixed_clks, nitems(tegra124_fixed_clks));
+ init_muxes(sc, tegra124_mux_clks, nitems(tegra124_mux_clks));
+ init_divs(sc, tegra124_div_clks, nitems(tegra124_div_clks));
+ init_gates(sc, tegra124_gate_clks, nitems(tegra124_gate_clks));
+ tegra124_periph_clock(sc);
+ tegra124_super_mux_clock(sc);
+ clkdom_finit(sc->clkdom);
+ clkdom_xlock(sc->clkdom);
+ postinit_clock(sc);
+ clkdom_unlock(sc->clkdom);
+ if (bootverbose)
+ clkdom_dump(sc->clkdom);
+}
+
+static int
+tegra124_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+{
+ struct tegra124_car_softc *sc;
+
+ sc = device_get_softc(dev);
+ *val = bus_read_4(sc->mem_res, addr);
+ return (0);
+}
+
+static int
+tegra124_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+{
+ struct tegra124_car_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_4(sc->mem_res, addr, val);
+ return (0);
+}
+
+static int
+tegra124_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
+ uint32_t set_mask)
+{
+ struct tegra124_car_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ reg = bus_read_4(sc->mem_res, addr);
+ reg &= ~clear_mask;
+ reg |= set_mask;
+ bus_write_4(sc->mem_res, addr, reg);
+ return (0);
+}
+
+static void
+tegra124_car_clkdev_device_lock(device_t dev)
+{
+ struct tegra124_car_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+}
+
+static void
+tegra124_car_clkdev_device_unlock(device_t dev)
+{
+ struct tegra124_car_softc *sc;
+
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
+
+static int
+tegra124_car_detach(device_t dev)
+{
+
+ device_printf(dev, "Error: Clock driver cannot be detached\n");
+ return (EBUSY);
+}
+
+static int
+tegra124_car_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Tegra Clock Driver");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+tegra124_car_attach(device_t dev)
+{
+ struct tegra124_car_softc *sc = device_get_softc(dev);
+ int rid, rv;
+
+ sc->dev = dev;
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+ sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+ /* Resource setup. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "cannot allocate memory resource\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ register_clocks(dev);
+ hwreset_register_ofw_provider(dev);
+ return (0);
+
+fail:
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (rv);
+}
+
+static int
+tegra124_car_hwreset_assert(device_t dev, intptr_t id, bool value)
+{
+ struct tegra124_car_softc *sc = device_get_softc(dev);
+
+ return (tegra124_hwreset_by_idx(sc, id, value));
+}
+
+static device_method_t tegra124_car_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra124_car_probe),
+ DEVMETHOD(device_attach, tegra124_car_attach),
+ DEVMETHOD(device_detach, tegra124_car_detach),
+
+ /* Clkdev interface*/
+ DEVMETHOD(clkdev_read_4, tegra124_car_clkdev_read_4),
+ DEVMETHOD(clkdev_write_4, tegra124_car_clkdev_write_4),
+ DEVMETHOD(clkdev_modify_4, tegra124_car_clkdev_modify_4),
+ DEVMETHOD(clkdev_device_lock, tegra124_car_clkdev_device_lock),
+ DEVMETHOD(clkdev_device_unlock, tegra124_car_clkdev_device_unlock),
+
+ /* Reset interface */
+ DEVMETHOD(hwreset_assert, tegra124_car_hwreset_assert),
+
+ DEVMETHOD_END
+};
+
+static devclass_t tegra124_car_devclass;
+
+static driver_t tegra124_car_driver = {
+ "tegra124_car",
+ tegra124_car_methods,
+ sizeof(struct tegra124_car_softc),
+};
+
+EARLY_DRIVER_MODULE(tegra124_car, simplebus, tegra124_car_driver,
+ tegra124_car_devclass, 0, 0, BUS_PASS_TIMER);
diff --git a/sys/arm/nvidia/tegra124/tegra124_car.h b/sys/arm/nvidia/tegra124/tegra124_car.h
new file mode 100644
index 0000000..b11742c
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_car.h
@@ -0,0 +1,337 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TEGRA124_CAR_
+#define _TEGRA124_CAR_
+
+#include "clkdev_if.h"
+
+#define RD4(sc, reg, val) CLKDEV_READ_4((sc)->clkdev, reg, val)
+#define WR4(sc, reg, val) CLKDEV_WRITE_4((sc)->clkdev, reg, val)
+#define MD4(sc, reg, mask, set) CLKDEV_MODIFY_4((sc)->clkdev, reg, mask, set)
+#define DEVICE_LOCK(sc) CLKDEV_DEVICE_LOCK((sc)->clkdev)
+#define DEVICE_UNLOCK(sc) CLKDEV_DEVICE_UNLOCK((sc)->clkdev)
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00C
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CCLK_BURST_POLICY 0x020
+#define SUPER_CCLK_DIVIDER 0x024
+#define SCLK_BURST_POLICY 0x028
+#define SUPER_SCLK_DIVIDER 0x02c
+#define CLK_SYSTEM_RATE 0x030
+
+#define OSC_CTRL 0x050
+ #define OSC_CTRL_OSC_FREQ_SHIFT 28
+ #define OSC_CTRL_PLL_REF_DIV_SHIFT 26
+
+#define PLLE_SS_CNTL 0x068
+#define PLLE_SS_CNTL_SSCINCINTRV_MASK (0x3f << 24)
+#define PLLE_SS_CNTL_SSCINCINTRV_VAL (0x20 << 24)
+#define PLLE_SS_CNTL_SSCINC_MASK (0xff << 16)
+#define PLLE_SS_CNTL_SSCINC_VAL (0x1 << 16)
+#define PLLE_SS_CNTL_SSCINVERT (1 << 15)
+#define PLLE_SS_CNTL_SSCCENTER (1 << 14)
+#define PLLE_SS_CNTL_SSCBYP (1 << 12)
+#define PLLE_SS_CNTL_INTERP_RESET (1 << 11)
+#define PLLE_SS_CNTL_BYPASS_SS (1 << 10)
+#define PLLE_SS_CNTL_SSCMAX_MASK 0x1ff
+#define PLLE_SS_CNTL_SSCMAX_VAL 0x25
+#define PLLE_SS_CNTL_DISABLE (PLLE_SS_CNTL_BYPASS_SS | \
+ PLLE_SS_CNTL_INTERP_RESET | \
+ PLLE_SS_CNTL_SSCBYP)
+#define PLLE_SS_CNTL_COEFFICIENTS_MASK (PLLE_SS_CNTL_SSCMAX_MASK | \
+ PLLE_SS_CNTL_SSCINC_MASK | \
+ PLLE_SS_CNTL_SSCINCINTRV_MASK)
+#define PLLE_SS_CNTL_COEFFICIENTS_VAL (PLLE_SS_CNTL_SSCMAX_VAL | \
+ PLLE_SS_CNTL_SSCINC_VAL | \
+ PLLE_SS_CNTL_SSCINCINTRV_VAL)
+
+#define PLLC_BASE 0x080
+#define PLLC_OUT 0x084
+#define PLLC_MISC2 0x088
+#define PLLC_MISC 0x08c
+#define PLLM_BASE 0x090
+#define PLLM_OUT 0x094
+#define PLLM_MISC 0x09c
+#define PLLP_BASE 0x0a0
+#define PLLP_MISC 0x0ac
+#define PLLP_OUTA 0x0a4
+#define PLLP_OUTB 0x0a8
+#define PLLA_BASE 0x0b0
+#define PLLA_OUT 0x0b4
+#define PLLA_MISC 0x0bc
+#define PLLU_BASE 0x0c0
+#define PLLU_MISC 0x0cc
+#define PLLD_BASE 0x0d0
+#define PLLD_MISC 0x0dc
+#define PLLX_BASE 0x0e0
+#define PLLX_MISC 0x0e4
+#define PLLE_BASE 0x0e8
+#define PLLE_BASE_LOCK_OVERRIDE (1 << 29)
+#define PLLE_BASE_DIVCML_SHIFT 24
+#define PLLE_BASE_DIVCML_MASK 0xf
+
+#define PLLE_MISC 0x0ec
+#define PLLE_MISC_SETUP_BASE_SHIFT 16
+#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_READY (1 << 15)
+#define PLLE_MISC_IDDQ_SWCTL (1 << 14)
+#define PLLE_MISC_IDDQ_OVERRIDE_VALUE (1 << 13)
+#define PLLE_MISC_LOCK (1 << 11)
+#define PLLE_MISC_REF_ENABLE (1 << 10)
+#define PLLE_MISC_LOCK_ENABLE (1 << 9)
+#define PLLE_MISC_PTS (1 << 8)
+#define PLLE_MISC_VREG_BG_CTRL_SHIFT 4
+#define PLLE_MISC_VREG_BG_CTRL_MASK (3 << PLLE_MISC_VREG_BG_CTRL_SHIFT)
+#define PLLE_MISC_VREG_CTRL_SHIFT 2
+#define PLLE_MISC_VREG_CTRL_MASK (2 << PLLE_MISC_VREG_CTRL_SHIFT)
+
+#define CLK_SOURCE_I2S1 0x100
+#define CLK_SOURCE_I2S2 0x104
+#define CLK_SOURCE_SPDIF_OUT 0x108
+#define CLK_SOURCE_SPDIF_IN 0x10c
+#define CLK_SOURCE_PWM 0x110
+#define CLK_SOURCE_SPI2 0x118
+#define CLK_SOURCE_SPI3 0x11c
+#define CLK_SOURCE_I2C1 0x124
+#define CLK_SOURCE_I2C5 0x128
+#define CLK_SOURCE_SPI1 0x134
+#define CLK_SOURCE_DISP1 0x138
+#define CLK_SOURCE_DISP2 0x13c
+#define CLK_SOURCE_ISP 0x144
+#define CLK_SOURCE_VI 0x148
+#define CLK_SOURCE_SDMMC1 0x150
+#define CLK_SOURCE_SDMMC2 0x154
+#define CLK_SOURCE_SDMMC4 0x164
+#define CLK_SOURCE_VFIR 0x168
+#define CLK_SOURCE_HSI 0x174
+#define CLK_SOURCE_UARTA 0x178
+#define CLK_SOURCE_UARTB 0x17c
+#define CLK_SOURCE_HOST1X 0x180
+#define CLK_SOURCE_HDMI 0x18c
+#define CLK_SOURCE_I2C2 0x198
+#define CLK_SOURCE_EMC 0x19c
+#define CLK_SOURCE_UARTC 0x1a0
+#define CLK_SOURCE_VI_SENSOR 0x1a8
+#define CLK_SOURCE_SPI4 0x1b4
+#define CLK_SOURCE_I2C3 0x1b8
+#define CLK_SOURCE_SDMMC3 0x1bc
+#define CLK_SOURCE_UARTD 0x1c0
+#define CLK_SOURCE_VDE 0x1c8
+#define CLK_SOURCE_OWR 0x1cc
+#define CLK_SOURCE_NOR 0x1d0
+#define CLK_SOURCE_CSITE 0x1d4
+#define CLK_SOURCE_I2S0 0x1d8
+#define CLK_SOURCE_DTV 0x1dc
+#define CLK_SOURCE_MSENC 0x1f0
+#define CLK_SOURCE_TSEC 0x1f4
+#define CLK_SOURCE_SPARE2 0x1f8
+
+#define CLK_OUT_ENB_X 0x280
+#define RST_DEVICES_X 0x28C
+
+#define RST_DEVICES_V 0x358
+#define RST_DEVICES_W 0x35C
+#define CLK_OUT_ENB_V 0x360
+#define CLK_OUT_ENB_W 0x364
+#define CCLKG_BURST_POLICY 0x368
+#define SUPER_CCLKG_DIVIDER 0x36C
+#define CCLKLP_BURST_POLICY 0x370
+#define SUPER_CCLKLP_DIVIDER 0x374
+
+#define CLK_SOURCE_MSELECT 0x3b4
+#define CLK_SOURCE_TSENSOR 0x3b8
+#define CLK_SOURCE_I2S3 0x3bc
+#define CLK_SOURCE_I2S4 0x3c0
+#define CLK_SOURCE_I2C4 0x3c4
+#define CLK_SOURCE_SPI5 0x3c8
+#define CLK_SOURCE_SPI6 0x3cc
+#define CLK_SOURCE_AUDIO 0x3d0
+#define CLK_SOURCE_DAM0 0x3d8
+#define CLK_SOURCE_DAM1 0x3dc
+#define CLK_SOURCE_DAM2 0x3e0
+#define CLK_SOURCE_HDA2CODEC_2X 0x3e4
+#define CLK_SOURCE_ACTMON 0x3e8
+#define CLK_SOURCE_EXTPERIPH1 0x3ec
+#define CLK_SOURCE_EXTPERIPH2 0x3f0
+#define CLK_SOURCE_EXTPERIPH3 0x3f4
+#define CLK_SOURCE_I2C_SLOW 0x3fc
+
+#define CLK_SOURCE_SYS 0x400
+#define CLK_SOURCE_SOR0 0x414
+#define CLK_SOURCE_SATA_OOB 0x420
+#define CLK_SOURCE_SATA 0x424
+#define CLK_SOURCE_HDA 0x428
+#define UTMIP_PLL_CFG0 0x480
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP (1 << 17)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN (1 << 16)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP (1 << 15)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN (1 << 14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN (1 << 12)
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN (1 << 4)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN (1 << 2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN (1 << 0)
+
+#define PLLE_AUX 0x48c
+#define PLLE_AUX_PLLRE_SEL (1 << 28)
+#define PLLE_AUX_SEQ_START_STATE (1 << 25)
+#define PLLE_AUX_SEQ_ENABLE (1 << 24)
+#define PLLE_AUX_SS_SWCTL (1 << 6)
+#define PLLE_AUX_ENABLE_SWCTL (1 << 4)
+#define PLLE_AUX_USE_LOCKDET (1 << 3)
+#define PLLE_AUX_PLLP_SEL (1 << 2)
+
+#define SATA_PLL_CFG0 0x490
+#define SATA_PLL_CFG0_SEQ_START_STATE (1 << 25)
+#define SATA_PLL_CFG0_SEQ_ENABLE (1 << 24)
+#define SATA_PLL_CFG0_SEQ_PADPLL_PD_INPUT_VALUE (1 << 7)
+#define SATA_PLL_CFG0_SEQ_LANE_PD_INPUT_VALUE (1 << 6)
+#define SATA_PLL_CFG0_SEQ_RESET_INPUT_VALUE (1 << 5)
+#define SATA_PLL_CFG0_SEQ_IN_SWCTL (1 << 4)
+#define SATA_PLL_CFG0_PADPLL_USE_LOCKDET (1 << 2)
+#define SATA_PLL_CFG0_PADPLL_RESET_OVERRIDE_VALUE (1 << 1)
+#define SATA_PLL_CFG0_PADPLL_RESET_SWCTL (1 << 0)
+
+#define SATA_PLL_CFG1 0x494
+#define PCIE_PLL_CFG0 0x498
+#define PCIE_PLL_CFG0_SEQ_START_STATE (1 << 25)
+#define PCIE_PLL_CFG0_SEQ_ENABLE (1 << 24)
+
+#define PLLD2_BASE 0x4b8
+#define PLLD2_MISC 0x4bc
+#define UTMIP_PLL_CFG3 0x4c0
+#define PLLRE_BASE 0x4c4
+#define PLLRE_MISC 0x4c8
+#define PLLC2_BASE 0x4e8
+#define PLLC2_MISC 0x4ec
+#define PLLC3_BASE 0x4fc
+
+#define PLLC3_MISC 0x500
+#define PLLX_MISC2 0x514
+#define PLLX_MISC2 0x514
+#define PLLX_MISC3 0x518
+#define PLLX_MISC3_DYNRAMP_STEPB_MASK 0xFF
+#define PLLX_MISC3_DYNRAMP_STEPB_SHIFT 24
+#define PLLX_MISC3_DYNRAMP_STEPA_MASK 0xFF
+#define PLLX_MISC3_DYNRAMP_STEPA_SHIFT 16
+#define PLLX_MISC3_NDIV_NEW_MASK 0xFF
+#define PLLX_MISC3_NDIV_NEW_SHIFT 8
+#define PLLX_MISC3_EN_FSTLCK (1 << 5)
+#define PLLX_MISC3_LOCK_OVERRIDE (1 << 4)
+#define PLLX_MISC3_PLL_FREQLOCK (1 << 3)
+#define PLLX_MISC3_DYNRAMP_DONE (1 << 2)
+#define PLLX_MISC3_CLAMP_NDIV (1 << 1)
+#define PLLX_MISC3_EN_DYNRAMP (1 << 0)
+#define XUSBIO_PLL_CFG0 0x51c
+#define XUSBIO_PLL_CFG0_SEQ_START_STATE (1 << 25)
+#define XUSBIO_PLL_CFG0_SEQ_ENABLE (1 << 24)
+#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET (1 << 6)
+#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL (1 << 2)
+#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL (1 << 0)
+
+#define PLLP_RESHIFT 0x528
+#define UTMIPLL_HW_PWRDN_CFG0 0x52c
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE (1 << 25)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE (1 << 24)
+#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET (1 << 6)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE (1 << 5)
+#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL (1 << 4)
+#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL (1 << 2)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE (1 << 1)
+#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL (1 << 0)
+
+#define PLLDP_BASE 0x590
+#define PLLDP_MISC 0x594
+#define PLLC4_BASE 0x5a4
+#define PLLC4_MISC 0x5a8
+
+#define CLK_SOURCE_XUSB_CORE_HOST 0x600
+#define CLK_SOURCE_XUSB_FALCON 0x604
+#define CLK_SOURCE_XUSB_FS 0x608
+#define CLK_SOURCE_XUSB_CORE_DEV 0x60c
+#define CLK_SOURCE_XUSB_SS 0x610
+#define CLK_SOURCE_CILAB 0x614
+#define CLK_SOURCE_CILCD 0x618
+#define CLK_SOURCE_CILE 0x61c
+#define CLK_SOURCE_DSIA_LP 0x620
+#define CLK_SOURCE_DSIB_LP 0x624
+#define CLK_SOURCE_ENTROPY 0x628
+#define CLK_SOURCE_DVFS_REF 0x62c
+#define CLK_SOURCE_DVFS_SOC 0x630
+#define CLK_SOURCE_TRACECLKIN 0x634
+#define CLK_SOURCE_ADX 0x638
+#define CLK_SOURCE_AMX 0x63c
+#define CLK_SOURCE_EMC_LATENCY 0x640
+#define CLK_SOURCE_SOC_THERM 0x644
+#define CLK_SOURCE_VI_SENSOR2 0x658
+#define CLK_SOURCE_I2C6 0x65c
+#define CLK_SOURCE_EMC_DLL 0x664
+#define CLK_SOURCE_HDMI_AUDIO 0x668
+#define CLK_SOURCE_CLK72MHZ 0x66c
+#define CLK_SOURCE_ADX1 0x670
+#define CLK_SOURCE_AMX1 0x674
+#define CLK_SOURCE_VIC 0x678
+#define PLLP_OUTC 0x67c
+#define PLLP_MISC1 0x680
+
+
+struct tegra124_car_softc {
+ device_t dev;
+ struct resource * mem_res;
+ struct mtx mtx;
+ struct clkdom *clkdom;
+ int type;
+};
+
+struct tegra124_init_item {
+ char *name;
+ char *parent;
+ uint64_t frequency;
+ int enable;
+};
+
+void tegra124_init_plls(struct tegra124_car_softc *sc);
+
+void tegra124_periph_clock(struct tegra124_car_softc *sc);
+void tegra124_super_mux_clock(struct tegra124_car_softc *sc);
+
+int tegra124_hwreset_by_idx(struct tegra124_car_softc *sc, intptr_t idx,
+ bool reset);
+
+#endif /*_TEGRA124_CAR_*/ \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra124/tegra124_clk_per.c b/sys/arm/nvidia/tegra124/tegra124_clk_per.c
new file mode 100644
index 0000000..65ae5d9
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_clk_per.c
@@ -0,0 +1,810 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h>
+#include "tegra124_car.h"
+
+/* Bits in base register. */
+#define PERLCK_AMUX_MASK 0x0F
+#define PERLCK_AMUX_SHIFT 16
+#define PERLCK_AMUX_DIS (1 << 20)
+#define PERLCK_UDIV_DIS (1 << 24)
+#define PERLCK_ENA_MASK (1 << 28)
+#define PERLCK_MUX_SHIFT 29
+#define PERLCK_MUX_MASK 0x07
+
+
+struct periph_def {
+ struct clknode_init_def clkdef;
+ uint32_t base_reg;
+ uint32_t div_width;
+ uint32_t div_mask;
+ uint32_t div_f_width;
+ uint32_t div_f_mask;
+ uint32_t flags;
+};
+
+struct pgate_def {
+ struct clknode_init_def clkdef;
+ uint32_t idx;
+ uint32_t flags;
+};
+#define PLIST(x) static const char *x[]
+
+#define GATE(_id, cname, plist, _idx) \
+{ \
+ .clkdef.id = TEGRA124_CLK_##_id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){plist}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .idx = _idx, \
+ .flags = 0, \
+}
+
+/* Sources for multiplexors. */
+PLIST(mux_a_N_audio_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_N_audio0_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio0", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_N_audio1_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio1", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_N_audio2_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio2", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_N_audio3_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio3", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_N_audio4_N_p_N_clkm) =
+ {"pllA_out0", NULL, "audio4", NULL,
+ "pllP_out0", NULL, "clk_m"};
+PLIST(mux_a_clks_p_clkm_e) =
+ {"pllA_out0", "clk_s", "pllP_out0",
+ "clk_m", "pllE_out0"};
+PLIST(mux_a_c2_c_c3_p_N_clkm) =
+ {"pllA_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllP_out0", NULL, "clk_m"};
+
+PLIST(mux_m_c_p_a_c2_c3) =
+ {"pllM_out0", "pllC_out0", "pllP_out0", "pllA_out0",
+ "pllC2_out0", "pllC3_out0"};
+PLIST(mux_m_c_p_a_c2_c3_clkm) =
+ {"pllM_out0", "pllC_out0", "pllP_out0", "pllA_out0",
+ "pllC2_out0", "pllC3_out0", "clk_m"};
+PLIST(mux_m_c_p_a_c2_c3_clkm_c4) =
+ {"pllM_out0", "pllC_out0", "pllP_out0", "pllA_out0",
+ "pllC2_out0", "pllC3_out0", "clk_m", "pllC4_out0"};
+PLIST(mux_m_c_p_clkm_mud_c2_c3) =
+ {"pllM_out0", "pllC_out0", "pllP_out0", "clk_m",
+ "pllM_UD", "pllC2_out0", "pllC3_out0"};
+PLIST(mux_m_c2_c_c3_p_N_a) =
+ {"pllM_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllP_out0", NULL, "pllA_out0"};
+PLIST(mux_m_c2_c_c3_p_N_a_c4) =
+ {"pllM_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ NULL, "pllA_out0", "pllC4_out0"};
+
+PLIST(mux_p_N_c_N_N_N_clkm) =
+ {"pllP_out0", NULL, "pllC_out0", NULL,
+ NULL, NULL, "clk_m"};
+PLIST(mux_p_N_c_N_m_N_clkm) =
+ {"pllP_out0", NULL, "pllC_out0", NULL,
+ "pllM_out0", NULL, "clk_m"};
+PLIST(mux_p_c_c2_clkm) =
+ {"pllP_out0", "pllC_out0", "pllC2_out0", "clk_m"};
+PLIST(mux_p_c2_c_c3_m) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllM_out0"};
+PLIST(mux_p_c2_c_c3_m_N_clkm) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllM_out0", NULL, "clk_m"};
+PLIST(mux_p_c2_c_c3_m_e_clkm) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllM_out0", "pllE_out0", "clk_m"};
+PLIST(mux_p_c2_c_c3_m_a_clkm) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllM_out0", "pllA_out0", "clk_m"};
+PLIST(mux_p_c2_c_c3_m_clks_clkm) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllM_out0", "clk_s", "clk_m"};
+PLIST(mux_p_c2_c_c3_clks_N_clkm) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "clk_s", NULL, "clk_m"};
+PLIST(mux_p_c2_c_c3_clkm_N_clks) =
+ {"pllP_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "clk_m", NULL, "clk_s"};
+PLIST(mux_p_clkm_clks_E) =
+ {"pllP_out0", "clk_m", "clk_s", "pllE_out0"};
+PLIST(mux_p_m_d_a_c_d2_clkm) =
+ {"pllP_out0", "pllM_out0", "pllD_out0", "pllA_out0",
+ "pllC_out0", "pllD2_out0", "clk_m"};
+
+PLIST(mux_clkm_N_u48_N_p_N_u480) =
+ {"clk_m", NULL, "pllU_48", NULL,
+ "pllP_out0", NULL, "pllU_480"};
+PLIST(mux_clkm_p_c2_c_c3_refre) =
+ {"clk_m", "pllP_out0", "pllC2_out0", "pllC_out0",
+ "pllC3_out0", "pllREFE_out"};
+PLIST(mux_clkm_refe_clks_u480_c_c2_c3_oscdiv) =
+ {"clk_m", "pllREFE_out", "clk_s", "pllU_480",
+ "pllC_out0", "pllC2_out0", "pllC3_out0", "osc_div_clk"};
+
+PLIST(mux_sep_audio) =
+ {"pllA_out0", "pllC2_out0", "pllC_out0", "pllC3_out0",
+ "pllP_out0", NULL, "clk_m", NULL,
+ "spdif_in", "i2s0", "i2s1", "i2s2",
+ "i2s4", "pllA_out0", "ext_vimclk"};
+
+static uint32_t clk_enabale_reg[] = {
+ CLK_OUT_ENB_L,
+ CLK_OUT_ENB_H,
+ CLK_OUT_ENB_U,
+ CLK_OUT_ENB_V,
+ CLK_OUT_ENB_W,
+ CLK_OUT_ENB_X,
+};
+
+static uint32_t clk_reset_reg[] = {
+ RST_DEVICES_L,
+ RST_DEVICES_H,
+ RST_DEVICES_U,
+ RST_DEVICES_V,
+ RST_DEVICES_W,
+ RST_DEVICES_X,
+};
+
+#define L(n) ((0 * 32) + (n))
+#define H(n) ((1 * 32) + (n))
+#define U(n) ((2 * 32) + (n))
+#define V(n) ((3 * 32) + (n))
+#define W(n) ((4 * 32) + (n))
+#define X(n) ((5 * 32) + (n))
+
+static struct pgate_def pgate_def[] = {
+ /* bank L -> 0-31 */
+ /* GATE(CPU, "cpu", "clk_m", L(0)), */
+ GATE(ISPB, "ispb", "clk_m", L(3)),
+ GATE(RTC, "rtc", "clk_s", L(4)),
+ GATE(TIMER, "timer", "clk_m", L(5)),
+ GATE(UARTA, "uarta", "pc_uarta" , L(6)),
+ GATE(UARTB, "uartb", "pc_uartb", L(7)),
+ GATE(VFIR, "vfir", "pc_vfir", L(7)),
+ /* GATE(GPIO, "gpio", "clk_m", L(8)), */
+ GATE(SDMMC2, "sdmmc2", "pc_sdmmc2", L(9)),
+ GATE(SPDIF_OUT, "spdif_out", "pc_spdif_out", L(10)),
+ GATE(SPDIF_IN, "spdif_in", "pc_spdif_in", L(10)),
+ GATE(I2S1, "i2s1", "pc_i2s1", L(11)),
+ GATE(I2C1, "i2c1", "pc_i2c1", L(12)),
+ GATE(SDMMC1, "sdmmc1", "pc_sdmmc1", L(14)),
+ GATE(SDMMC4, "sdmmc4", "pc_sdmmc4", L(15)),
+ GATE(PWM, "pwm", "pc_pwm", L(17)),
+ GATE(I2S2, "i2s2", "pc_i2s2", L(18)),
+ GATE(VI, "vi", "pc_vi", L(20)),
+ GATE(USBD, "usbd", "clk_m", L(22)),
+ GATE(ISP, "isp", "pc_isp", L(23)),
+ GATE(DISP2, "disp2", "pc_disp2", L(26)),
+ GATE(DISP1, "disp1", "pc_disp1", L(27)),
+ GATE(HOST1X, "host1x", "pc_host1x", L(28)),
+ GATE(VCP, "vcp", "clk_m", L(29)),
+ GATE(I2S0, "i2s0", "pc_i2s0", L(30)),
+ /* GATE(CACHE2, "ccache2", "clk_m", L(31)), */
+
+ /* bank H -> 32-63 */
+ GATE(MC, "mem", "clk_m", H(0)),
+ /* GATE(AHBDMA, "ahbdma", "clk_m", H(1)), */
+ GATE(APBDMA, "apbdma", "clk_m", H(2)),
+ GATE(KBC, "kbc", "clk_s", H(4)),
+ /* GATE(STAT_MON, "stat_mon", "clk_s", H(5)), */
+ /* GATE(PMC, "pmc", "clk_s", H(6)), */
+ GATE(FUSE, "fuse", "clk_m", H(7)),
+ GATE(KFUSE, "kfuse", "clk_m", H(8)),
+ GATE(SBC1, "spi1", "pc_spi1", H(9)),
+ GATE(NOR, "snor", "pc_snor", H(10)),
+ /* GATE(JTAG2TBC, "jtag2tbc", "clk_m", H(11)), */
+ GATE(SBC2, "spi2", "pc_spi2", H(12)),
+ GATE(SBC3, "spi3", "pc_spi3", H(14)),
+ GATE(I2C5, "i2c5", "pc_i2c5", H(15)),
+ GATE(DSIA, "dsia", "dsia_mux", H(16)),
+ GATE(MIPI, "hsi", "pc_hsi", H(18)),
+ GATE(HDMI, "hdmi", "pc_hdmi", H(19)),
+ GATE(CSI, "csi", "pllP_out3", H(20)),
+ GATE(I2C2, "i2c2", "pc_i2c2", H(22)),
+ GATE(UARTC, "uartc", "pc_uartc", H(23)),
+ GATE(MIPI_CAL, "mipi_cal", "clk_m", H(24)),
+ GATE(EMC, "emc", "emc_mux", H(25)),
+ GATE(USB2, "usb2", "clk_m", H(26)),
+ GATE(USB3, "usb3", "clk_m", H(27)),
+ GATE(VDE, "vde", "pc_vde", H(29)),
+ GATE(BSEA, "bsea", "clk_m", H(30)),
+ GATE(BSEV, "bsev", "clk_m", H(31)),
+
+ /* bank U -> 64-95 */
+ GATE(UARTD, "uartd", "pc_uartd", U(1)),
+ GATE(I2C3, "i2c3", "pc_i2c3", U(3)),
+ GATE(SBC4, "spi4", "pc_spi4", U(4)),
+ GATE(SDMMC3, "sdmmc3", "pc_sdmmc3", U(5)),
+ GATE(PCIE, "pcie", "clk_m", U(6)),
+ GATE(OWR, "owr", "pc_owr", U(7)),
+ GATE(AFI, "afi", "clk_m", U(8)),
+ GATE(CSITE, "csite", "pc_csite", U(9)),
+ /* GATE(AVPUCQ, "avpucq", clk_m, U(11)), */
+ GATE(TRACE, "traceclkin", "pc_traceclkin", U(13)),
+ GATE(SOC_THERM, "soc_therm", "pc_soc_therm", U(14)),
+ GATE(DTV, "dtv", "clk_m", U(15)),
+ GATE(I2CSLOW, "i2c_slow", "pc_i2c_slow", U(17)),
+ GATE(DSIB, "dsib", "dsib_mux", U(18)),
+ GATE(TSEC, "tsec", "pc_tsec", U(19)),
+ /* GATE(IRAMA, "irama", "clk_m", U(20)), */
+ /* GATE(IRAMB, "iramb", "clk_m", U(21)), */
+ /* GATE(IRAMC, "iramc", "clk_m", U(22)), */
+ /* GATE(IRAMD, "iramd", "clk_m", U(23)), */
+ /* GATE(CRAM2, "cram2", "clk_m", U(24)), */
+ GATE(XUSB_HOST, "xusb_core_host", "pc_xusb_core_host", U(25)),
+ /* GATE(M_DOUBLER, "m_doubler", "clk_m", U(26)), */
+ GATE(MSENC, "msenc", "pc_msenc", U(27)),
+ GATE(CSUS, "sus_out", "clk_m", U(28)),
+ /* GATE(DEVD2_OUT, "devd2_out", "clk_m", U(29)), */
+ /* GATE(DEVD1_OUT, "devd1_out", "clk_m", U(30)), */
+ GATE(XUSB_DEV_SRC, "xusb_core_dev", "pc_xusb_core_dev", U(31)),
+
+ /* bank V -> 96-127 */
+ /* GATE(CPUG, "cpug", "clk_m", V(0)), */
+ /* GATE(CPULP, "cpuLP", "clk_m", V(1)), */
+ GATE(MSELECT, "mselect", "pc_mselect", V(3)),
+ GATE(TSENSOR, "tsensor", "pc_tsensor", V(4)),
+ GATE(I2S3, "i2s3", "pc_i2s3", V(5)),
+ GATE(I2S4, "i2s4", "pc_i2s4", V(6)),
+ GATE(I2C4, "i2c4", "pc_i2c4", V(7)),
+ GATE(SBC5, "spi5", "pc_spi5", V(8)),
+ GATE(SBC6, "spi6", "pc_spi6", V(9)),
+ GATE(D_AUDIO, "audio", "pc_audio", V(10)),
+ GATE(APBIF, "apbif", "clk_m", V(11)),
+ GATE(DAM0, "dam0", "pc_dam0", V(12)),
+ GATE(DAM1, "dam1", "pc_dam1", V(13)),
+ GATE(DAM2, "dam2", "pc_dam2", V(14)),
+ GATE(HDA2CODEC_2X, "hda2codec_2x", "pc_hda2codec_2x", V(15)),
+ /* GATE(ATOMICS, "atomics", "clk_m", V(16)), */
+ /* GATE(SPDIF_DOUBLER, "spdif_doubler", "clk_m", V(22)), */
+ GATE(ACTMON, "actmon", "pc_actmon", V(23)),
+ GATE(EXTERN1, "extperiph1", "pc_extperiph1", V(24)),
+ GATE(EXTERN2, "extperiph2", "pc_extperiph2", V(25)),
+ GATE(EXTERN3, "extperiph3", "pc_extperiph3", V(26)),
+ GATE(SATA_OOB, "sata_oob", "pc_sata_oob", V(27)),
+ GATE(SATA, "sata", "pc_sata", V(28)),
+ GATE(HDA, "hda", "pc_hda", V(29)),
+
+ /* bank W -> 128-159*/
+ GATE(HDA2HDMI, "hda2hdmi", "clk_m", W(0)),
+ GATE(SATA_COLD, "sata_cold", "clk_m", W(1)), /* Reset only */
+ /* GATE(PCIERX0, "pcierx0", "clk_m", W(2)), */
+ /* GATE(PCIERX1, "pcierx1", "clk_m", W(3)), */
+ /* GATE(PCIERX2, "pcierx2", "clk_m", W(4)), */
+ /* GATE(PCIERX3, "pcierx3", "clk_m", W(5)), */
+ /* GATE(PCIERX4, "pcierx4", "clk_m", W(6)), */
+ /* GATE(PCIERX5, "pcierx5", "clk_m", W(7)), */
+ /* GATE(CEC, "cec", "clk_m", W(8)), */
+ /* GATE(PCIE2_IOBIST, "pcie2_iobist", "clk_m", W(9)), */
+ /* GATE(EMC_IOBIST, "emc_iobist", "clk_m", W(10)), */
+ /* GATE(HDMI_IOBIST, "hdmi_iobist", "clk_m", W(11)), */
+ /* GATE(SATA_IOBIST, "sata_iobist", "clk_m", W(12)), */
+ /* GATE(MIPI_IOBIST, "mipi_iobist", "clk_m", W(13)), */
+ /* GATE(XUSB_IOBIST, "xusb_iobist", "clk_m", W(15)), */
+ GATE(CILAB, "cilab", "pc_cilab", W(16)),
+ GATE(CILCD, "cilcd", "pc_cilcd", W(17)),
+ GATE(CILE, "cile", "pc_cile", W(18)),
+ GATE(DSIALP, "dsia_lp", "pc_dsia_lp", W(19)),
+ GATE(DSIBLP, "dsib_lp", "pc_dsib_lp", W(20)),
+ GATE(ENTROPY, "entropy", "pc_entropy", W(21)),
+ GATE(AMX, "amx", "pc_amx", W(25)),
+ GATE(ADX, "adx", "pc_adx", W(26)),
+ GATE(DFLL_REF, "dvfs_ref", "pc_dvfs_ref", X(27)),
+ GATE(DFLL_SOC, "dvfs_soc", "pc_dvfs_soc", X(27)),
+ GATE(XUSB_SS_SRC, "xusb_ss", "xusb_ss_mux", X(28)),
+ /* GATE(EMC_LATENCY, "emc_latency", "pc_emc_latency", X(29)), */
+
+ /* bank X -> 160-191*/
+ /* GATE(SPARE, "spare", "clk_m", X(0)), */
+ /* GATE(CAM_MCLK, "CAM_MCLK", "clk_m", X(4)), */
+ /* GATE(CAM_MCLK2, "CAM_MCLK2", "clk_m", X(5)), */
+ GATE(I2C6, "i2c6", "pc_i2c6", X(6)),
+ /* GATE(VIM2_CLK, "vim2_clk", clk_m, X(11)), */
+ /* GATE(EMC_DLL, "emc_dll", "pc_emc_dll", X(14)), */
+ GATE(HDMI_AUDIO, "hdmi_audio", "pc_hdmi_audio", X(16)),
+ GATE(CLK72MHZ, "clk72mhz", "pc_clk72mhz", X(17)),
+ GATE(VIC03, "vic", "pc_vic", X(18)),
+ GATE(ADX1, "adx1", "pc_adx1", X(20)),
+ GATE(DPAUX, "dpaux", "clk_m", X(21)),
+ GATE(SOR0_LVDS, "sor0", "pc_sor0", X(22)),
+ GATE(GPU, "gpu", "osc_div_clk", X(24)),
+ GATE(AMX1, "amx1", "pc_amx1", X(26)),
+};
+
+/* Peripheral clock clock */
+#define DCF_HAVE_MUX 0x0100 /* Block with multipexor */
+#define DCF_HAVE_ENA 0x0200 /* Block with enable bit */
+#define DCF_HAVE_DIV 0x0400 /* Block with divider */
+
+/* Mark block with additional bis / functionality. */
+#define DCF_IS_MASK 0x00FF
+#define DCF_IS_UART 0x0001
+#define DCF_IS_VI 0x0002
+#define DCF_IS_HOST1X 0x0003
+#define DCF_IS_XUSB_SS 0x0004
+#define DCF_IS_EMC_DLL 0x0005
+#define FDS_IS_SATA 0x0006
+#define DCF_IS_VIC 0x0007
+#define DCF_IS_AUDIO 0x0008
+#define DCF_IS_SOR0 0x0009
+
+/* Basic pheripheral clock */
+#define PER_CLK(_id, cn, pl, r, diw, fiw, f) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cn, \
+ .clkdef.parent_names = pl, \
+ .clkdef.parent_cnt = nitems(pl), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .base_reg = r, \
+ .div_width = diw, \
+ .div_f_width = fiw, \
+ .flags = f, \
+}
+
+/* Mux with fractional 8.1 divider. */
+#define CLK_8_1(cn, pl, r, f) \
+ PER_CLK(0, cn, pl, r, 8, 1, (f) | DCF_HAVE_MUX | DCF_HAVE_DIV)
+/* Mux with fractional 16.1 divider. */
+#define CLK16_1(cn, pl, r, f) \
+ PER_CLK(0, cn, pl, r, 16, 1, (f) | DCF_HAVE_MUX | DCF_HAVE_DIV)
+/* Mux with integer 16bits divider. */
+#define CLK16_0(cn, pl, r, f) \
+ PER_CLK(0, cn, pl, r, 16, 0, (f) | DCF_HAVE_MUX | DCF_HAVE_DIV)
+/* Mux wihout divider. */
+#define CLK_0_0(cn, pl, r, f) \
+ PER_CLK(0, cn, pl, r, 0, 0, (f) | DCF_HAVE_MUX)
+
+static struct periph_def periph_def[] = {
+ CLK_8_1("pc_i2s1", mux_a_N_audio1_N_p_N_clkm, CLK_SOURCE_I2S1, DCF_HAVE_ENA),
+ CLK_8_1("pc_i2s2", mux_a_N_audio2_N_p_N_clkm, CLK_SOURCE_I2S2, DCF_HAVE_ENA),
+ CLK_8_1("pc_spdif_out", mux_a_N_audio_N_p_N_clkm, CLK_SOURCE_SPDIF_OUT, 0),
+ CLK_8_1("pc_spdif_in", mux_p_c2_c_c3_m, CLK_SOURCE_SPDIF_IN, 0),
+ CLK_8_1("pc_pwm", mux_p_c2_c_c3_clks_N_clkm, CLK_SOURCE_PWM, 0),
+ CLK_8_1("pc_spi2", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI2, 0),
+ CLK_8_1("pc_spi3", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI3, 0),
+ CLK16_0("pc_i2c5", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C5, 0),
+ CLK16_0("pc_i2c1", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C1, 0),
+ CLK_8_1("pc_spi1", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI1, 0),
+ CLK_0_0("pc_disp1", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_DISP1, 0),
+ CLK_0_0("pc_disp2", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_DISP2, 0),
+ CLK_8_1("pc_isp", mux_m_c_p_a_c2_c3_clkm_c4, CLK_SOURCE_ISP, 0),
+ CLK_8_1("pc_vi", mux_m_c2_c_c3_p_N_a_c4, CLK_SOURCE_VI, DCF_IS_VI),
+ CLK_8_1("pc_sdmmc1", mux_p_c2_c_c3_m_e_clkm, CLK_SOURCE_SDMMC1, 0),
+ CLK_8_1("pc_sdmmc2", mux_p_c2_c_c3_m_e_clkm, CLK_SOURCE_SDMMC2, 0),
+ CLK_8_1("pc_sdmmc4", mux_p_c2_c_c3_m_e_clkm, CLK_SOURCE_SDMMC4, 0),
+ CLK_8_1("pc_vfir", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_VFIR, 0),
+ CLK_8_1("pc_hsi", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HSI, 0),
+ CLK16_1("pc_uarta", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTA, DCF_IS_UART),
+ CLK16_1("pc_uartb", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTB, DCF_IS_UART),
+ CLK_8_1("pc_host1x", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HOST1X, DCF_IS_HOST1X),
+ CLK_8_1("pc_hdmi", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_HDMI, 0),
+ CLK16_0("pc_i2c2", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C2, 0),
+/* EMC 8 */
+ CLK16_1("pc_uartc", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTC, DCF_IS_UART),
+ CLK_8_1("pc_vi_sensor", mux_m_c2_c_c3_p_N_a, CLK_SOURCE_VI_SENSOR, 0),
+ CLK_8_1("pc_spi4", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI4, 0),
+ CLK16_0("pc_i2c3", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C3, 0),
+ CLK_8_1("pc_sdmmc3", mux_p_c2_c_c3_m_e_clkm, CLK_SOURCE_SDMMC3, 0),
+ CLK16_1("pc_uartd", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_UARTD, DCF_IS_UART),
+ CLK_8_1("pc_vde", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_VDE, 0),
+ CLK_8_1("pc_owr", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_OWR, 0),
+ CLK_8_1("pc_snor", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_NOR, 0),
+ CLK_8_1("pc_csite", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_CSITE, 0),
+ CLK_8_1("pc_i2s0", mux_a_N_audio0_N_p_N_clkm, CLK_SOURCE_I2S0, 0),
+/* DTV xxx */
+ CLK_8_1("pc_msenc", mux_m_c2_c_c3_p_N_a, CLK_SOURCE_MSENC, 0),
+ CLK_8_1("pc_tsec", mux_p_c2_c_c3_m_a_clkm, CLK_SOURCE_TSEC, 0),
+/* SPARE2 */
+
+
+ CLK_8_1("pc_mselect", mux_p_c2_c_c3_m_clks_clkm, CLK_SOURCE_MSELECT, 0),
+ CLK_8_1("pc_tsensor", mux_p_c2_c_c3_clkm_N_clks, CLK_SOURCE_TSENSOR, 0),
+ CLK_8_1("pc_i2s3", mux_a_N_audio3_N_p_N_clkm, CLK_SOURCE_I2S3, DCF_HAVE_ENA),
+ CLK_8_1("pc_i2s4", mux_a_N_audio4_N_p_N_clkm, CLK_SOURCE_I2S4, DCF_HAVE_ENA),
+ CLK16_0("pc_i2c4", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C4, 0),
+ CLK_8_1("pc_spi5", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI5, 0),
+ CLK_8_1("pc_spi6", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_SPI6, 0),
+ CLK_8_1("pc_audio", mux_sep_audio, CLK_SOURCE_AUDIO, DCF_IS_AUDIO),
+ CLK_8_1("pc_dam0", mux_sep_audio, CLK_SOURCE_DAM0, DCF_IS_AUDIO),
+ CLK_8_1("pc_dam1", mux_sep_audio, CLK_SOURCE_DAM1, DCF_IS_AUDIO),
+ CLK_8_1("pc_dam2", mux_sep_audio, CLK_SOURCE_DAM2, DCF_IS_AUDIO),
+ CLK_8_1("pc_hda2codec_2x", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HDA2CODEC_2X, 0),
+ CLK_8_1("pc_actmon", mux_p_c2_c_c3_clks_N_clkm, CLK_SOURCE_ACTMON, 0),
+ CLK_8_1("pc_extperiph1", mux_a_clks_p_clkm_e, CLK_SOURCE_EXTPERIPH1, 0),
+ CLK_8_1("pc_extperiph2", mux_a_clks_p_clkm_e, CLK_SOURCE_EXTPERIPH2, 0),
+ CLK_8_1("pc_extperiph3", mux_a_clks_p_clkm_e, CLK_SOURCE_EXTPERIPH3, 0),
+ CLK_8_1("pc_i2c_slow", mux_p_c2_c_c3_clks_N_clkm, CLK_SOURCE_I2C_SLOW, 0),
+/* SYS */
+ CLK_8_1("pc_sor0", mux_p_m_d_a_c_d2_clkm, CLK_SOURCE_SOR0, DCF_IS_SOR0),
+ CLK_8_1("pc_sata_oob", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA_OOB, 0),
+ CLK_8_1("pc_sata", mux_p_N_c_N_m_N_clkm, CLK_SOURCE_SATA, FDS_IS_SATA),
+ CLK_8_1("pc_hda", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_HDA, 0),
+
+
+ CLK_8_1("pc_xusb_core_host", mux_clkm_p_c2_c_c3_refre, CLK_SOURCE_XUSB_CORE_HOST, 0),
+ CLK_8_1("pc_xusb_falcon", mux_clkm_p_c2_c_c3_refre, CLK_SOURCE_XUSB_FALCON, 0),
+ CLK_8_1("pc_xusb_fs", mux_clkm_N_u48_N_p_N_u480, CLK_SOURCE_XUSB_FS, 0),
+ CLK_8_1("pc_xusb_core_dev", mux_clkm_p_c2_c_c3_refre, CLK_SOURCE_XUSB_CORE_DEV, 0),
+ CLK_8_1("pc_xusb_ss", mux_clkm_refe_clks_u480_c_c2_c3_oscdiv, CLK_SOURCE_XUSB_SS, DCF_IS_XUSB_SS),
+ CLK_8_1("pc_cilab", mux_p_N_c_N_N_N_clkm, CLK_SOURCE_CILAB, 0),
+ CLK_8_1("pc_cilcd", mux_p_N_c_N_N_N_clkm, CLK_SOURCE_CILCD, 0),
+ CLK_8_1("pc_cile", mux_p_N_c_N_N_N_clkm, CLK_SOURCE_CILE, 0),
+ CLK_8_1("pc_dsia_lp", mux_p_N_c_N_N_N_clkm, CLK_SOURCE_DSIA_LP, 0),
+ CLK_8_1("pc_dsib_lp", mux_p_N_c_N_N_N_clkm, CLK_SOURCE_DSIB_LP, 0),
+ CLK_8_1("pc_entropy", mux_p_clkm_clks_E, CLK_SOURCE_ENTROPY, 0),
+ CLK_8_1("pc_dvfs_ref", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_DVFS_REF, DCF_HAVE_ENA),
+ CLK_8_1("pc_dvfs_soc", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_DVFS_SOC, DCF_HAVE_ENA),
+ CLK_8_1("pc_traceclkin", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_TRACECLKIN, 0),
+ CLK_8_1("pc_adx", mux_a_c2_c_c3_p_N_clkm, CLK_SOURCE_ADX, DCF_HAVE_ENA),
+ CLK_8_1("pc_amx", mux_a_c2_c_c3_p_N_clkm, CLK_SOURCE_AMX, DCF_HAVE_ENA),
+ CLK_8_1("pc_emc_latency", mux_m_c_p_clkm_mud_c2_c3, CLK_SOURCE_EMC_LATENCY, 0),
+ CLK_8_1("pc_soc_therm", mux_m_c_p_a_c2_c3, CLK_SOURCE_SOC_THERM, 0),
+ CLK_8_1("pc_vi_sensor2", mux_m_c2_c_c3_p_N_a, CLK_SOURCE_VI_SENSOR2, 0),
+ CLK16_0("pc_i2c6", mux_p_c2_c_c3_m_N_clkm, CLK_SOURCE_I2C6, 0),
+ CLK_8_1("pc_emc_dll", mux_m_c_p_clkm_mud_c2_c3, CLK_SOURCE_EMC_DLL, DCF_IS_EMC_DLL),
+ CLK_8_1("pc_hdmi_audio", mux_p_c_c2_clkm, CLK_SOURCE_HDMI_AUDIO, 0),
+ CLK_8_1("pc_clk72mhz", mux_p_c_c2_clkm, CLK_SOURCE_CLK72MHZ, 0),
+ CLK_8_1("pc_adx1", mux_a_c2_c_c3_p_N_clkm, CLK_SOURCE_ADX1, DCF_HAVE_ENA),
+ CLK_8_1("pc_amx1", mux_a_c2_c_c3_p_N_clkm, CLK_SOURCE_AMX1, DCF_HAVE_ENA),
+ CLK_8_1("pc_vic", mux_m_c_p_a_c2_c3_clkm, CLK_SOURCE_VIC, DCF_IS_VIC),
+};
+
+static int periph_init(struct clknode *clk, device_t dev);
+static int periph_recalc(struct clknode *clk, uint64_t *freq);
+static int periph_set_freq(struct clknode *clk, uint64_t fin,
+ uint64_t *fout, int flags, int *stop);
+static int periph_set_mux(struct clknode *clk, int idx);
+
+struct periph_sc {
+ device_t clkdev;
+ uint32_t base_reg;
+ uint32_t div_shift;
+ uint32_t div_width;
+ uint32_t div_mask;
+ uint32_t div_f_width;
+ uint32_t div_f_mask;
+ uint32_t flags;
+
+ uint32_t divider;
+ int mux;
+};
+
+static clknode_method_t periph_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, periph_init),
+ CLKNODEMETHOD(clknode_recalc_freq, periph_recalc),
+ CLKNODEMETHOD(clknode_set_freq, periph_set_freq),
+ CLKNODEMETHOD(clknode_set_mux, periph_set_mux),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(tegra124_periph, tegra124_periph_class, periph_methods,
+ sizeof(struct periph_sc), clknode_class);
+static int
+periph_init(struct clknode *clk, device_t dev)
+{
+ struct periph_sc *sc;
+ uint32_t reg;
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(sc);
+ if (sc->flags & DCF_HAVE_ENA)
+ MD4(sc, sc->base_reg, PERLCK_ENA_MASK, PERLCK_ENA_MASK);
+
+ RD4(sc, sc->base_reg, &reg);
+ DEVICE_UNLOCK(sc);
+
+ /* Stnadard mux. */
+ if (sc->flags & DCF_HAVE_MUX)
+ sc->mux = (reg >> PERLCK_MUX_SHIFT) & PERLCK_MUX_MASK;
+ else
+ sc->mux = 0;
+ if (sc->flags & DCF_HAVE_DIV)
+ sc->divider = (reg & sc->div_mask) + 2;
+ else
+ sc->divider = 1;
+ if ((sc->flags & DCF_IS_MASK) == DCF_IS_UART) {
+ if (!(reg & PERLCK_UDIV_DIS))
+ sc->divider = 2;
+ }
+
+ /* AUDIO MUX */
+ if ((sc->flags & DCF_IS_MASK) == DCF_IS_AUDIO) {
+ if (!(reg & PERLCK_AMUX_DIS) && (sc->mux == 7)) {
+ sc->mux = 8 +
+ ((reg >> PERLCK_AMUX_SHIFT) & PERLCK_MUX_MASK);
+ }
+ }
+ clknode_init_parent_idx(clk, sc->mux);
+ return(0);
+}
+
+static int
+periph_set_mux(struct clknode *clk, int idx)
+{
+ struct periph_sc *sc;
+ uint32_t reg;
+
+
+ sc = clknode_get_softc(clk);
+ if (!(sc->flags & DCF_HAVE_MUX))
+ return (ENXIO);
+
+ sc->mux = idx;
+ DEVICE_LOCK(sc);
+ RD4(sc, sc->base_reg, &reg);
+ reg &= ~(PERLCK_MUX_MASK << PERLCK_MUX_SHIFT);
+ if ((sc->flags & DCF_IS_MASK) == DCF_IS_AUDIO) {
+ reg &= ~PERLCK_AMUX_DIS;
+ reg &= ~(PERLCK_MUX_MASK << PERLCK_AMUX_SHIFT);
+
+ if (idx <= 7) {
+ reg |= idx << PERLCK_MUX_SHIFT;
+ } else {
+ reg |= 7 << PERLCK_MUX_SHIFT;
+ reg |= (idx - 8) << PERLCK_AMUX_SHIFT;
+ }
+ } else {
+ reg |= idx << PERLCK_MUX_SHIFT;
+ }
+ WR4(sc, sc->base_reg, reg);
+ DEVICE_UNLOCK(sc);
+
+ return(0);
+}
+
+static int
+periph_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct periph_sc *sc;
+ uint32_t reg;
+
+ sc = clknode_get_softc(clk);
+
+ if (sc->flags & DCF_HAVE_DIV) {
+ DEVICE_LOCK(sc);
+ RD4(sc, sc->base_reg, &reg);
+ DEVICE_UNLOCK(sc);
+ *freq = (*freq << sc->div_f_width) / sc->divider;
+ }
+ return (0);
+}
+
+static int
+periph_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct periph_sc *sc;
+ uint64_t tmp, divider;
+
+ sc = clknode_get_softc(clk);
+ if (!(sc->flags & DCF_HAVE_DIV)) {
+ *stop = 0;
+ return (0);
+ }
+
+ tmp = fin << sc->div_f_width;
+ divider = tmp / *fout;
+ if ((tmp % *fout) != 0)
+ divider++;
+
+ if (divider < (1 << sc->div_f_width))
+ divider = 1 << sc->div_f_width;
+
+ if ((*stop != 0) &&
+ ((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&
+ (*fout != (tmp / divider)))
+ return (ERANGE);
+
+ if ((flags & CLK_SET_DRYRUN) == 0) {
+ DEVICE_LOCK(sc);
+ MD4(sc, sc->base_reg, sc->div_mask,
+ (divider - (1 << sc->div_f_width)));
+ DEVICE_UNLOCK(sc);
+ sc->divider = divider;
+ }
+ *fout = tmp / divider;
+ *stop = 1;
+ return (0);
+}
+
+static int
+periph_register(struct clkdom *clkdom, struct periph_def *clkdef)
+{
+ struct clknode *clk;
+ struct periph_sc *sc;
+
+ clk = clknode_create(clkdom, &tegra124_periph_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->clkdev = clknode_get_device(clk);
+ sc->base_reg = clkdef->base_reg;
+ sc->div_width = clkdef->div_width;
+ sc->div_mask = (1 <<clkdef->div_width) - 1;
+ sc->div_f_width = clkdef->div_f_width;
+ sc->div_f_mask = (1 <<clkdef->div_f_width) - 1;
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
+
+/* -------------------------------------------------------------------------- */
+static int pgate_init(struct clknode *clk, device_t dev);
+static int pgate_set_gate(struct clknode *clk, bool enable);
+
+struct pgate_sc {
+ device_t clkdev;
+ uint32_t idx;
+ uint32_t flags;
+ uint32_t enabled;
+
+};
+
+static clknode_method_t pgate_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, pgate_init),
+ CLKNODEMETHOD(clknode_set_gate, pgate_set_gate),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(tegra124_pgate, tegra124_pgate_class, pgate_methods,
+ sizeof(struct pgate_sc), clknode_class);
+
+static uint32_t
+get_enable_reg(int idx)
+{
+ KASSERT(idx / 32 < nitems(clk_enabale_reg),
+ ("Invalid clock index for enable: %d", idx));
+ return (clk_enabale_reg[idx / 32]);
+}
+
+static uint32_t
+get_reset_reg(int idx)
+{
+ KASSERT(idx / 32 < nitems(clk_reset_reg),
+ ("Invalid clock index for reset: %d", idx));
+ return (clk_reset_reg[idx / 32]);
+}
+
+static int
+pgate_init(struct clknode *clk, device_t dev)
+{
+ struct pgate_sc *sc;
+ uint32_t ena_reg, rst_reg, mask;
+
+ sc = clknode_get_softc(clk);
+ mask = 1 << (sc->idx % 32);
+
+ DEVICE_LOCK(sc);
+ RD4(sc, get_enable_reg(sc->idx), &ena_reg);
+ RD4(sc, get_reset_reg(sc->idx), &rst_reg);
+ DEVICE_UNLOCK(sc);
+
+ sc->enabled = ena_reg & mask ? 1 : 0;
+ clknode_init_parent_idx(clk, 0);
+
+ return(0);
+}
+
+static int
+pgate_set_gate(struct clknode *clk, bool enable)
+{
+ struct pgate_sc *sc;
+ uint32_t reg, mask, base_reg;
+
+ sc = clknode_get_softc(clk);
+ mask = 1 << (sc->idx % 32);
+ sc->enabled = enable;
+ base_reg = get_enable_reg(sc->idx);
+
+ DEVICE_LOCK(sc);
+ MD4(sc, base_reg, mask, enable ? mask : 0);
+ RD4(sc, base_reg, &reg);
+ DEVICE_UNLOCK(sc);
+
+ DELAY(2);
+ return(0);
+}
+
+int
+tegra124_hwreset_by_idx(struct tegra124_car_softc *sc, intptr_t idx, bool reset)
+{
+ uint32_t reg, mask, reset_reg;
+
+ mask = 1 << (idx % 32);
+ reset_reg = get_reset_reg(idx);
+
+ CLKDEV_DEVICE_LOCK(sc->dev);
+ CLKDEV_MODIFY_4(sc->dev, reset_reg, mask, reset ? mask : 0);
+ CLKDEV_READ_4(sc->dev, reset_reg, &reg);
+ CLKDEV_DEVICE_UNLOCK(sc->dev);
+
+ return(0);
+}
+
+static int
+pgate_register(struct clkdom *clkdom, struct pgate_def *clkdef)
+{
+ struct clknode *clk;
+ struct pgate_sc *sc;
+
+ clk = clknode_create(clkdom, &tegra124_pgate_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->clkdev = clknode_get_device(clk);
+ sc->idx = clkdef->idx;
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
+
+void
+tegra124_periph_clock(struct tegra124_car_softc *sc)
+{
+ int i, rv;
+
+ for (i = 0; i < nitems(periph_def); i++) {
+ rv = periph_register(sc->clkdom, &periph_def[i]);
+ if (rv != 0)
+ panic("tegra124_periph_register failed");
+ }
+ for (i = 0; i < nitems(pgate_def); i++) {
+ rv = pgate_register(sc->clkdom, &pgate_def[i]);
+ if (rv != 0)
+ panic("tegra124_pgate_register failed");
+ }
+
+}
diff --git a/sys/arm/nvidia/tegra124/tegra124_clk_pll.c b/sys/arm/nvidia/tegra124/tegra124_clk_pll.c
new file mode 100644
index 0000000..6adfd32
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_clk_pll.c
@@ -0,0 +1,1066 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h>
+#include "tegra124_car.h"
+
+/* #define TEGRA_PLL_DEBUG */
+#ifdef TEGRA_PLL_DEBUG
+#define dprintf(...) printf(__VA_ARGS__)
+#else
+#define dprintf(...)
+#endif
+
+/* All PLLs. */
+enum pll_type {
+ PLL_M,
+ PLL_X,
+ PLL_C,
+ PLL_C2,
+ PLL_C3,
+ PLL_C4,
+ PLL_P,
+ PLL_A,
+ PLL_U,
+ PLL_D,
+ PLL_D2,
+ PLL_DP,
+ PLL_E,
+ PLL_REFE};
+
+/* Common base register bits. */
+#define PLL_BASE_BYPASS (1U << 31)
+#define PLL_BASE_ENABLE (1 << 30)
+#define PLL_BASE_REFDISABLE (1 << 29)
+#define PLL_BASE_LOCK (1 << 27)
+#define PLL_BASE_DIVM_SHIFT 0
+#define PLL_BASE_DIVN_SHIFT 8
+
+#define PLLRE_MISC_LOCK (1 << 24)
+
+#define PLL_MISC_LOCK_ENABLE (1 << 18)
+#define PLLC_MISC_LOCK_ENABLE (1 << 24)
+#define PLLDU_MISC_LOCK_ENABLE (1 << 22)
+#define PLLRE_MISC_LOCK_ENABLE (1 << 30)
+#define PLLSS_MISC_LOCK_ENABLE (1 << 30)
+
+#define PLLC_IDDQ_BIT 26
+#define PLLX_IDDQ_BIT 3
+#define PLLRE_IDDQ_BIT 16
+#define PLLSS_IDDQ_BIT 19
+
+#define PLL_LOCK_TIMEOUT 1000
+
+/* Post divider <-> register value mapping. */
+struct pdiv_table {
+ uint32_t divider; /* real divider */
+ uint32_t value; /* register value */
+};
+
+/* Bits definition of M, N and P fields. */
+struct mnp_bits {
+ uint32_t m_width;
+ uint32_t n_width;
+ uint32_t p_width;
+ uint32_t p_shift;
+};
+
+struct clk_pll_def {
+ struct clknode_init_def clkdef;
+ enum pll_type type;
+ uint32_t base_reg;
+ uint32_t misc_reg;
+ uint32_t lock_mask;
+ uint32_t lock_enable;
+ uint32_t iddq_reg;
+ uint32_t iddq_mask;
+ uint32_t flags;
+ struct pdiv_table *pdiv_table;
+ struct mnp_bits mnp_bits;
+};
+
+#define PLL(_id, cname, pname) \
+ .clkdef.id = _id, \
+ .clkdef.name = cname, \
+ .clkdef.parent_names = (const char *[]){pname}, \
+ .clkdef.parent_cnt = 1, \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS
+
+/* Tegra K1 PLLs
+ PLLM: Clock source for EMC 2x clock
+ PLLX: Clock source for the fast CPU cluster and the shadow CPU
+ PLLC: Clock source for general use
+ PLLC2: Clock source for engine scaling
+ PLLC3: Clock source for engine scaling
+ PLLC4: Clock source for ISP/VI units
+ PLLP: Clock source for most peripherals
+ PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz)
+ PLLU: Clock source for USB PHY, provides 12/60/480 MHz
+ PLLD: Clock sources for the DSI and display subsystem
+ PLLD2: Clock sources for the DSI and display subsystem
+ refPLLe:
+ PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum)
+ PLLDP: Clock source for eDP/LVDS (spread spectrum)
+
+ DFLLCPU: DFLL clock source for the fast CPU cluster
+ GPCPLL: Clock source for the GPU
+*/
+
+static struct pdiv_table pllm_map[] = {
+ {1, 0},
+ {2, 1},
+ {0, 0}
+};
+
+static struct pdiv_table pllxc_map[] = {
+ { 1, 0},
+ { 2, 1},
+ { 3, 2},
+ { 4, 3},
+ { 5, 4},
+ { 6, 5},
+ { 8, 6},
+ {10, 7},
+ {12, 8},
+ {16, 9},
+ {12, 10},
+ {16, 11},
+ {20, 12},
+ {24, 13},
+ {32, 14},
+ { 0, 0}
+};
+
+static struct pdiv_table pllc_map[] = {
+ { 1, 0},
+ { 2, 1},
+ { 3, 2},
+ { 4, 3},
+ { 6, 4},
+ { 8, 5},
+ {12, 6},
+ {16, 7},
+ { 0, 0}
+};
+
+static struct pdiv_table pll12g_ssd_esd_map[] = {
+ { 1, 0},
+ { 2, 1},
+ { 3, 2},
+ { 4, 3},
+ { 5, 4},
+ { 6, 5},
+ { 8, 6},
+ {10, 7},
+ {12, 8},
+ {16, 9},
+ {12, 10},
+ {16, 11},
+ {20, 12},
+ {24, 13},
+ {32, 14},
+ { 0, 0}
+};
+
+static struct pdiv_table pllu_map[] = {
+ {1, 1},
+ {2, 0},
+ {0, 0}
+};
+
+static struct clk_pll_def pll_clks[] = {
+/* PLLM: 880 MHz Clock source for EMC 2x clock */
+ {
+ PLL(TEGRA124_CLK_PLL_M, "pllM_out0", "osc_div_clk"),
+ .type = PLL_M,
+ .base_reg = PLLM_BASE,
+ .misc_reg = PLLM_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .pdiv_table = pllm_map,
+ .mnp_bits = {8, 8, 1, 20},
+ },
+/* PLLX: 1GHz Clock source for the fast CPU cluster and the shadow CPU */
+ {
+ PLL(TEGRA124_CLK_PLL_X, "pllX_out", "osc_div_clk"),
+ .type = PLL_X,
+ .base_reg = PLLX_BASE,
+ .misc_reg = PLLX_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLX_MISC3,
+ .iddq_mask = 1 << PLLX_IDDQ_BIT,
+ .pdiv_table = pllxc_map,
+ .mnp_bits = {8, 8, 4, 20},
+ },
+/* PLLC: 600 MHz Clock source for general use */
+ {
+ PLL(TEGRA124_CLK_PLL_C, "pllC_out0", "osc_div_clk"),
+ .type = PLL_C,
+ .base_reg = PLLC_BASE,
+ .misc_reg = PLLC_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLLC_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLC_MISC,
+ .iddq_mask = 1 << PLLC_IDDQ_BIT,
+ .pdiv_table = pllc_map,
+ .mnp_bits = {8, 8, 4, 20},
+ },
+/* PLLC2: 600 MHz Clock source for engine scaling */
+ {
+ PLL(TEGRA124_CLK_PLL_C2, "pllC2_out0", "osc_div_clk"),
+ .type = PLL_C2,
+ .base_reg = PLLC2_BASE,
+ .misc_reg = PLLC2_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .pdiv_table = pllc_map,
+ .mnp_bits = {2, 8, 3, 20},
+ },
+/* PLLC3: 600 MHz Clock source for engine scaling */
+ {
+ PLL(TEGRA124_CLK_PLL_C3, "pllC3_out0", "osc_div_clk"),
+ .type = PLL_C3,
+ .base_reg = PLLC3_BASE,
+ .misc_reg = PLLC3_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .pdiv_table = pllc_map,
+ .mnp_bits = {2, 8, 3, 20},
+ },
+/* PLLC4: 600 MHz Clock source for ISP/VI units */
+ {
+ PLL(TEGRA124_CLK_PLL_C4, "pllC4_out0", "pllC4_src"),
+ .type = PLL_C4,
+ .base_reg = PLLC4_BASE,
+ .misc_reg = PLLC4_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLLSS_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLC4_BASE,
+ .iddq_mask = 1 << PLLSS_IDDQ_BIT,
+ .pdiv_table = pll12g_ssd_esd_map,
+ .mnp_bits = {8, 8, 4, 20},
+ },
+/* PLLP: 408 MHz Clock source for most peripherals */
+ {
+ PLL(TEGRA124_CLK_PLL_P, "pllP_out0", "osc_div_clk"),
+ .type = PLL_P,
+ .base_reg = PLLP_BASE,
+ .misc_reg = PLLP_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .mnp_bits = {5, 10, 3, 20},
+ },
+/* PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz) */
+ {
+ PLL(TEGRA124_CLK_PLL_A, "pllA_out", "pllP_out1"),
+ .type = PLL_A,
+ .base_reg = PLLA_BASE,
+ .misc_reg = PLLA_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .mnp_bits = {5, 10, 3, 20},
+ },
+/* PLLU: 480 MHz Clock source for USB PHY, provides 12/60/480 MHz */
+ {
+ PLL(TEGRA124_CLK_PLL_U, "pllU_out", "osc_div_clk"),
+ .type = PLL_U,
+ .base_reg = PLLU_BASE,
+ .misc_reg = PLLU_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLLDU_MISC_LOCK_ENABLE,
+ .pdiv_table = pllu_map,
+ .mnp_bits = {5, 10, 1, 20},
+ },
+/* PLLD: 600 MHz Clock sources for the DSI and display subsystem */
+ {
+ PLL(TEGRA124_CLK_PLL_D, "pllD_out", "osc_div_clk"),
+ .type = PLL_D,
+ .base_reg = PLLD_BASE,
+ .misc_reg = PLLD_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLL_MISC_LOCK_ENABLE,
+ .mnp_bits = {5, 11, 3, 20},
+ },
+/* PLLD2: 600 MHz Clock sources for the DSI and display subsystem */
+ {
+ PLL(TEGRA124_CLK_PLL_D2, "pllD2_out", "pllD2_src"),
+ .type = PLL_D2,
+ .base_reg = PLLD2_BASE,
+ .misc_reg = PLLD2_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLLSS_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLD2_BASE,
+ .iddq_mask = 1 << PLLSS_IDDQ_BIT,
+ .pdiv_table = pll12g_ssd_esd_map,
+ .mnp_bits = {8, 8, 4, 20},
+ },
+/* refPLLe: */
+ {
+ PLL(0, "pllREFE_out", "osc_div_clk"),
+ .type = PLL_REFE,
+ .base_reg = PLLRE_BASE,
+ .misc_reg = PLLRE_MISC,
+ .lock_mask = PLLRE_MISC_LOCK,
+ .lock_enable = PLLRE_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLRE_MISC,
+ .iddq_mask = 1 << PLLRE_IDDQ_BIT,
+ .mnp_bits = {8, 8, 4, 16},
+ },
+/* PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum) */
+ {
+ PLL(TEGRA124_CLK_PLL_E, "pllE_out0", "pllE_src"),
+ .type = PLL_E,
+ .base_reg = PLLE_BASE,
+ .misc_reg = PLLE_MISC,
+ .lock_mask = PLLE_MISC_LOCK,
+ .lock_enable = PLLE_MISC_LOCK_ENABLE,
+ .mnp_bits = {8, 8, 4, 24},
+ },
+/* PLLDP: 600 MHz Clock source for eDP/LVDS (spread spectrum) */
+ {
+ PLL(0, "pllDP_out0", "pllDP_src"),
+ .type = PLL_DP,
+ .base_reg = PLLDP_BASE,
+ .misc_reg = PLLDP_MISC,
+ .lock_mask = PLL_BASE_LOCK,
+ .lock_enable = PLLSS_MISC_LOCK_ENABLE,
+ .iddq_reg = PLLDP_BASE,
+ .iddq_mask = 1 << PLLSS_IDDQ_BIT,
+ .pdiv_table = pll12g_ssd_esd_map,
+ .mnp_bits = {8, 8, 4, 20},
+ },
+};
+
+static int tegra124_pll_init(struct clknode *clk, device_t dev);
+static int tegra124_pll_set_gate(struct clknode *clk, bool enable);
+static int tegra124_pll_recalc(struct clknode *clk, uint64_t *freq);
+static int tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin,
+ uint64_t *fout, int flags, int *stop);
+struct pll_sc {
+ device_t clkdev;
+ enum pll_type type;
+ uint32_t base_reg;
+ uint32_t misc_reg;
+ uint32_t lock_mask;
+ uint32_t lock_enable;
+ uint32_t iddq_reg;
+ uint32_t iddq_mask;
+ uint32_t flags;
+ struct pdiv_table *pdiv_table;
+ struct mnp_bits mnp_bits;
+};
+
+static clknode_method_t tegra124_pll_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, tegra124_pll_init),
+ CLKNODEMETHOD(clknode_set_gate, tegra124_pll_set_gate),
+ CLKNODEMETHOD(clknode_recalc_freq, tegra124_pll_recalc),
+ CLKNODEMETHOD(clknode_set_freq, tegra124_pll_set_freq),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(tegra124_pll, tegra124_pll_class, tegra124_pll_methods,
+ sizeof(struct pll_sc), clknode_class);
+
+static int
+pll_enable(struct pll_sc *sc)
+{
+ uint32_t reg;
+
+
+ RD4(sc, sc->base_reg, &reg);
+ if (sc->type != PLL_E)
+ reg &= ~PLL_BASE_BYPASS;
+ reg |= PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+ return (0);
+}
+
+static int
+pll_disable(struct pll_sc *sc)
+{
+ uint32_t reg;
+
+ RD4(sc, sc->base_reg, &reg);
+ if (sc->type != PLL_E)
+ reg |= PLL_BASE_BYPASS;
+ reg &= ~PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+ return (0);
+}
+
+static uint32_t
+pdiv_to_reg(struct pll_sc *sc, uint32_t p_div)
+{
+ struct pdiv_table *tbl;
+
+ tbl = sc->pdiv_table;
+ if (tbl == NULL)
+ return (ffs(p_div));
+
+ while (tbl->divider != 0) {
+ if (p_div <= tbl->divider)
+ return (tbl->value);
+ tbl++;
+ }
+ return ~0;
+}
+
+static uint32_t
+reg_to_pdiv(struct pll_sc *sc, uint32_t reg)
+{
+ struct pdiv_table *tbl;
+
+ tbl = sc->pdiv_table;
+ if (tbl != NULL) {
+ while (tbl->divider) {
+ if (reg == tbl->value)
+ return (tbl->divider);
+ tbl++;
+ }
+ return (0);
+ }
+ return (1 << reg);
+}
+
+static uint32_t
+get_masked(uint32_t val, uint32_t shift, uint32_t width)
+{
+
+ return ((val >> shift) & ((1 << width) - 1));
+}
+
+static uint32_t
+set_masked(uint32_t val, uint32_t v, uint32_t shift, uint32_t width)
+{
+
+ val &= ~(((1 << width) - 1) << shift);
+ val |= (v & ((1 << width) - 1)) << shift;
+ return (val);
+}
+
+static void
+get_divisors(struct pll_sc *sc, uint32_t *m, uint32_t *n, uint32_t *p)
+{
+ uint32_t val;
+ struct mnp_bits *mnp_bits;
+
+ mnp_bits = &sc->mnp_bits;
+ RD4(sc, sc->base_reg, &val);
+ *m = get_masked(val, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);
+ *n = get_masked(val, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);
+ *p = get_masked(val, mnp_bits->p_shift, mnp_bits->p_width);
+}
+
+static uint32_t
+set_divisors(struct pll_sc *sc, uint32_t val, uint32_t m, uint32_t n,
+ uint32_t p)
+{
+ struct mnp_bits *mnp_bits;
+
+ mnp_bits = &sc->mnp_bits;
+ val = set_masked(val, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);
+ val = set_masked(val, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);
+ val = set_masked(val, p, mnp_bits->p_shift, mnp_bits->p_width);
+ return (val);
+}
+
+static bool
+is_locked(struct pll_sc *sc)
+{
+ uint32_t reg;
+
+ switch (sc->type) {
+ case PLL_REFE:
+ RD4(sc, sc->misc_reg, &reg);
+ reg &= PLLRE_MISC_LOCK;
+ break;
+
+ case PLL_E:
+ RD4(sc, sc->misc_reg, &reg);
+ reg &= PLLE_MISC_LOCK;
+ break;
+
+ default:
+ RD4(sc, sc->base_reg, &reg);
+ reg &= PLL_BASE_LOCK;
+ break;
+ }
+ return (reg != 0);
+}
+
+static int
+wait_for_lock(struct pll_sc *sc)
+{
+ int i;
+
+ for (i = PLL_LOCK_TIMEOUT / 10; i > 0; i--) {
+ if (is_locked(sc))
+ break;
+ DELAY(10);
+ }
+ if (i <= 0) {
+ printf("PLL lock timeout\n");
+ return (ETIMEDOUT);
+ }
+ return (0);
+}
+
+static int
+plle_enable(struct pll_sc *sc)
+{
+ uint32_t reg;
+ int rv;
+ struct mnp_bits *mnp_bits;
+ uint32_t pll_m = 1;
+ uint32_t pll_n = 200;
+ uint32_t pll_p = 13;
+ uint32_t pll_cml = 13;
+
+ mnp_bits = &sc->mnp_bits;
+
+
+ /* Disable lock override. */
+ RD4(sc, sc->base_reg, &reg);
+ reg &= ~PLLE_BASE_LOCK_OVERRIDE;
+ WR4(sc, sc->base_reg, reg);
+
+ RD4(sc, PLLE_AUX, &reg);
+ reg |= PLLE_AUX_ENABLE_SWCTL;
+ reg &= ~PLLE_AUX_SEQ_ENABLE;
+ WR4(sc, PLLE_AUX, reg);
+ DELAY(10);
+
+ RD4(sc, sc->misc_reg, &reg);
+ reg |= PLLE_MISC_LOCK_ENABLE;
+ reg |= PLLE_MISC_IDDQ_SWCTL;
+ reg &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE;
+ reg |= PLLE_MISC_PTS;
+ reg |= PLLE_MISC_VREG_BG_CTRL_MASK;
+ reg |= PLLE_MISC_VREG_CTRL_MASK;
+ WR4(sc, sc->misc_reg, reg);
+ DELAY(10);
+
+ RD4(sc, PLLE_SS_CNTL, &reg);
+ reg |= PLLE_SS_CNTL_DISABLE;
+ WR4(sc, PLLE_SS_CNTL, reg);
+
+ RD4(sc, sc->base_reg, &reg);
+ reg = set_divisors(sc, reg, pll_m, pll_n, pll_p);
+ reg &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT);
+ reg |= pll_cml << PLLE_BASE_DIVCML_SHIFT;
+ WR4(sc, sc->base_reg, reg);
+ DELAY(10);
+
+ pll_enable(sc);
+ rv = wait_for_lock(sc);
+ if (rv != 0)
+ return (rv);
+
+ RD4(sc, PLLE_SS_CNTL, &reg);
+ reg &= ~PLLE_SS_CNTL_SSCCENTER;
+ reg &= ~PLLE_SS_CNTL_SSCINVERT;
+ reg &= ~PLLE_SS_CNTL_COEFFICIENTS_MASK;
+ reg |= PLLE_SS_CNTL_COEFFICIENTS_VAL;
+ WR4(sc, PLLE_SS_CNTL, reg);
+ reg &= ~PLLE_SS_CNTL_SSCBYP;
+ reg &= ~PLLE_SS_CNTL_BYPASS_SS;
+ WR4(sc, PLLE_SS_CNTL, reg);
+ DELAY(10);
+
+ reg &= ~PLLE_SS_CNTL_INTERP_RESET;
+ WR4(sc, PLLE_SS_CNTL, reg);
+ DELAY(10);
+
+ /* HW control of brick pll. */
+ RD4(sc, sc->misc_reg, &reg);
+ reg &= ~PLLE_MISC_IDDQ_SWCTL;
+ WR4(sc, sc->misc_reg, reg);
+
+ RD4(sc, PLLE_AUX, &reg);
+ reg |= PLLE_AUX_USE_LOCKDET;
+ reg |= PLLE_AUX_SEQ_START_STATE;
+ reg &= ~PLLE_AUX_ENABLE_SWCTL;
+ reg &= ~PLLE_AUX_SS_SWCTL;
+ WR4(sc, PLLE_AUX, reg);
+ reg |= PLLE_AUX_SEQ_START_STATE;
+ DELAY(10);
+ reg |= PLLE_AUX_SEQ_ENABLE;
+ WR4(sc, PLLE_AUX, reg);
+
+ RD4(sc, XUSBIO_PLL_CFG0, &reg);
+ reg |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET;
+ reg |= XUSBIO_PLL_CFG0_SEQ_START_STATE;
+ reg &= ~XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL;
+ reg &= ~XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL;
+ WR4(sc, XUSBIO_PLL_CFG0, reg);
+ DELAY(10);
+
+ reg |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
+ WR4(sc, XUSBIO_PLL_CFG0, reg);
+
+
+ /* Enable HW control and unreset SATA PLL. */
+ RD4(sc, SATA_PLL_CFG0, &reg);
+ reg &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL;
+ reg &= ~SATA_PLL_CFG0_PADPLL_RESET_OVERRIDE_VALUE;
+ reg |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET;
+ reg &= ~SATA_PLL_CFG0_SEQ_IN_SWCTL;
+ reg &= ~SATA_PLL_CFG0_SEQ_RESET_INPUT_VALUE;
+ reg &= ~SATA_PLL_CFG0_SEQ_LANE_PD_INPUT_VALUE;
+ reg &= ~SATA_PLL_CFG0_SEQ_PADPLL_PD_INPUT_VALUE;
+ reg &= ~SATA_PLL_CFG0_SEQ_ENABLE;
+ reg |= SATA_PLL_CFG0_SEQ_START_STATE;
+ WR4(sc, SATA_PLL_CFG0, reg);
+ DELAY(10);
+ reg |= SATA_PLL_CFG0_SEQ_ENABLE;
+ WR4(sc, SATA_PLL_CFG0, reg);
+
+ /* Enable HW control of PCIe PLL. */
+ RD4(sc, PCIE_PLL_CFG0, &reg);
+ reg |= PCIE_PLL_CFG0_SEQ_ENABLE;
+ WR4(sc, PCIE_PLL_CFG0, reg);
+
+ return (0);
+}
+
+static int
+tegra124_pll_set_gate(struct clknode *clknode, bool enable)
+{
+ int rv;
+ struct pll_sc *sc;
+
+ sc = clknode_get_softc(clknode);
+ if (enable == 0) {
+ rv = pll_disable(sc);
+ return(rv);
+ }
+
+ if (sc->type == PLL_E)
+ rv = plle_enable(sc);
+ else
+ rv = pll_enable(sc);
+ return (rv);
+}
+
+static int
+pll_set_std(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags,
+ uint32_t m, uint32_t n, uint32_t p)
+{
+ uint32_t reg;
+ struct mnp_bits *mnp_bits;
+ int rv;
+
+ mnp_bits = &sc->mnp_bits;
+ if (m >= (1 << mnp_bits->m_width))
+ return (ERANGE);
+ if (n >= (1 << mnp_bits->n_width))
+ return (ERANGE);
+ if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width))
+ return (ERANGE);
+
+ if (flags & CLK_SET_DRYRUN) {
+ if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&
+ (*fout != (((fin / m) * n) /p)))
+ return (ERANGE);
+
+ *fout = ((fin / m) * n) /p;
+ return (0);
+ }
+
+ pll_disable(sc);
+
+ /* take pll out of IDDQ */
+ if (sc->iddq_reg != 0)
+ MD4(sc, sc->iddq_reg, sc->iddq_mask, 0);
+
+ RD4(sc, sc->base_reg, &reg);
+ reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);
+ reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);
+ reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift,
+ mnp_bits->p_width);
+ WR4(sc, sc->base_reg, reg);
+
+ /* Enable PLL. */
+ RD4(sc, sc->base_reg, &reg);
+ reg |= PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+
+ /* Enable lock detection. */
+ RD4(sc, sc->misc_reg, &reg);
+ reg |= sc->lock_enable;
+ WR4(sc, sc->misc_reg, reg);
+
+ rv = wait_for_lock(sc);
+ if (rv != 0) {
+ /* Disable PLL */
+ RD4(sc, sc->base_reg, &reg);
+ reg &= ~PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+ return (rv);
+ }
+ RD4(sc, sc->misc_reg, &reg);
+
+ pll_enable(sc);
+ *fout = ((fin / m) * n) / p;
+ return 0;
+}
+
+static int
+plla_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
+{
+ uint32_t m, n, p;
+
+ p = 1;
+ m = 5;
+ n = (*fout * p * m + fin / 2)/ fin;
+ dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);
+ return (pll_set_std(sc, fin, fout, flags, m, n, p));
+}
+
+static int
+pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
+{
+ uint32_t m, n, p;
+
+
+ p = 2;
+ m = 1;
+ n = (*fout * p * m + fin / 2)/ fin;
+ dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);
+ return (pll_set_std( sc, fin, fout, flags, m, n, p));
+}
+
+static int
+plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
+{
+ uint32_t m, n, p;
+
+ p = 2;
+ m = 1;
+ n = (*fout * p * m + fin / 2)/ fin;
+ dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);
+ return (pll_set_std(sc, fin, fout, flags, m, n, p));
+}
+
+
+
+static int
+pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
+{
+ uint32_t m, n, p;
+
+ m = 1;
+ p = 1;
+ n = *fout * p * m / fin;
+ return (pll_set_std(sc, fin, fout, flags, m, n, p));
+}
+
+static int
+pllx_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags)
+{
+ uint32_t reg;
+ uint32_t m, n, p;
+ struct mnp_bits *mnp_bits;
+ int rv;
+
+ mnp_bits = &sc->mnp_bits;
+
+ p = 1;
+ m = 1;
+ n = (*fout * p * m + fin / 2)/ fin;
+ dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p);
+
+ if (m >= (1 << mnp_bits->m_width))
+ return (ERANGE);
+ if (n >= (1 << mnp_bits->n_width))
+ return (ERANGE);
+ if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width))
+ return (ERANGE);
+
+ if (flags & CLK_SET_DRYRUN) {
+ if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) &&
+ (*fout != (((fin / m) * n) /p)))
+ return (ERANGE);
+ *fout = ((fin / m) * n) /p;
+ return (0);
+ }
+
+ /* Set bypass. */
+ RD4(sc, sc->base_reg, &reg);
+ reg |= PLL_BASE_BYPASS;
+ WR4(sc, sc->base_reg, reg);
+ RD4(sc, sc->base_reg, &reg);
+ DELAY(100);
+
+ /* Set PLL. */
+ RD4(sc, sc->base_reg, &reg);
+ reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width);
+ reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width);
+ reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift,
+ mnp_bits->p_width);
+ WR4(sc, sc->base_reg, reg);
+ RD4(sc, sc->base_reg, &reg);
+ DELAY(100);
+
+ /* Enable PLL. */
+ RD4(sc, sc->base_reg, &reg);
+ reg |= PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+
+ /* Enable lock detection */
+ RD4(sc, sc->misc_reg, &reg);
+ reg |= sc->lock_enable;
+ WR4(sc, sc->misc_reg, reg);
+
+ rv = wait_for_lock(sc);
+ if (rv != 0) {
+ /* Disable PLL */
+ RD4(sc, sc->base_reg, &reg);
+ reg &= ~PLL_BASE_ENABLE;
+ WR4(sc, sc->base_reg, reg);
+ return (rv);
+ }
+ RD4(sc, sc->misc_reg, &reg);
+
+ /* Clear bypass. */
+ RD4(sc, sc->base_reg, &reg);
+ reg &= ~PLL_BASE_BYPASS;
+ WR4(sc, sc->base_reg, reg);
+ *fout = ((fin / m) * n) / p;
+ return (0);
+}
+
+static int
+tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ *stop = 1;
+ int rv;
+ struct pll_sc *sc;
+
+ sc = clknode_get_softc(clknode);
+ dprintf("%s: Requested freq: %llu, input freq: %llu\n", __func__,
+ *fout, fin);
+ switch (sc->type) {
+ case PLL_A:
+ rv = plla_set_freq(sc, fin, fout, flags);
+ break;
+ case PLL_C:
+ rv = pllc_set_freq(sc, fin, fout, flags);
+ break;
+ case PLL_D2:
+ rv = plld2_set_freq(sc, fin, fout, flags);
+ break;
+
+ case PLL_REFE:
+ rv = pllrefe_set_freq(sc, fin, fout, flags);
+ break;
+
+ case PLL_X:
+ rv = pllx_set_freq(sc, fin, fout, flags);
+ break;
+
+ case PLL_U:
+ if (*fout == 480000000) /* PLLU is fixed to 480 MHz */
+ rv = 0;
+ else
+ rv = ERANGE;
+ break;
+ default:
+ rv = ENXIO;
+ break;
+ }
+ return (rv);
+}
+
+
+static int
+tegra124_pll_init(struct clknode *clk, device_t dev)
+{
+ struct pll_sc *sc;
+ uint32_t reg;
+
+ sc = clknode_get_softc(clk);
+
+ /* If PLL is enabled, enable lock detect too. */
+ RD4(sc, sc->base_reg, &reg);
+ if (reg & PLL_BASE_ENABLE) {
+ RD4(sc, sc->misc_reg, &reg);
+ reg |= sc->lock_enable;
+ WR4(sc, sc->misc_reg, reg);
+ }
+
+ clknode_init_parent_idx(clk, 0);
+ return(0);
+}
+
+static int
+tegra124_pll_recalc(struct clknode *clk, uint64_t *freq)
+{
+ struct pll_sc *sc;
+ uint32_t m, n, p, pr;
+ uint32_t reg, misc_reg;
+ int locked;
+
+ sc = clknode_get_softc(clk);
+
+ RD4(sc, sc->base_reg, &reg);
+ RD4(sc, sc->misc_reg, &misc_reg);
+
+ get_divisors(sc, &m, &n, &pr);
+ if (sc->type != PLL_E)
+ p = reg_to_pdiv(sc, pr);
+ else
+ p = 2 * (pr - 1);
+ locked = is_locked(sc);
+
+ dprintf("%s: %s (0x%08x, 0x%08x) - m: %d, n: %d, p: %d (%d): "
+ "e: %d, r: %d, o: %d - %s\n", __func__,
+ clknode_get_name(clk), reg, misc_reg, m, n, p, pr,
+ (reg >> 30) & 1, (reg >> 29) & 1, (reg >> 28) & 1,
+ locked ? "locked" : "unlocked");
+
+ if ((m == 0) || (n == 0) || (p == 0)) {
+ *freq = 0;
+ return (EINVAL);
+ }
+ *freq = ((*freq / m) * n) / p;
+ return (0);
+}
+
+static int
+pll_register(struct clkdom *clkdom, struct clk_pll_def *clkdef)
+{
+ struct clknode *clk;
+ struct pll_sc *sc;
+
+ clk = clknode_create(clkdom, &tegra124_pll_class, &clkdef->clkdef);
+ if (clk == NULL)
+ return (ENXIO);
+
+ sc = clknode_get_softc(clk);
+ sc->clkdev = clknode_get_device(clk);
+ sc->type = clkdef->type;
+ sc->base_reg = clkdef->base_reg;
+ sc->misc_reg = clkdef->misc_reg;
+ sc->lock_mask = clkdef->lock_mask;
+ sc->lock_enable = clkdef->lock_enable;
+ sc->iddq_reg = clkdef->iddq_reg;
+ sc->iddq_mask = clkdef->iddq_mask;
+ sc->flags = clkdef->flags;
+ sc->pdiv_table = clkdef->pdiv_table;
+ sc->mnp_bits = clkdef->mnp_bits;
+ clknode_register(clkdom, clk);
+ return (0);
+}
+
+static void config_utmi_pll(struct tegra124_car_softc *sc)
+{
+ uint32_t reg;
+ /*
+ * XXX Simplified UTMIP settings for 12MHz base clock.
+ */
+#define ENABLE_DELAY_COUNT 0x02
+#define STABLE_COUNT 0x2F
+#define ACTIVE_DELAY_COUNT 0x04
+#define XTAL_FREQ_COUNT 0x76
+
+ CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG2, &reg);
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(STABLE_COUNT);
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(ACTIVE_DELAY_COUNT);
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+ CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG2, reg);
+
+ CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, &reg);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(ENABLE_DELAY_COUNT);
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(XTAL_FREQ_COUNT);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+ CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg);
+
+ /* Prepare UTMIP requencer. */
+ CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, &reg);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL;
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE;
+ CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);
+
+ /* Powerup UTMIP. */
+ CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, &reg);
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg);
+ DELAY(10);
+
+ /* SW override for UTMIPLL */
+ CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, &reg);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL;
+ reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE;
+ CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);
+ DELAY(10);
+
+ /* HW control of UTMIPLL. */
+ CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, &reg);
+ reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE;
+ CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg);
+}
+
+void
+tegra124_init_plls(struct tegra124_car_softc *sc)
+{
+ int i, rv;
+
+ for (i = 0; i < nitems(pll_clks); i++) {
+ rv = pll_register(sc->clkdom, pll_clks + i);
+ if (rv != 0)
+ panic("pll_register failed");
+ }
+ config_utmi_pll(sc);
+
+}
diff --git a/sys/arm/nvidia/tegra124/tegra124_clk_super.c b/sys/arm/nvidia/tegra124/tegra124_clk_super.c
new file mode 100644
index 0000000..7f32eba
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_clk_super.c
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h>
+#include "tegra124_car.h"
+
+
+/* Flags */
+#define SMF_HAVE_DIVIDER_2 1
+
+struct super_mux_def {
+ struct clknode_init_def clkdef;
+ uint32_t base_reg;
+ uint32_t flags;
+ int src_pllx;
+ int src_div2;
+};
+
+#define PLIST(x) static const char *x[]
+#define SM(_id, cn, pl, r, x, d, f) \
+{ \
+ .clkdef.id = _id, \
+ .clkdef.name = cn, \
+ .clkdef.parent_names = pl, \
+ .clkdef.parent_cnt = nitems(pl), \
+ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
+ .base_reg = r, \
+ .src_pllx = x, \
+ .src_div2 = d, \
+ .flags = f, \
+}
+
+PLIST(cclk_g_parents) = {
+ "clk_m", "pllC_out0", "clk_s", "pllM_out0",
+ "pllP_out0", "pllP_out4", "pllC2_out0", "pllC3_out0",
+ "pllX_out", NULL, NULL, NULL,
+ NULL, NULL, NULL,NULL, // "dfllCPU_out0"
+};
+
+PLIST(cclk_lp_parents) = {
+ "clk_m", "pllC_out0", "clk_s", "pllM_out0",
+ "pllP_out0", "pllP_out4", "pllC2_out0", "pllC3_out0",
+ "pllX_out", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "pllX_out0"
+};
+
+PLIST(sclk_parents) = {
+ "clk_m", "pllC_out1", "pllP_out4", "pllP_out0",
+ "pllP_out2", "pllC_out0", "clk_s", "pllM_out1",
+};
+
+static struct super_mux_def super_mux_def[] = {
+ SM(TEGRA124_CLK_CCLK_G, "cclk_g", cclk_g_parents, CCLKG_BURST_POLICY, 0, 0, 0),
+ SM(TEGRA124_CLK_CCLK_LP, "cclk_lp", cclk_lp_parents, CCLKLP_BURST_POLICY, 8, 16, SMF_HAVE_DIVIDER_2),
+ SM(TEGRA124_CLK_SCLK, "sclk", sclk_parents, SCLK_BURST_POLICY, 0, 0, 0),
+};
+
+static int super_mux_init(struct clknode *clk, device_t dev);
+static int super_mux_set_mux(struct clknode *clk, int idx);
+
+struct super_mux_sc {
+ device_t clkdev;
+ uint32_t base_reg;
+ int src_pllx;
+ int src_div2;
+ uint32_t flags;
+
+ int mux;
+};
+
+static clknode_method_t super_mux_methods[] = {
+ /* Device interface */
+ CLKNODEMETHOD(clknode_init, super_mux_init),
+ CLKNODEMETHOD(clknode_set_mux, super_mux_set_mux),
+ CLKNODEMETHOD_END
+};
+DEFINE_CLASS_1(tegra124_super_mux, tegra124_super_mux_class, super_mux_methods,
+ sizeof(struct super_mux_sc), clknode_class);
+
+/* Mux status. */
+#define SUPER_MUX_STATE_STDBY 0
+#define SUPER_MUX_STATE_IDLE 1
+#define SUPER_MUX_STATE_RUN 2
+#define SUPER_MUX_STATE_IRQ 3
+#define SUPER_MUX_STATE_FIQ 4
+
+/* Mux register bits. */
+#define SUPER_MUX_STATE_BIT_SHIFT 28
+#define SUPER_MUX_STATE_BIT_MASK 0xF
+/* State is Priority encoded */
+#define SUPER_MUX_STATE_BIT_STDBY 0x00
+#define SUPER_MUX_STATE_BIT_IDLE 0x01
+#define SUPER_MUX_STATE_BIT_RUN 0x02
+#define SUPER_MUX_STATE_BIT_IRQ 0x04
+#define SUPER_MUX_STATE_BIT_FIQ 0x08
+
+#define SUPER_MUX_MUX_WIDTH 4
+#define SUPER_MUX_LP_DIV2_BYPASS (1 << 16)
+
+static uint32_t
+super_mux_get_state(uint32_t reg)
+{
+ reg = (reg >> SUPER_MUX_STATE_BIT_SHIFT) & SUPER_MUX_STATE_BIT_MASK;
+ if (reg & SUPER_MUX_STATE_BIT_FIQ)
+ return (SUPER_MUX_STATE_FIQ);
+ if (reg & SUPER_MUX_STATE_BIT_IRQ)
+ return (SUPER_MUX_STATE_IRQ);
+ if (reg & SUPER_MUX_STATE_BIT_RUN)
+ return (SUPER_MUX_STATE_RUN);
+ if (reg & SUPER_MUX_STATE_BIT_IDLE)
+ return (SUPER_MUX_STATE_IDLE);
+ return (SUPER_MUX_STATE_STDBY);
+}
+
+static int
+super_mux_init(struct clknode *clk, device_t dev)
+{
+ struct super_mux_sc *sc;
+ uint32_t reg;
+ int shift, state;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(sc);
+ RD4(sc, sc->base_reg, &reg);
+ DEVICE_UNLOCK(sc);
+ state = super_mux_get_state(reg);
+
+ if ((state != SUPER_MUX_STATE_RUN) &&
+ (state != SUPER_MUX_STATE_IDLE)) {
+ panic("Unexpected super mux state: %u", state);
+ }
+
+ shift = state * SUPER_MUX_MUX_WIDTH;
+
+ sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);
+
+ /*
+ * CCLKLP uses PLLX/2 as source if LP_DIV2_BYPASS isn't set
+ * and source mux is set to PLLX.
+ */
+ if (sc->flags & SMF_HAVE_DIVIDER_2) {
+ if (((reg & SUPER_MUX_LP_DIV2_BYPASS) == 0) &&
+ (sc->mux == sc->src_pllx))
+ sc->mux = sc->src_div2;
+ }
+ clknode_init_parent_idx(clk, sc->mux);
+
+ return(0);
+}
+
+static int
+super_mux_set_mux(struct clknode *clk, int idx)
+{
+
+ struct super_mux_sc *sc;
+ int shift, state;
+ uint32_t reg, dummy;
+
+ sc = clknode_get_softc(clk);
+
+ DEVICE_LOCK(sc);
+ RD4(sc, sc->base_reg, &reg);
+ state = super_mux_get_state(reg);
+
+ if ((state != SUPER_MUX_STATE_RUN) &&
+ (state != SUPER_MUX_STATE_IDLE)) {
+ panic("Unexpected super mux state: %u", state);
+ }
+
+ shift = state * SUPER_MUX_MUX_WIDTH;
+ sc->mux = idx;
+ if (sc->flags & SMF_HAVE_DIVIDER_2) {
+ if (idx == sc->src_div2) {
+ idx = sc->src_pllx;
+ reg &= ~SUPER_MUX_LP_DIV2_BYPASS;
+ WR4(sc, sc->base_reg, reg);
+ RD4(sc, sc->base_reg, &dummy);
+ } else if (idx == sc->src_pllx) {
+ reg = SUPER_MUX_LP_DIV2_BYPASS;
+ WR4(sc, sc->base_reg, reg);
+ RD4(sc, sc->base_reg, &dummy);
+ }
+ }
+ reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
+ reg |= idx << shift;
+ WR4(sc, sc->base_reg, reg);
+ RD4(sc, sc->base_reg, &dummy);
+ DEVICE_UNLOCK(sc);
+
+ return(0);
+}
+
+static int
+super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)
+{
+ struct clknode *clk;
+ struct super_mux_sc *sc;
+
+ clk = clknode_create(clkdom, &tegra124_super_mux_class,
+ &clkdef->clkdef);
+ if (clk == NULL)
+ return (1);
+
+ sc = clknode_get_softc(clk);
+ sc->clkdev = clknode_get_device(clk);
+ sc->base_reg = clkdef->base_reg;
+ sc->src_pllx = clkdef->src_pllx;
+ sc->src_div2 = clkdef->src_div2;
+ sc->flags = clkdef->flags;
+
+ clknode_register(clkdom, clk);
+ return (0);
+}
+
+void
+tegra124_super_mux_clock(struct tegra124_car_softc *sc)
+{
+ int i, rv;
+
+ for (i = 0; i < nitems(super_mux_def); i++) {
+ rv = super_mux_register(sc->clkdom, &super_mux_def[i]);
+ if (rv != 0)
+ panic("super_mux_register failed");
+ }
+
+}
diff --git a/sys/arm/nvidia/tegra124/tegra124_coretemp.c b/sys/arm/nvidia/tegra124/tegra124_coretemp.c
new file mode 100644
index 0000000..c29fe8e
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_coretemp.c
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "tegra_soctherm_if.h"
+
+
+enum therm_info {
+ CORETEMP_TEMP,
+ CORETEMP_DELTA,
+ CORETEMP_RESOLUTION,
+ CORETEMP_TJMAX,
+};
+
+struct tegra124_coretemp_softc {
+ device_t dev;
+ int overheat_log;
+ int core_max_temp;
+ int cpu_id;
+ device_t tsens_dev;
+ intptr_t tsens_id;
+};
+
+static int
+coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev;
+ int val, temp, rv;
+ struct tegra124_coretemp_softc *sc;
+ enum therm_info type;
+ char stemp[16];
+
+
+ dev = (device_t) arg1;
+ sc = device_get_softc(dev);
+ type = arg2;
+
+
+ rv = TEGRA_SOCTHERM_GET_TEMPERATURE(sc->tsens_dev, sc->dev,
+ sc->tsens_id, &temp);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot read temperature sensor %d: %d\n",
+ sc->tsens_id, rv);
+ return (rv);
+ }
+
+ switch (type) {
+ case CORETEMP_TEMP:
+ val = temp / 100;
+ val += 2731;
+ break;
+ case CORETEMP_DELTA:
+ val = (sc->core_max_temp - temp) / 1000;
+ break;
+ case CORETEMP_RESOLUTION:
+ val = 1;
+ break;
+ case CORETEMP_TJMAX:
+ val = sc->core_max_temp / 100;
+ val += 2731;
+ break;
+ }
+
+
+ if ((temp > sc->core_max_temp) && !sc->overheat_log) {
+ sc->overheat_log = 1;
+
+ /*
+ * Check for Critical Temperature Status and Critical
+ * Temperature Log. It doesn't really matter if the
+ * current temperature is invalid because the "Critical
+ * Temperature Log" bit will tell us if the Critical
+ * Temperature has * been reached in past. It's not
+ * directly related to the current temperature.
+ *
+ * If we reach a critical level, allow devctl(4)
+ * to catch this and shutdown the system.
+ */
+ device_printf(dev, "critical temperature detected, "
+ "suggest system shutdown\n");
+ snprintf(stemp, sizeof(stemp), "%d", val);
+ devctl_notify("coretemp", "Thermal", stemp,
+ "notify=0xcc");
+ } else {
+ sc->overheat_log = 0;
+ }
+
+ return (sysctl_handle_int(oidp, 0, val, req));
+}
+
+static int
+tegra124_coretemp_ofw_parse(struct tegra124_coretemp_softc *sc)
+{
+ int rv, ncells;
+ phandle_t node, xnode;
+ pcell_t *cells;
+
+ node = OF_peer(0);
+ node = ofw_bus_find_child(node, "thermal-zones");
+ if (node <= 0) {
+ device_printf(sc->dev, "Cannot find 'thermal-zones'.\n");
+ return (ENXIO);
+ }
+
+ node = ofw_bus_find_child(node, "cpu");
+ if (node <= 0) {
+ device_printf(sc->dev, "Cannot find 'cpu'\n");
+ return (ENXIO);
+ }
+ rv = ofw_bus_parse_xref_list_alloc(node, "thermal-sensors",
+ "#thermal-sensor-cells", 0, &xnode, &ncells, &cells);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot parse 'thermal-sensors' property.\n");
+ return (ENXIO);
+ }
+ if (ncells != 1) {
+ device_printf(sc->dev,
+ "Invalid format of 'thermal-sensors' property(%d).\n",
+ ncells);
+ return (ENXIO);
+ }
+
+ sc->tsens_id = 0x100 + sc->cpu_id; //cells[0];
+ free(cells, M_OFWPROP);
+
+ sc->tsens_dev = OF_device_from_xref(xnode);
+ if (sc->tsens_dev == NULL) {
+ device_printf(sc->dev,
+ "Cannot find thermal sensors device.");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+static void
+tegra124_coretemp_identify(driver_t *driver, device_t parent)
+{
+
+ if (device_find_child(parent, "tegra124_coretemp", -1) != NULL)
+ return;
+ if (BUS_ADD_CHILD(parent, 0, "tegra124_coretemp", -1) == NULL)
+ device_printf(parent, "add child failed\n");
+}
+
+static int
+tegra124_coretemp_probe(device_t dev)
+{
+
+ device_set_desc(dev, "CPU Frequency Control");
+ return (0);
+}
+
+static int
+tegra124_coretemp_attach(device_t dev)
+{
+ struct tegra124_coretemp_softc *sc;
+ device_t pdev;
+ struct sysctl_oid *oid;
+ struct sysctl_ctx_list *ctx;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->cpu_id = device_get_unit(dev);
+ sc->core_max_temp = 102000;
+ pdev = device_get_parent(dev);
+
+ rv = tegra124_coretemp_ofw_parse(sc);
+ if (rv != 0)
+ return (rv);
+
+ ctx = device_get_sysctl_ctx(dev);
+
+ oid = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), OID_AUTO,
+ "coretemp", CTLFLAG_RD, NULL, "Per-CPU thermal information");
+
+ /*
+ * Add the MIBs to dev.cpu.N and dev.cpu.N.coretemp.
+ */
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)),
+ OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, CORETEMP_TEMP, coretemp_get_val_sysctl, "IK",
+ "Current temperature");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "delta",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_DELTA,
+ coretemp_get_val_sysctl, "I",
+ "Delta between TCC activation and current temperature");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "resolution",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_RESOLUTION,
+ coretemp_get_val_sysctl, "I",
+ "Resolution of CPU thermal sensor");
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "tjmax",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_TJMAX,
+ coretemp_get_val_sysctl, "IK",
+ "TCC activation temperature");
+
+ return (0);
+}
+
+static int
+tegra124_coretemp_detach(device_t dev)
+{
+ struct tegra124_coretemp_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (0);
+}
+
+
+static device_method_t tegra124_coretemp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, tegra124_coretemp_identify),
+ DEVMETHOD(device_probe, tegra124_coretemp_probe),
+ DEVMETHOD(device_attach, tegra124_coretemp_attach),
+ DEVMETHOD(device_detach, tegra124_coretemp_detach),
+
+
+ DEVMETHOD_END
+};
+
+static devclass_t tegra124_coretemp_devclass;
+static driver_t tegra124_coretemp_driver = {
+ "tegra124_coretemp",
+ tegra124_coretemp_methods,
+ sizeof(struct tegra124_coretemp_softc),
+};
+
+DRIVER_MODULE(tegra124_coretemp, cpu, tegra124_coretemp_driver,
+ tegra124_coretemp_devclass, 0, 0);
diff --git a/sys/arm/nvidia/tegra124/tegra124_cpufreq.c b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c
new file mode 100644
index 0000000..1227c81
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c
@@ -0,0 +1,583 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_efuse.h>
+
+#include "cpufreq_if.h"
+
+#define XXX
+
+/* CPU voltage table entry */
+struct speedo_entry {
+ uint64_t freq; /* Frequency point */
+ int c0; /* Coeeficient values for */
+ int c1; /* quadratic equation: */
+ int c2; /* c2 * speedo^2 + c1 * speedo + c0 */
+};
+
+struct cpu_volt_def {
+ int min_uvolt; /* Min allowed CPU voltage */
+ int max_uvolt; /* Max allowed CPU voltage */
+ int step_uvolt; /* Step of CPU voltage */
+ int speedo_scale; /* Scaling factor for cvt */
+ int speedo_nitems; /* Size of speedo table */
+ struct speedo_entry *speedo_tbl; /* CPU voltage table */
+};
+
+struct cpu_speed_point {
+ uint64_t freq; /* Frequecy */
+ int uvolt; /* Requested voltage */
+};
+
+static struct speedo_entry tegra124_speedo_dpll_tbl[] =
+{
+ { 204000000ULL, 1112619, -29295, 402},
+ { 306000000ULL, 1150460, -30585, 402},
+ { 408000000ULL, 1190122, -31865, 402},
+ { 510000000ULL, 1231606, -33155, 402},
+ { 612000000ULL, 1274912, -34435, 402},
+ { 714000000ULL, 1320040, -35725, 402},
+ { 816000000ULL, 1366990, -37005, 402},
+ { 918000000ULL, 1415762, -38295, 402},
+ {1020000000ULL, 1466355, -39575, 402},
+ {1122000000ULL, 1518771, -40865, 402},
+ {1224000000ULL, 1573009, -42145, 402},
+ {1326000000ULL, 1629068, -43435, 402},
+ {1428000000ULL, 1686950, -44715, 402},
+ {1530000000ULL, 1746653, -46005, 402},
+ {1632000000ULL, 1808179, -47285, 402},
+ {1734000000ULL, 1871526, -48575, 402},
+ {1836000000ULL, 1936696, -49855, 402},
+ {1938000000ULL, 2003687, -51145, 402},
+ {2014500000ULL, 2054787, -52095, 402},
+ {2116500000ULL, 2124957, -53385, 402},
+ {2218500000ULL, 2196950, -54665, 402},
+ {2320500000ULL, 2270765, -55955, 402},
+ {2320500000ULL, 2270765, -55955, 402},
+ {2422500000ULL, 2346401, -57235, 402},
+ {2524500000ULL, 2437299, -58535, 402},
+};
+
+static struct cpu_volt_def tegra124_cpu_volt_dpll_def =
+{
+ .min_uvolt = 900000, /* 0.9 V */
+ .max_uvolt = 1260000, /* 1.26 */
+ .step_uvolt = 10000, /* 10 mV */
+ .speedo_scale = 100,
+ .speedo_nitems = nitems(tegra124_speedo_dpll_tbl),
+ .speedo_tbl = tegra124_speedo_dpll_tbl,
+};
+
+static struct speedo_entry tegra124_speedo_pllx_tbl[] =
+{
+ { 204000000ULL, 800000, 0, 0},
+ { 306000000ULL, 800000, 0, 0},
+ { 408000000ULL, 800000, 0, 0},
+ { 510000000ULL, 800000, 0, 0},
+ { 612000000ULL, 800000, 0, 0},
+ { 714000000ULL, 800000, 0, 0},
+ { 816000000ULL, 820000, 0, 0},
+ { 918000000ULL, 840000, 0, 0},
+ {1020000000ULL, 880000, 0, 0},
+ {1122000000ULL, 900000, 0, 0},
+ {1224000000ULL, 930000, 0, 0},
+ {1326000000ULL, 960000, 0, 0},
+ {1428000000ULL, 990000, 0, 0},
+ {1530000000ULL, 1020000, 0, 0},
+ {1632000000ULL, 1070000, 0, 0},
+ {1734000000ULL, 1100000, 0, 0},
+ {1836000000ULL, 1140000, 0, 0},
+ {1938000000ULL, 1180000, 0, 0},
+ {2014500000ULL, 1220000, 0, 0},
+ {2116500000ULL, 1260000, 0, 0},
+ {2218500000ULL, 1310000, 0, 0},
+ {2320500000ULL, 1360000, 0, 0},
+ {2397000000ULL, 1400000, 0, 0},
+ {2499000000ULL, 1400000, 0, 0},
+};
+
+
+static struct cpu_volt_def tegra124_cpu_volt_pllx_def =
+{
+ .min_uvolt = 900000, /* 0.9 V */
+ .max_uvolt = 1260000, /* 1.26 */
+ .step_uvolt = 10000, /* 10 mV */
+ .speedo_scale = 100,
+ .speedo_nitems = nitems(tegra124_speedo_pllx_tbl),
+ .speedo_tbl = tegra124_speedo_pllx_tbl,
+};
+
+static uint64_t cpu_freq_tbl[] = {
+ 204000000ULL,
+ 306000000ULL,
+ 408000000ULL,
+ 510000000ULL,
+ 612000000ULL,
+ 714000000ULL,
+ 816000000ULL,
+ 918000000ULL,
+ 1020000000ULL,
+ 1122000000ULL,
+ 1224000000ULL,
+ 1326000000ULL,
+ 1428000000ULL,
+ 1530000000ULL,
+ 1632000000ULL,
+ 1734000000ULL,
+ 1836000000ULL,
+ 1938000000ULL,
+ 2014000000ULL,
+ 2116000000ULL,
+ 2218000000ULL,
+ 2320000000ULL,
+ 2320000000ULL,
+ 2422000000ULL,
+ 2524000000ULL,
+};
+
+static uint64_t cpu_max_freq[] = {
+ 2014500000ULL,
+ 2320500000ULL,
+ 2116500000ULL,
+ 2524500000ULL,
+};
+
+struct tegra124_cpufreq_softc {
+ device_t dev;
+ phandle_t node;
+
+ regulator_t supply_vdd_cpu;
+ clk_t clk_cpu_g;
+ clk_t clk_cpu_lp;
+ clk_t clk_pll_x;
+ clk_t clk_pll_p;
+ clk_t clk_dfll;
+
+ int process_id;
+ int speedo_id;
+ int speedo_value;
+
+ uint64_t cpu_max_freq;
+ struct cpu_volt_def *cpu_def;
+ struct cpu_speed_point *speed_points;
+ int nspeed_points;
+
+ struct cpu_speed_point *act_speed_point;
+
+ int latency;
+};
+
+static int cpufreq_lowest_freq = 1;
+TUNABLE_INT("hw.tegra124.cpufreq.lowest_freq", &cpufreq_lowest_freq);
+
+#define DIV_ROUND_CLOSEST(val, div) (((val) + ((div) / 2)) / (div))
+
+#define ROUND_UP(val, div) ((((val) + ((div) - 1)) / (div)) * (div))
+#define ROUND_DOWN(val, div) (((val) / (div)) * (div))
+
+/*
+ * Compute requesetd voltage for given frequency and SoC process variations,
+ * - compute base voltage from speedo value using speedo table
+ * - round up voltage to next regulator step
+ * - clamp it to regulator limits
+ */
+static int
+freq_to_voltage(struct tegra124_cpufreq_softc *sc, uint64_t freq)
+{
+ int uv, scale, min_uvolt, max_uvolt, step_uvolt;
+ struct speedo_entry *ent;
+ int i;
+
+ /* Get speedo entry with higher frequency */
+ ent = NULL;
+ for (i = 0; i < sc->cpu_def->speedo_nitems; i++) {
+ if (sc->cpu_def->speedo_tbl[i].freq >= freq) {
+ ent = &sc->cpu_def->speedo_tbl[i];
+ break;
+ }
+ }
+ if (ent == NULL)
+ ent = &sc->cpu_def->speedo_tbl[sc->cpu_def->speedo_nitems - 1];
+ scale = sc->cpu_def->speedo_scale;
+
+
+ /* uV = (c2 * speedo / scale + c1) * speedo / scale + c0) */
+ uv = DIV_ROUND_CLOSEST(ent->c2 * sc->speedo_value, scale);
+ uv = DIV_ROUND_CLOSEST((uv + ent->c1) * sc->speedo_value, scale) +
+ ent->c0;
+ step_uvolt = sc->cpu_def->step_uvolt;
+ /* Round up it to next regulator step */
+ uv = ROUND_UP(uv, step_uvolt);
+
+ /* Clamp result */
+ min_uvolt = ROUND_UP(sc->cpu_def->min_uvolt, step_uvolt);
+ max_uvolt = ROUND_DOWN(sc->cpu_def->max_uvolt, step_uvolt);
+ if (uv < min_uvolt)
+ uv = min_uvolt;
+ if (uv > max_uvolt)
+ uv = max_uvolt;
+ return (uv);
+
+}
+
+static void
+build_speed_points(struct tegra124_cpufreq_softc *sc) {
+ int i;
+
+ sc->nspeed_points = nitems(cpu_freq_tbl);
+ sc->speed_points = malloc(sizeof(struct cpu_speed_point) *
+ sc->nspeed_points, M_DEVBUF, M_NOWAIT);
+ for (i = 0; i < sc->nspeed_points; i++) {
+ sc->speed_points[i].freq = cpu_freq_tbl[i];
+ sc->speed_points[i].uvolt = freq_to_voltage(sc,
+ cpu_freq_tbl[i]);
+ }
+}
+
+static struct cpu_speed_point *
+get_speed_point(struct tegra124_cpufreq_softc *sc, uint64_t freq)
+{
+ int i;
+
+ if (sc->speed_points[0].freq >= freq)
+ return (sc->speed_points + 0);
+
+ for (i = 0; i < sc->nspeed_points - 1; i++) {
+ if (sc->speed_points[i + 1].freq > freq)
+ return (sc->speed_points + i);
+ }
+
+ return (sc->speed_points + sc->nspeed_points - 1);
+}
+
+static int
+tegra124_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)
+{
+ struct tegra124_cpufreq_softc *sc;
+ int i, j, max_cnt;
+
+ if (sets == NULL || count == NULL)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));
+
+ max_cnt = min(sc->nspeed_points, *count);
+ for (i = 0, j = sc->nspeed_points - 1; j >= 0; j--) {
+ if (sc->cpu_max_freq < sc->speed_points[j].freq)
+ continue;
+ sets[i].freq = sc->speed_points[j].freq / 1000000;
+ sets[i].volts = sc->speed_points[j].uvolt / 1000;
+ sets[i].lat = sc->latency;
+ sets[i].dev = dev;
+ i++;
+ }
+ *count = i;
+
+ return (0);
+}
+
+static int
+set_cpu_freq(struct tegra124_cpufreq_softc *sc, uint64_t freq)
+{
+ struct cpu_speed_point *point;
+ int rv;
+
+ point = get_speed_point(sc, freq);
+
+ if (sc->act_speed_point->uvolt < point->uvolt) {
+ /* set cpu voltage */
+ rv = regulator_set_voltage(sc->supply_vdd_cpu,
+ point->uvolt, point->uvolt);
+ DELAY(10000);
+ if (rv != 0)
+ return (rv);
+ }
+ rv = clk_set_freq(sc->clk_cpu_g, point->freq, CLK_SET_ROUND_DOWN);
+ if (rv != 0) {
+ device_printf(sc->dev, "Can't set CPU clock frequency\n");
+ return (rv);
+ }
+
+ if (sc->act_speed_point->uvolt > point->uvolt) {
+ /* set cpu voltage */
+ rv = regulator_set_voltage(sc->supply_vdd_cpu,
+ point->uvolt, point->uvolt);
+ if (rv != 0)
+ return (rv);
+ }
+
+ sc->act_speed_point = point;
+
+ return (0);
+}
+
+static int
+tegra124_cpufreq_set(device_t dev, const struct cf_setting *cf)
+{
+ struct tegra124_cpufreq_softc *sc;
+ uint64_t freq;
+ int rv;
+
+ if (cf == NULL || cf->freq < 0)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+
+ freq = cf->freq;
+ if (freq < cpufreq_lowest_freq)
+ freq = cpufreq_lowest_freq;
+ freq *= 1000000;
+ if (freq >= sc->cpu_max_freq)
+ freq = sc->cpu_max_freq;
+ rv = set_cpu_freq(sc, freq);
+
+ return (rv);
+}
+
+static int
+tegra124_cpufreq_get(device_t dev, struct cf_setting *cf)
+{
+ struct tegra124_cpufreq_softc *sc;
+
+ if (cf == NULL)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
+ cf->dev = NULL;
+ cf->freq = sc->act_speed_point->freq / 1000000;
+ cf->volts = sc->act_speed_point->uvolt / 1000;
+ /* Transition latency in us. */
+ cf->lat = sc->latency;
+ /* Driver providing this setting. */
+ cf->dev = dev;
+
+ return (0);
+}
+
+
+static int
+tegra124_cpufreq_type(device_t dev, int *type)
+{
+
+ if (type == NULL)
+ return (EINVAL);
+ *type = CPUFREQ_TYPE_ABSOLUTE;
+
+ return (0);
+}
+
+static int
+get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node)
+{
+ int rv;
+ device_t parent_dev;
+
+ parent_dev = device_get_parent(sc->dev);
+ rv = regulator_get_by_ofw_property(parent_dev, "vdd-cpu-supply",
+ &sc->supply_vdd_cpu);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'vdd-cpu' regulator\n");
+ return (rv);
+ }
+
+ rv = clk_get_by_ofw_name(parent_dev, "cpu_g", &sc->clk_cpu_g);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'cpu_g' clock: %d\n", rv);
+ return (ENXIO);
+ }
+
+ rv = clk_get_by_ofw_name(parent_dev, "cpu_lp", &sc->clk_cpu_lp);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'cpu_lp' clock\n");
+ return (ENXIO);
+ }
+
+ rv = clk_get_by_ofw_name(parent_dev, "pll_x", &sc->clk_pll_x);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pll_x' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(parent_dev, "pll_p", &sc->clk_pll_p);
+ if (rv != 0) {
+ device_printf(parent_dev, "Cannot get 'pll_p' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(parent_dev, "dfll", &sc->clk_dfll);
+ if (rv != 0) {
+ /* XXX DPLL is not implemented yet */
+/*
+ device_printf(sc->dev, "Cannot get 'dfll' clock\n");
+ return (ENXIO);
+*/
+ }
+ return (0);
+}
+
+static void
+tegra124_cpufreq_identify(driver_t *driver, device_t parent)
+{
+
+ if (device_find_child(parent, "tegra124_cpufreq", -1) != NULL)
+ return;
+ if (BUS_ADD_CHILD(parent, 0, "tegra124_cpufreq", -1) == NULL)
+ device_printf(parent, "add child failed\n");
+}
+
+static int
+tegra124_cpufreq_probe(device_t dev)
+{
+
+ if (device_get_unit(dev) != 0)
+ return (ENXIO);
+ device_set_desc(dev, "CPU Frequency Control");
+
+ return (0);
+}
+
+static int
+tegra124_cpufreq_attach(device_t dev)
+{
+ struct tegra124_cpufreq_softc *sc;
+ uint64_t freq;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->node = ofw_bus_get_node(device_get_parent(dev));
+
+ sc->process_id = tegra_sku_info.cpu_process_id;
+ sc->speedo_id = tegra_sku_info.cpu_speedo_id;
+ sc->speedo_value = tegra_sku_info.cpu_speedo_value;
+
+ /* Tegra 124 */
+ /* XXX DPLL is not implemented yet */
+ if (1)
+ sc->cpu_def = &tegra124_cpu_volt_pllx_def;
+ else
+ sc->cpu_def = &tegra124_cpu_volt_dpll_def;
+
+
+ rv = get_fdt_resources(sc, sc->node);
+ if (rv != 0) {
+ return (rv);
+ }
+
+ build_speed_points(sc);
+
+ rv = clk_get_freq(sc->clk_cpu_g, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Can't get CPU clock frequency\n");
+ return (rv);
+ }
+ if (sc->speedo_id < nitems(cpu_max_freq))
+ sc->cpu_max_freq = cpu_max_freq[sc->speedo_id];
+ else
+ sc->cpu_max_freq = cpu_max_freq[0];
+ sc->act_speed_point = get_speed_point(sc, freq);
+
+ /* Set safe startup CPU frequency. */
+ rv = set_cpu_freq(sc, 1632000000);
+ if (rv != 0) {
+ device_printf(dev, "Can't set initial CPU clock frequency\n");
+ return (rv);
+ }
+
+ /* This device is controlled by cpufreq(4). */
+ cpufreq_register(dev);
+
+ return (0);
+}
+
+static int
+tegra124_cpufreq_detach(device_t dev)
+{
+ struct tegra124_cpufreq_softc *sc;
+
+ sc = device_get_softc(dev);
+ cpufreq_unregister(dev);
+
+ if (sc->supply_vdd_cpu != NULL)
+ regulator_release(sc->supply_vdd_cpu);
+
+ if (sc->clk_cpu_g != NULL)
+ clk_release(sc->clk_cpu_g);
+ if (sc->clk_cpu_lp != NULL)
+ clk_release(sc->clk_cpu_lp);
+ if (sc->clk_pll_x != NULL)
+ clk_release(sc->clk_pll_x);
+ if (sc->clk_pll_p != NULL)
+ clk_release(sc->clk_pll_p);
+ if (sc->clk_dfll != NULL)
+ clk_release(sc->clk_dfll);
+ return (0);
+}
+
+static device_method_t tegra124_cpufreq_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, tegra124_cpufreq_identify),
+ DEVMETHOD(device_probe, tegra124_cpufreq_probe),
+ DEVMETHOD(device_attach, tegra124_cpufreq_attach),
+ DEVMETHOD(device_detach, tegra124_cpufreq_detach),
+
+ /* cpufreq interface */
+ DEVMETHOD(cpufreq_drv_set, tegra124_cpufreq_set),
+ DEVMETHOD(cpufreq_drv_get, tegra124_cpufreq_get),
+ DEVMETHOD(cpufreq_drv_settings, tegra124_cpufreq_settings),
+ DEVMETHOD(cpufreq_drv_type, tegra124_cpufreq_type),
+
+ DEVMETHOD_END
+};
+
+static devclass_t tegra124_cpufreq_devclass;
+static driver_t tegra124_cpufreq_driver = {
+ "tegra124_cpufreq",
+ tegra124_cpufreq_methods,
+ sizeof(struct tegra124_cpufreq_softc),
+};
+
+DRIVER_MODULE(tegra124_cpufreq, cpu, tegra124_cpufreq_driver,
+ tegra124_cpufreq_devclass, 0, 0);
diff --git a/sys/arm/nvidia/tegra124/tegra124_machdep.c b/sys/arm/nvidia/tegra124/tegra124_machdep.c
new file mode 100644
index 0000000..e74a05b
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_machdep.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/reboot.h>
+
+#include <vm/vm.h>
+
+#include <machine/bus.h>
+#include <machine/devmap.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+#include <machine/machdep.h>
+#include <machine/platformvar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <arm/nvidia/tegra124/tegra124_mp.h>
+
+#include "platform_if.h"
+
+#define PMC_PHYSBASE 0x7000e400
+#define PMC_SIZE 0x400
+#define PMC_CONTROL_REG 0x0
+#define PMC_SCRATCH0 0x50
+#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
+#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
+#define PMC_SCRATCH0_MODE_RCM (1 << 1)
+#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
+ PMC_SCRATCH0_MODE_BOOTLOADER | \
+ PMC_SCRATCH0_MODE_RCM)
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+static vm_offset_t
+tegra124_lastaddr(platform_t plat)
+{
+
+ return (arm_devmap_lastaddr());
+}
+
+static int
+tegra124_attach(platform_t plat)
+{
+
+ return (0);
+}
+
+static void
+tegra124_late_init(platform_t plat)
+{
+
+}
+
+/*
+ * Set up static device mappings.
+ *
+ */
+static int
+tegra124_devmap_init(platform_t plat)
+{
+
+ arm_devmap_add_entry(0x70000000, 0x01000000);
+ return (0);
+}
+
+void
+cpu_reset(void)
+{
+ bus_space_handle_t pmc;
+ uint32_t reg;
+
+ printf("Resetting...\n");
+ bus_space_map(fdtbus_bs_tag, PMC_PHYSBASE, PMC_SIZE, 0, &pmc);
+
+ reg = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0);
+ reg &= PMC_SCRATCH0_MODE_MASK;
+ bus_space_write_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0,
+ reg | PMC_SCRATCH0_MODE_BOOTLOADER); /* boot to bootloader */
+ bus_space_read_4(fdtbus_bs_tag, pmc, PMC_SCRATCH0);
+
+ reg = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG);
+ spinlock_enter();
+ dsb();
+ bus_space_write_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG, reg | 0x10);
+ bus_space_read_4(fdtbus_bs_tag, pmc, PMC_CONTROL_REG);
+ while(1)
+ ;
+
+}
+
+/*
+ * Early putc routine for EARLY_PRINTF support. To use, add to kernel config:
+ * option SOCDEV_PA=0x02000000
+ * option SOCDEV_VA=0x02000000
+ * option EARLY_PRINTF
+ */
+#if 0
+static void
+tegra124_early_putc(int c)
+{
+ volatile uint32_t * UART_STAT_REG = (uint32_t *)0x02020098;
+ volatile uint32_t * UART_TX_REG = (uint32_t *)0x02020040;
+ const uint32_t UART_TXRDY = (1 << 3);
+
+ while ((*UART_STAT_REG & UART_TXRDY) == 0)
+ continue;
+ *UART_TX_REG = c;
+}
+early_putc_t *early_putc = tegra124_early_putc;
+#endif
+
+static platform_method_t tegra124_methods[] = {
+ PLATFORMMETHOD(platform_attach, tegra124_attach),
+ PLATFORMMETHOD(platform_lastaddr, tegra124_lastaddr),
+ PLATFORMMETHOD(platform_devmap_init, tegra124_devmap_init),
+ PLATFORMMETHOD(platform_late_init, tegra124_late_init),
+#ifdef SMP
+ PLATFORMMETHOD(platform_mp_start_ap, tegra124_mp_start_ap),
+ PLATFORMMETHOD(platform_mp_setmaxid, tegra124_mp_setmaxid),
+#endif
+ PLATFORMMETHOD_END,
+};
+
+FDT_PLATFORM_DEF(tegra124, "Nvidia Jetson-TK1", 0, "nvidia,jetson-tk1");
diff --git a/sys/arm/nvidia/tegra124/tegra124_mp.c b/sys/arm/nvidia/tegra124/tegra124_mp.c
new file mode 100644
index 0000000..36b3b7c
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_mp.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/cpu.h>
+#include <machine/intr.h>
+#include <machine/fdt.h>
+#include <machine/smp.h>
+#include <machine/platformvar.h>
+#include <machine/pmap.h>
+
+#include <arm/nvidia/tegra124/tegra124_mp.h>
+
+#define PMC_PHYSBASE 0x7000e400
+#define PMC_SIZE 0x400
+#define PMC_CONTROL_REG 0x0
+#define PMC_PWRGATE_TOGGLE 0x30
+#define PCM_PWRGATE_TOGGLE_START (1 << 8)
+#define PMC_PWRGATE_STATUS 0x38
+
+#define TEGRA_EXCEPTION_VECTORS_BASE 0x6000F000 /* exception vectors */
+#define TEGRA_EXCEPTION_VECTORS_SIZE 1024
+#define TEGRA_EXCEPTION_VECTOR_ENTRY 0x100
+
+void
+tegra124_mp_setmaxid(platform_t plat)
+{
+ int ncpu;
+
+ /* If we've already set the global vars don't bother to do it again. */
+ if (mp_ncpus != 0)
+ return;
+
+ /* Read current CP15 Cache Size ID Register */
+ ncpu = cp15_l2ctlr_get();
+ ncpu = CPUV7_L2CTLR_NPROC(ncpu);
+
+ mp_ncpus = ncpu;
+ mp_maxid = ncpu - 1;
+}
+
+void
+tegra124_mp_start_ap(platform_t plat)
+{
+ bus_space_handle_t pmc;
+ bus_space_handle_t exvec;
+ int i;
+ uint32_t val;
+ uint32_t mask;
+
+ if (bus_space_map(fdtbus_bs_tag, PMC_PHYSBASE, PMC_SIZE, 0, &pmc) != 0)
+ panic("Couldn't map the PMC\n");
+ if (bus_space_map(fdtbus_bs_tag, TEGRA_EXCEPTION_VECTORS_BASE,
+ TEGRA_EXCEPTION_VECTORS_SIZE, 0, &exvec) != 0)
+ panic("Couldn't map the exception vectors\n");
+
+ bus_space_write_4(fdtbus_bs_tag, exvec , TEGRA_EXCEPTION_VECTOR_ENTRY,
+ pmap_kextract((vm_offset_t)mpentry));
+ bus_space_read_4(fdtbus_bs_tag, exvec , TEGRA_EXCEPTION_VECTOR_ENTRY);
+
+
+ /* Wait until POWERGATE is ready (max 20 APB cycles). */
+ do {
+ val = bus_space_read_4(fdtbus_bs_tag, pmc,
+ PMC_PWRGATE_TOGGLE);
+ } while ((val & PCM_PWRGATE_TOGGLE_START) != 0);
+
+ for (i = 1; i < mp_ncpus; i++) {
+ val = bus_space_read_4(fdtbus_bs_tag, pmc, PMC_PWRGATE_STATUS);
+ mask = 1 << (i + 8); /* cpu mask */
+ if ((val & mask) == 0) {
+ /* Wait until POWERGATE is ready (max 20 APB cycles). */
+ do {
+ val = bus_space_read_4(fdtbus_bs_tag, pmc,
+ PMC_PWRGATE_TOGGLE);
+ } while ((val & PCM_PWRGATE_TOGGLE_START) != 0);
+ bus_space_write_4(fdtbus_bs_tag, pmc,
+ PMC_PWRGATE_TOGGLE,
+ PCM_PWRGATE_TOGGLE_START | (8 + i));
+
+ /* Wait until CPU is powered */
+ do {
+ val = bus_space_read_4(fdtbus_bs_tag, pmc,
+ PMC_PWRGATE_STATUS);
+ } while ((val & mask) == 0);
+ }
+
+ }
+ armv7_sev();
+ bus_space_unmap(fdtbus_bs_tag, pmc, PMC_SIZE);
+ bus_space_unmap(fdtbus_bs_tag, exvec, TEGRA_EXCEPTION_VECTORS_SIZE);
+}
diff --git a/sys/compat/cloudabi/cloudabi_syscalldefs.h b/sys/arm/nvidia/tegra124/tegra124_mp.h
index fc86eff..57785aa 100644
--- a/sys/compat/cloudabi/cloudabi_syscalldefs.h
+++ b/sys/arm/nvidia/tegra124/tegra124_mp.h
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,24 +26,10 @@
* $FreeBSD$
*/
-#ifndef _CLOUDABI_SYSCALLDEFS_H_
-#define _CLOUDABI_SYSCALLDEFS_H_
+#ifndef _TEGRA124_MP_H_
+#define _TEGRA124_MP_H_
-#ifdef _KERNEL
-#include <sys/types.h>
-#include <sys/stdint.h>
+void tegra124_mp_setmaxid(platform_t plat);
+void tegra124_mp_start_ap(platform_t plat);
-#define alignas _Alignas
-#define alignof _Alignof
-#define static_assert _Static_assert
-#else
-#include <assert.h>
-#include <stdalign.h>
-#include <stddef.h>
-#include <stdint.h>
-#endif
-
-/* Import machine-independent CloudABI definitions. */
-#include <contrib/cloudabi/syscalldefs_mi.h>
-
-#endif
+#endif /*_TEGRA124_MP_H_*/ \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra124/tegra124_pmc.c b/sys/arm/nvidia/tegra124/tegra124_pmc.c
new file mode 100644
index 0000000..7ff7307
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_pmc.c
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_pmc.h>
+
+#define PMC_CNTRL 0x000
+#define PMC_CNTRL_CPUPWRGOOD_SEL_MASK (0x3 << 20)
+#define PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT 20
+#define PMC_CNTRL_CPUPWRGOOD_EN (1 << 19)
+#define PMC_CNTRL_FUSE_OVERRIDE (1 << 18)
+#define PMC_CNTRL_INTR_POLARITY (1 << 17)
+#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16)
+#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15)
+#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14)
+#define PMC_CNTRL_AOINIT (1 << 13)
+#define PMC_CNTRL_PWRGATE_DIS (1 << 12)
+#define PMC_CNTRL_SYSCLK_OE (1 << 11)
+#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10)
+#define PMC_CNTRL_PWRREQ_OE (1 << 9)
+#define PMC_CNTRL_PWRREQ_POLARITY (1 << 8)
+#define PMC_CNTRL_BLINK_EN (1 << 7)
+#define PMC_CNTRL_GLITCHDET_DIS (1 << 6)
+#define PMC_CNTRL_LATCHWAKE_EN (1 << 5)
+#define PMC_CNTRL_MAIN_RST (1 << 4)
+#define PMC_CNTRL_KBC_RST (1 << 3)
+#define PMC_CNTRL_RTC_RST (1 << 2)
+#define PMC_CNTRL_RTC_CLK_DIS (1 << 1)
+#define PMC_CNTRL_KBC_CLK_DIS (1 << 0)
+
+#define PMC_DPD_SAMPLE 0x020
+
+#define PMC_CLAMP_STATUS 0x02C
+#define PMC_CLAMP_STATUS_PARTID(x) (1 << ((x) & 0x1F))
+
+#define PMC_PWRGATE_TOGGLE 0x030
+#define PMC_PWRGATE_TOGGLE_START (1 << 8)
+#define PMC_PWRGATE_TOGGLE_PARTID(x) (((x) & 0x1F) << 0)
+
+#define PMC_REMOVE_CLAMPING_CMD 0x034
+#define PMC_REMOVE_CLAMPING_CMD_PARTID(x) (1 << ((x) & 0x1F))
+
+#define PMC_PWRGATE_STATUS 0x038
+#define PMC_PWRGATE_STATUS_PARTID(x) (1 << ((x) & 0x1F))
+
+#define PMC_SCRATCH0 0x050
+#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31)
+#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30)
+#define PMC_SCRATCH0_MODE_RCM (1 << 1)
+#define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \
+ PMC_SCRATCH0_MODE_BOOTLOADER | \
+ PMC_SCRATCH0_MODE_RCM)
+
+#define PMC_CPUPWRGOOD_TIMER 0x0c8
+#define PMC_CPUPWROFF_TIMER 0x0cc
+
+#define PMC_SCRATCH41 0x140
+
+#define PMC_SENSOR_CTRL 0x1b0
+#define PMC_SENSOR_CTRL_BLOCK_SCRATCH_WRITE (1 << 2)
+#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
+#define PMC_SENSOR_CTRL_ENABLE_PG (1 << 0)
+
+#define PMC_IO_DPD_REQ 0x1b8
+#define PMC_IO_DPD_REQ_CODE_IDLE (0 << 30)
+#define PMC_IO_DPD_REQ_CODE_OFF (1 << 30)
+#define PMC_IO_DPD_REQ_CODE_ON (2 << 30)
+#define PMC_IO_DPD_REQ_CODE_MASK (3 << 30)
+
+#define PMC_IO_DPD_STATUS 0x1bc
+#define PMC_IO_DPD_STATUS_HDMI (1 << 28)
+#define PMC_IO_DPD2_REQ 0x1c0
+#define PMC_IO_DPD2_STATUS 0x1c4
+#define PMC_IO_DPD2_STATUS_HV (1 << 6)
+#define PMC_SEL_DPD_TIM 0x1c8
+
+#define PMC_SCRATCH54 0x258
+#define PMC_SCRATCH54_DATA_SHIFT 8
+#define PMC_SCRATCH54_ADDR_SHIFT 0
+
+#define PMC_SCRATCH55 0x25c
+#define PMC_SCRATCH55_RST_ENABLE (1 << 31)
+#define PMC_SCRATCH55_CNTRL_TYPE (1 << 30)
+#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
+#define PMC_SCRATCH55_CNTRL_ID_MASK 0x07
+#define PMC_SCRATCH55_PINMUX_SHIFT 24
+#define PMC_SCRATCH55_PINMUX_MASK 0x07
+#define PMC_SCRATCH55_CHECKSUM_SHIFT 16
+#define PMC_SCRATCH55_CHECKSUM_MASK 0xFF
+#define PMC_SCRATCH55_16BITOP (1 << 15)
+#define PMC_SCRATCH55_I2CSLV1_SHIFT 0
+#define PMC_SCRATCH55_I2CSLV1_MASK 0x7F
+
+#define PMC_GPU_RG_CNTRL 0x2d4
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
+
+#define PMC_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define PMC_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define PMC_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
+ device_get_nameunit(_sc->dev), "tegra124_pmc", MTX_DEF)
+#define PMC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx);
+#define PMC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED);
+#define PMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED);
+
+struct tegra124_pmc_softc {
+ device_t dev;
+ struct resource *mem_res;
+ clk_t clk;
+ struct mtx mtx;
+
+ uint32_t rate;
+ enum tegra_suspend_mode suspend_mode;
+ uint32_t cpu_good_time;
+ uint32_t cpu_off_time;
+ uint32_t core_osc_time;
+ uint32_t core_pmu_time;
+ uint32_t core_off_time;
+ int corereq_high;
+ int sysclkreq_high;
+ int combined_req;
+ int cpu_pwr_good_en;
+ uint32_t lp0_vec_phys;
+ uint32_t lp0_vec_size;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-pmc", 1},
+ {NULL, 0},
+};
+
+static struct tegra124_pmc_softc *pmc_sc;
+
+static inline struct tegra124_pmc_softc *
+tegra124_pmc_get_sc(void)
+{
+ if (pmc_sc == NULL)
+ panic("To early call to Tegra PMC driver.\n");
+ return (pmc_sc);
+}
+
+static int
+tegra124_pmc_set_powergate(struct tegra124_pmc_softc *sc,
+ enum tegra_powergate_id id, int ena)
+{
+ uint32_t reg;
+ int i;
+
+ PMC_LOCK(sc);
+
+ reg = RD4(sc, PMC_PWRGATE_STATUS) & PMC_PWRGATE_STATUS_PARTID(id);
+ if (((reg != 0) && ena) || ((reg == 0) && !ena)) {
+ PMC_UNLOCK(sc);
+ return (0);
+ }
+
+ for (i = 100; i > 0; i--) {
+ reg = RD4(sc, PMC_PWRGATE_TOGGLE);
+ if ((reg & PMC_PWRGATE_TOGGLE_START) == 0)
+ break;
+ DELAY(1);
+ }
+ if (i <= 0)
+ device_printf(sc->dev,
+ "Timeout when waiting for TOGGLE_START\n");
+
+ WR4(sc, PMC_PWRGATE_TOGGLE,
+ PMC_PWRGATE_TOGGLE_START | PMC_PWRGATE_TOGGLE_PARTID(id));
+
+ for (i = 100; i > 0; i--) {
+ reg = RD4(sc, PMC_PWRGATE_TOGGLE);
+ if ((reg & PMC_PWRGATE_TOGGLE_START) == 0)
+ break;
+ DELAY(1);
+ }
+ if (i <= 0)
+ device_printf(sc->dev,
+ "Timeout when waiting for TOGGLE_START\n");
+ PMC_UNLOCK(sc);
+ return (0);
+}
+
+int
+tegra_powergate_remove_clamping(enum tegra_powergate_id id)
+{
+ struct tegra124_pmc_softc *sc;
+ uint32_t reg;
+ enum tegra_powergate_id swid;
+ int i;
+
+ sc = tegra124_pmc_get_sc();
+
+ if (id == TEGRA_POWERGATE_3D) {
+ WR4(sc, PMC_GPU_RG_CNTRL, 0);
+ return (0);
+ }
+
+ reg = RD4(sc, PMC_PWRGATE_STATUS);
+ if ((reg & PMC_PWRGATE_STATUS_PARTID(id)) == 0)
+ panic("Attempt to remove clamping for unpowered partition.\n");
+
+ if (id == TEGRA_POWERGATE_PCX)
+ swid = TEGRA_POWERGATE_VDE;
+ else if (id == TEGRA_POWERGATE_VDE)
+ swid = TEGRA_POWERGATE_PCX;
+ else
+ swid = id;
+ WR4(sc, PMC_REMOVE_CLAMPING_CMD, PMC_REMOVE_CLAMPING_CMD_PARTID(swid));
+
+ for (i = 100; i > 0; i--) {
+ reg = RD4(sc, PMC_REMOVE_CLAMPING_CMD);
+ if ((reg & PMC_REMOVE_CLAMPING_CMD_PARTID(swid)) == 0)
+ break;
+ DELAY(1);
+ }
+ if (i <= 0)
+ device_printf(sc->dev, "Timeout when remove clamping\n");
+
+ reg = RD4(sc, PMC_CLAMP_STATUS);
+ if ((reg & PMC_CLAMP_STATUS_PARTID(id)) != 0)
+ panic("Cannot remove clamping\n");
+
+ return (0);
+}
+
+int
+tegra_powergate_is_powered(enum tegra_powergate_id id)
+{
+ struct tegra124_pmc_softc *sc;
+ uint32_t reg;
+
+ sc = tegra124_pmc_get_sc();
+
+ reg = RD4(sc, PMC_PWRGATE_STATUS);
+ return ((reg & PMC_PWRGATE_STATUS_PARTID(id)) ? 1 : 0);
+}
+
+int
+tegra_powergate_power_on(enum tegra_powergate_id id)
+{
+ struct tegra124_pmc_softc *sc;
+ int rv, i;
+
+ sc = tegra124_pmc_get_sc();
+
+ rv = tegra124_pmc_set_powergate(sc, id, 1);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot set powergate: %d\n", id);
+ return (rv);
+ }
+
+ for (i = 100; i > 0; i--) {
+ if (tegra_powergate_is_powered(id))
+ break;
+ DELAY(1);
+ }
+ if (i <= 0)
+ device_printf(sc->dev, "Timeout when waiting on power up\n");
+
+ return (rv);
+}
+
+int
+tegra_powergate_power_off(enum tegra_powergate_id id)
+{
+ struct tegra124_pmc_softc *sc;
+ int rv, i;
+
+ sc = tegra124_pmc_get_sc();
+
+ rv = tegra124_pmc_set_powergate(sc, id, 0);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot set powergate: %d\n", id);
+ return (rv);
+ }
+ for (i = 100; i > 0; i--) {
+ if (!tegra_powergate_is_powered(id))
+ break;
+ DELAY(1);
+ }
+ if (i <= 0)
+ device_printf(sc->dev, "Timeout when waiting on power off\n");
+
+ return (rv);
+}
+
+int
+tegra_powergate_sequence_power_up(enum tegra_powergate_id id, clk_t clk,
+ hwreset_t rst)
+{
+ struct tegra124_pmc_softc *sc;
+ int rv;
+
+ sc = tegra124_pmc_get_sc();
+
+ rv = hwreset_assert(rst);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert reset\n");
+ return (rv);
+ }
+
+ rv = clk_stop(clk);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot stop clock\n");
+ goto clk_fail;
+ }
+
+ rv = tegra_powergate_power_on(id);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot power on powergate\n");
+ goto clk_fail;
+ }
+
+ rv = clk_enable(clk);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable clock\n");
+ goto clk_fail;
+ }
+ DELAY(20);
+
+ rv = tegra_powergate_remove_clamping(id);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot remove clamping\n");
+ goto fail;
+ }
+ rv = hwreset_deassert(rst);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot unreset reset\n");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ clk_disable(clk);
+clk_fail:
+ hwreset_assert(rst);
+ tegra_powergate_power_off(id);
+ return (rv);
+}
+
+static int
+tegra124_pmc_parse_fdt(struct tegra124_pmc_softc *sc, phandle_t node)
+{
+ int rv;
+ uint32_t tmp;
+ uint32_t tmparr[2];
+
+ rv = OF_getencprop(node, "nvidia,suspend-mode", &tmp, sizeof(tmp));
+ if (rv > 0) {
+ switch (tmp) {
+ case 0:
+ sc->suspend_mode = TEGRA_SUSPEND_LP0;
+ break;
+
+ case 1:
+ sc->suspend_mode = TEGRA_SUSPEND_LP1;
+ break;
+
+ case 2:
+ sc->suspend_mode = TEGRA_SUSPEND_LP2;
+ break;
+
+ default:
+ sc->suspend_mode = TEGRA_SUSPEND_NONE;
+ break;
+ }
+ }
+
+ rv = OF_getencprop(node, "nvidia,cpu-pwr-good-time", &tmp, sizeof(tmp));
+ if (rv > 0) {
+ sc->cpu_good_time = tmp;
+ sc->suspend_mode = TEGRA_SUSPEND_NONE;
+ }
+
+ rv = OF_getencprop(node, "nvidia,cpu-pwr-off-time", &tmp, sizeof(tmp));
+ if (rv > 0) {
+ sc->cpu_off_time = tmp;
+ sc->suspend_mode = TEGRA_SUSPEND_NONE;
+ }
+
+ rv = OF_getencprop(node, "nvidia,core-pwr-good-time", tmparr,
+ sizeof(tmparr));
+ if (rv == sizeof(tmparr)) {
+ sc->core_osc_time = tmparr[0];
+ sc->core_pmu_time = tmparr[1];
+ sc->suspend_mode = TEGRA_SUSPEND_NONE;
+ }
+
+ rv = OF_getencprop(node, "nvidia,core-pwr-off-time", &tmp, sizeof(tmp));
+ if (rv > 0) {
+ sc->core_off_time = tmp;
+ sc->suspend_mode = TEGRA_SUSPEND_NONE;
+ }
+
+ sc->corereq_high =
+ OF_hasprop(node, "nvidia,core-power-req-active-high");
+ sc->sysclkreq_high =
+ OF_hasprop(node, "nvidia,sys-clock-req-active-high");
+ sc->combined_req =
+ OF_hasprop(node, "nvidia,combined-power-req");
+ sc->cpu_pwr_good_en =
+ OF_hasprop(node, "nvidia,cpu-pwr-good-en");
+
+ rv = OF_getencprop(node, "nvidia,lp0-vec", tmparr, sizeof(tmparr));
+ if (rv == sizeof(tmparr)) {
+
+ sc->lp0_vec_phys = tmparr[0];
+ sc->core_pmu_time = tmparr[1];
+ sc->lp0_vec_size = TEGRA_SUSPEND_NONE;
+ if (sc->suspend_mode == TEGRA_SUSPEND_LP0)
+ sc->suspend_mode = TEGRA_SUSPEND_LP1;
+ }
+ return 0;
+}
+
+static int
+tegra124_pmc_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Tegra PMC");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra124_pmc_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static int
+tegra124_pmc_attach(device_t dev)
+{
+ struct tegra124_pmc_softc *sc;
+ int rid, rv;
+ uint32_t reg;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+
+ rv = tegra124_pmc_parse_fdt(sc, node);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse FDT data\n");
+ return (rv);
+ }
+
+ rv = clk_get_by_ofw_name(sc->dev, "pclk", &sc->clk);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get \"pclk\" clock\n");
+ return (ENXIO);
+ }
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ PMC_LOCK_INIT(sc);
+
+ /* Enable CPU power request. */
+ reg = RD4(sc, PMC_CNTRL);
+ reg |= PMC_CNTRL_CPU_PWRREQ_OE;
+ WR4(sc, PMC_CNTRL, reg);
+
+ /* Set sysclk output polarity */
+ reg = RD4(sc, PMC_CNTRL);
+ if (sc->sysclkreq_high)
+ reg &= ~PMC_CNTRL_SYSCLK_POLARITY;
+ else
+ reg |= PMC_CNTRL_SYSCLK_POLARITY;
+ WR4(sc, PMC_CNTRL, reg);
+
+ /* Enable sysclk request. */
+ reg = RD4(sc, PMC_CNTRL);
+ reg |= PMC_CNTRL_SYSCLK_OE;
+ WR4(sc, PMC_CNTRL, reg);
+
+ /*
+ * Remove HDMI from deep power down mode.
+ * XXX mote this to HDMI driver
+ */
+ reg = RD4(sc, PMC_IO_DPD_STATUS);
+ reg &= ~ PMC_IO_DPD_STATUS_HDMI;
+ WR4(sc, PMC_IO_DPD_STATUS, reg);
+
+ reg = RD4(sc, PMC_IO_DPD2_STATUS);
+ reg &= ~ PMC_IO_DPD2_STATUS_HV;
+ WR4(sc, PMC_IO_DPD2_STATUS, reg);
+
+ if (pmc_sc != NULL)
+ panic("tegra124_pmc: double driver attach");
+ pmc_sc = sc;
+ return (0);
+}
+
+static device_method_t tegra124_pmc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra124_pmc_probe),
+ DEVMETHOD(device_attach, tegra124_pmc_attach),
+ DEVMETHOD(device_detach, tegra124_pmc_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra124_pmc_driver = {
+ "tegra124_pmc",
+ tegra124_pmc_methods,
+ sizeof(struct tegra124_pmc_softc),
+};
+
+static devclass_t tegra124_pmc_devclass;
+EARLY_DRIVER_MODULE(tegra124_pmc, simplebus, tegra124_pmc_driver,
+ tegra124_pmc_devclass, 0, 0, 70);
diff --git a/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c b/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c
new file mode 100644
index 0000000..e06d4bf
--- /dev/null
+++ b/sys/arm/nvidia/tegra124/tegra124_xusbpadctl.c
@@ -0,0 +1,603 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <gnu/dts/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+
+#include "phy_if.h"
+
+#define XUSB_PADCTL_USB2_PAD_MUX 0x004
+
+#define XUSB_PADCTL_ELPG_PROGRAM 0x01C
+#define ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
+#define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
+#define ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
+#define IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
+#define IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf<< 12)
+#define IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
+#define IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
+#define IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
+#define IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
+
+
+#define XUSB_PADCTL_USB3_PAD_MUX 0x134
+
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
+#define IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
+#define IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
+#define IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
+#define IOPHY_PLL_S0_CTL1_PLL_RST_L (1 << 1)
+#define IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
+
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL2 0x13C
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL3 0x140
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL4 0x144
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
+#define IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
+#define IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14C
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL3 0x150
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL4 0x154
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15C
+
+struct lane_cfg {
+ char *function;
+ char **lanes;
+ int iddq;
+};
+
+struct xusbpadctl_softc {
+ device_t dev;
+ struct resource *mem_res;
+ hwreset_t rst;
+ int phy_ena_cnt;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-xusb-padctl", 1},
+ {NULL, 0},
+};
+
+struct padctl_lane {
+ const char *name;
+ bus_size_t reg;
+ uint32_t shift;
+ uint32_t mask;
+ int iddq;
+ char **mux;
+ int nmux;
+};
+
+static char *otg_mux[] = {"snps", "xusb", "uart", "rsvd"};
+static char *usb_mux[] = {"snps", "xusb"};
+static char *pci_mux[] = {"pcie", "usb3", "sata", "rsvd"};
+
+#define LANE(n, r, s, m, i, mx) \
+{ \
+ .name = n, \
+ .reg = r, \
+ .shift = s, \
+ .mask = m, \
+ .iddq = i, \
+ .mux = mx, \
+ .nmux = nitems(mx), \
+}
+
+static const struct padctl_lane lanes_tbl[] = {
+ LANE("otg-0", XUSB_PADCTL_USB2_PAD_MUX, 0, 0x3, -1, otg_mux),
+ LANE("otg-1", XUSB_PADCTL_USB2_PAD_MUX, 2, 0x3, -1, otg_mux),
+ LANE("otg-2", XUSB_PADCTL_USB2_PAD_MUX, 4, 0x3, -1, otg_mux),
+ LANE("ulpi-0", XUSB_PADCTL_USB2_PAD_MUX, 12, 0x1, -1, usb_mux),
+ LANE("hsic-0", XUSB_PADCTL_USB2_PAD_MUX, 14, 0x1, -1, usb_mux),
+ LANE("hsic-1", XUSB_PADCTL_USB2_PAD_MUX, 15, 0x1, -1, usb_mux),
+ LANE("pcie-0", XUSB_PADCTL_USB3_PAD_MUX, 16, 0x3, 1, pci_mux),
+ LANE("pcie-1", XUSB_PADCTL_USB3_PAD_MUX, 18, 0x3, 2, pci_mux),
+ LANE("pcie-2", XUSB_PADCTL_USB3_PAD_MUX, 20, 0x3, 3, pci_mux),
+ LANE("pcie-3", XUSB_PADCTL_USB3_PAD_MUX, 22, 0x3, 4, pci_mux),
+ LANE("pcie-4", XUSB_PADCTL_USB3_PAD_MUX, 24, 0x3, 5, pci_mux),
+ LANE("sata-0", XUSB_PADCTL_USB3_PAD_MUX, 26, 0x3, 6, pci_mux),
+};
+
+static int
+xusbpadctl_mux_function(const struct padctl_lane *lane, char *fnc_name)
+{
+ int i;
+
+ for (i = 0; i < lane->nmux; i++) {
+ if (strcmp(fnc_name, lane->mux[i]) == 0)
+ return (i);
+ }
+
+ return (-1);
+}
+
+static int
+xusbpadctl_config_lane(struct xusbpadctl_softc *sc, char *lane_name,
+ const struct padctl_lane *lane, struct lane_cfg *cfg)
+{
+
+ int tmp;
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mem_res, lane->reg);
+ if (cfg->function != NULL) {
+ tmp = xusbpadctl_mux_function(lane, cfg->function);
+ if (tmp == -1) {
+ device_printf(sc->dev,
+ "Unknown function %s for lane %s\n", cfg->function,
+ lane_name);
+ return (EINVAL);
+ }
+ reg &= ~(lane->mask << lane->shift);
+ reg |= (tmp & lane->mask) << lane->shift;
+ }
+ if (cfg->iddq != -1) {
+ if (lane->iddq == -1) {
+ device_printf(sc->dev, "Invalid IDDQ for lane %s\n",
+ lane_name);
+ return (EINVAL);
+ }
+ if (cfg->iddq != 0)
+ reg &= ~(1 << lane->iddq);
+ else
+ reg |= 1 << lane->iddq;
+ }
+
+ bus_write_4(sc->mem_res, lane->reg, reg);
+ return (0);
+}
+
+static const struct padctl_lane *
+xusbpadctl_search_lane(char *lane_name)
+{
+ int i;
+
+ for (i = 0; i < nitems(lanes_tbl); i++) {
+ if (strcmp(lane_name, lanes_tbl[i].name) == 0)
+ return (&lanes_tbl[i]);
+ }
+
+ return (NULL);
+}
+
+static int
+xusbpadctl_config_node(struct xusbpadctl_softc *sc, char *lane_name,
+ struct lane_cfg *cfg)
+{
+ const struct padctl_lane *lane;
+ int rv;
+
+ lane = xusbpadctl_search_lane(lane_name);
+ if (lane == NULL) {
+ device_printf(sc->dev, "Unknown lane: %s\n", lane_name);
+ return (ENXIO);
+ }
+ rv = xusbpadctl_config_lane(sc, lane_name, lane, cfg);
+ return (rv);
+}
+
+static int
+xusbpadctl_read_node(struct xusbpadctl_softc *sc, phandle_t node,
+ struct lane_cfg *cfg, char **lanes, int *llanes)
+{
+ int rv;
+
+ *llanes = OF_getprop_alloc(node, "nvidia,lanes", 1, (void **)lanes);
+ if (*llanes <= 0)
+ return (ENOENT);
+
+ /* Read function (mux) settings. */
+ rv = OF_getprop_alloc(node, "nvidia,function", 1,
+ (void **)&cfg->function);
+ if (rv <= 0)
+ cfg->function = NULL;
+ /* Read numeric properties. */
+ rv = OF_getencprop(node, "nvidia,iddq", &cfg->iddq,
+ sizeof(cfg->iddq));
+ if (rv <= 0)
+ cfg->iddq = -1;
+ return (0);
+}
+
+static int
+xusbpadctl_process_node(struct xusbpadctl_softc *sc, phandle_t node)
+{
+ struct lane_cfg cfg;
+ char *lanes, *lname;
+ int i, len, llanes, rv;
+
+ rv = xusbpadctl_read_node(sc, node, &cfg, &lanes, &llanes);
+ if (rv != 0)
+ return (rv);
+
+ len = 0;
+ lname = lanes;
+ do {
+ i = strlen(lname) + 1;
+ rv = xusbpadctl_config_node(sc, lname, &cfg);
+ if (rv != 0)
+ device_printf(sc->dev,
+ "Cannot configure lane: %s: %d\n", lname, rv);
+
+ len += i;
+ lname += i;
+ } while (len < llanes);
+
+ if (lanes != NULL)
+ free(lanes, M_OFWPROP);
+ if (cfg.function != NULL)
+ free(cfg.function, M_OFWPROP);
+ return (rv);
+}
+
+
+static int
+xusbpadctl_pinctrl_cfg(device_t dev, phandle_t cfgxref)
+{
+ struct xusbpadctl_softc *sc;
+ phandle_t node, cfgnode;
+ int rv;
+
+ sc = device_get_softc(dev);
+ cfgnode = OF_node_from_xref(cfgxref);
+
+ rv = 0;
+ for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
+ if (!fdt_is_enabled(node))
+ continue;
+ rv = xusbpadctl_process_node(sc, node);
+ if (rv != 0)
+ return (rv);
+ }
+
+ return (rv);
+}
+
+static int
+xusbpadctl_phy_pcie_powerup(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+ int i;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+ reg &= ~IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+ reg |= IOPHY_PLL_P0_CTL2_REFCLKBUF_EN;
+ reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_EN;
+ reg |= IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL2, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+ reg |= IOPHY_PLL_P0_CTL1_PLL_RST;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+ DELAY(100);
+
+ for (i = 0; i < 100; i++) {
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+ if (reg & IOPHY_PLL_P0_CTL1_PLL0_LOCKDET)
+ return (0);
+ DELAY(10);
+ }
+
+ return (ETIMEDOUT);
+}
+
+
+static int
+xusbpadctl_phy_pcie_powerdown(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+ reg &= ~IOPHY_PLL_P0_CTL1_PLL_RST;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_P0_CTL1, reg);
+ DELAY(100);
+ return (0);
+
+}
+
+static int
+xusbpadctl_phy_sata_powerup(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+ int i;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+ reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+ reg &= ~IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg &= ~IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+ reg &= ~IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg |= IOPHY_PLL_S0_CTL1_PLL1_MODE;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg |= IOPHY_PLL_S0_CTL1_PLL_RST_L;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+
+ for (i = 100; i >= 0; i--) {
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ if (reg & IOPHY_PLL_S0_CTL1_PLL1_LOCKDET)
+ break;
+ DELAY(100);
+ }
+ if (i <= 0) {
+ device_printf(sc->dev, "Failed to power up SATA phy\n");
+ return (ETIMEDOUT);
+ }
+
+ return (0);
+}
+
+static int
+xusbpadctl_phy_sata_powerdown(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg &= ~IOPHY_PLL_S0_CTL1_PLL_RST_L;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg &= ~IOPHY_PLL_S0_CTL1_PLL1_MODE;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+ reg |= IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+ reg |= IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_PLL_S0_CTL1, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+ reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+ reg |= IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1, reg);
+ DELAY(100);
+
+ return (0);
+}
+
+static int
+xusbpadctl_phy_powerup(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg &= ~ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ return (0);
+}
+
+static int
+xusbpadctl_phy_powerdown(struct xusbpadctl_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg |= ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ reg = bus_read_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM);
+ reg |= ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+ bus_write_4(sc->mem_res, XUSB_PADCTL_ELPG_PROGRAM, reg);
+ DELAY(100);
+
+ return (0);
+}
+
+static int
+xusbpadctl_phy_enable(device_t dev, intptr_t id, bool enable)
+{
+ struct xusbpadctl_softc *sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+
+ if ((id != TEGRA_XUSB_PADCTL_PCIE) &&
+ (id != TEGRA_XUSB_PADCTL_SATA)) {
+ device_printf(dev, "Unknown phy: %d\n", id);
+ return (ENXIO);
+ }
+
+ rv = 0;
+ if (enable) {
+ if (sc->phy_ena_cnt == 0) {
+ rv = xusbpadctl_phy_powerup(sc);
+ if (rv != 0)
+ return (rv);
+ }
+ sc->phy_ena_cnt++;
+ }
+
+ if (id == TEGRA_XUSB_PADCTL_PCIE) {
+ if (enable)
+ rv = xusbpadctl_phy_pcie_powerup(sc);
+ else
+ rv = xusbpadctl_phy_pcie_powerdown(sc);
+ if (rv != 0)
+ return (rv);
+ } else if (id == TEGRA_XUSB_PADCTL_SATA) {
+ if (enable)
+ rv = xusbpadctl_phy_sata_powerup(sc);
+ else
+ rv = xusbpadctl_phy_sata_powerdown(sc);
+ if (rv != 0)
+ return (rv);
+ }
+ if (!enable) {
+ if (sc->phy_ena_cnt == 1) {
+ rv = xusbpadctl_phy_powerdown(sc);
+ if (rv != 0)
+ return (rv);
+ }
+ sc->phy_ena_cnt--;
+ }
+
+ return (0);
+}
+
+static int
+xusbpadctl_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Tegra XUSB phy");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+xusbpadctl_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static int
+xusbpadctl_attach(device_t dev)
+{
+ struct xusbpadctl_softc * sc;
+ int rid, rv;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ node = ofw_bus_get_node(dev);
+ rv = hwreset_get_by_ofw_name(dev, "padctl", &sc->rst);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'padctl' reset: %d\n", rv);
+ return (rv);
+ }
+ rv = hwreset_deassert(sc->rst);
+ if (rv != 0) {
+ device_printf(dev, "Cannot unreset 'padctl' reset: %d\n", rv);
+ return (rv);
+ }
+
+ /* Register as a pinctrl device and use default configuration */
+ fdt_pinctrl_register(dev, NULL);
+ fdt_pinctrl_configure_by_name(dev, "default");
+ phy_register_provider(dev);
+
+ return (0);
+}
+
+
+static device_method_t tegra_xusbpadctl_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, xusbpadctl_probe),
+ DEVMETHOD(device_attach, xusbpadctl_attach),
+ DEVMETHOD(device_detach, xusbpadctl_detach),
+
+ /* fdt_pinctrl interface */
+ DEVMETHOD(fdt_pinctrl_configure, xusbpadctl_pinctrl_cfg),
+
+ /* phy interface */
+ DEVMETHOD(phy_enable, xusbpadctl_phy_enable),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra_xusbpadctl_driver = {
+ "tegra_xusbpadctl",
+ tegra_xusbpadctl_methods,
+ sizeof(struct xusbpadctl_softc),
+};
+
+static devclass_t tegra_xusbpadctl_devclass;
+
+EARLY_DRIVER_MODULE(tegra_xusbpadctl, simplebus, tegra_xusbpadctl_driver,
+ tegra_xusbpadctl_devclass, 0, 0, 73);
diff --git a/sys/arm/nvidia/tegra_abpmisc.c b/sys/arm/nvidia/tegra_abpmisc.c
new file mode 100644
index 0000000..83ee44f
--- /dev/null
+++ b/sys/arm/nvidia/tegra_abpmisc.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * SoC misc configuration and indentification driver.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_efuse.h>
+
+#define PMC_STRAPPING_OPT_A 0 /* 0x464 */
+
+#define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT 4
+#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG \
+ (0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
+#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT \
+ (0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
+
+
+#define ABP_RD4(_sc, _r) bus_read_4((_sc)->abp_misc_res, (_r))
+#define STR_RD4(_sc, _r) bus_read_4((_sc)->strap_opt_res, (_r))
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-apbmisc", 1},
+ {NULL, 0}
+};
+
+struct tegra_abpmisc_softc {
+ device_t dev;
+
+ struct resource *abp_misc_res;
+ struct resource *strap_opt_res;
+};
+
+static struct tegra_abpmisc_softc *dev_sc;
+
+static void
+tegra_abpmisc_read_revision(struct tegra_abpmisc_softc *sc)
+{
+ uint32_t id, chip_id, minor_rev;
+ int rev;
+
+ id = ABP_RD4(sc, 4);
+ chip_id = (id >> 8) & 0xff;
+ minor_rev = (id >> 16) & 0xf;
+
+ switch (minor_rev) {
+ case 1:
+ rev = TEGRA_REVISION_A01;
+ break;
+ case 2:
+ rev = TEGRA_REVISION_A02;
+ break;
+ case 3:
+ rev = TEGRA_REVISION_A03;
+ break;
+ case 4:
+ rev = TEGRA_REVISION_A04;
+ break;
+ default:
+ rev = TEGRA_REVISION_UNKNOWN;
+ }
+
+ tegra_sku_info.chip_id = chip_id;
+ tegra_sku_info.revision = rev;
+}
+
+static int
+tegra_abpmisc_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_abpmisc_attach(device_t dev)
+{
+ int rid;
+ struct tegra_abpmisc_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ rid = 0;
+ sc->abp_misc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->abp_misc_res == NULL) {
+ device_printf(dev, "Cannot map ABP misc registers.\n");
+ goto fail;
+ }
+
+ rid = 1;
+ sc->strap_opt_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->strap_opt_res == NULL) {
+ device_printf(dev, "Cannot map strapping options registers.\n");
+ goto fail;
+ }
+
+ tegra_abpmisc_read_revision(sc);
+
+ /* XXX - Hack - address collision with pinmux. */
+ if (sc->abp_misc_res != NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->abp_misc_res);
+ sc->abp_misc_res = NULL;
+ }
+
+ dev_sc = sc;
+ return (bus_generic_attach(dev));
+
+fail:
+ if (sc->abp_misc_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->abp_misc_res);
+ if (sc->strap_opt_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->strap_opt_res);
+
+ return (ENXIO);
+}
+
+static int
+tegra_abpmisc_detach(device_t dev)
+{
+ struct tegra_abpmisc_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->abp_misc_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->abp_misc_res);
+ if (sc->strap_opt_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->strap_opt_res);
+ return (bus_generic_detach(dev));
+}
+
+static device_method_t tegra_abpmisc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_abpmisc_probe),
+ DEVMETHOD(device_attach, tegra_abpmisc_attach),
+ DEVMETHOD(device_detach, tegra_abpmisc_detach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(tegra_abpmisc, tegra_abpmisc_driver, tegra_abpmisc_methods,
+ sizeof(struct tegra_abpmisc_softc));
+static devclass_t tegra_abpmisc_devclass;
+EARLY_DRIVER_MODULE(tegra_abpmisc, simplebus, tegra_abpmisc_driver,
+ tegra_abpmisc_devclass, 0, 0, BUS_PASS_TIMER);
diff --git a/sys/arm/nvidia/tegra_ahci.c b/sys/arm/nvidia/tegra_ahci.c
new file mode 100644
index 0000000..4afba17
--- /dev/null
+++ b/sys/arm/nvidia/tegra_ahci.c
@@ -0,0 +1,627 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * AHCI driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ahci/ahci.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_efuse.h>
+#include <arm/nvidia/tegra_pmc.h>
+
+#define AHCI_WR4(_sc, _r, _v) bus_write_4((_sc)->ctlr.r_mem, (_r), (_v))
+#define AHCI_RD4(_sc, _r) bus_read_4((_sc)->ctlr.r_mem, (_r))
+#define SATA_WR4(_sc, _r, _v) bus_write_4((_sc)->sata_mem, (_r), (_v))
+#define SATA_RD4(_sc, _r) bus_read_4((_sc)->sata_mem, (_r))
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-ahci", 1},
+ {NULL, 0}
+};
+
+struct tegra_ahci_sc {
+ struct ahci_controller ctlr; /* Must be first */
+ device_t dev;
+ struct resource *sata_mem;
+ clk_t clk_sata;
+ clk_t clk_sata_oob;
+ clk_t clk_pll_e;
+ clk_t clk_cml;
+ hwreset_t hwreset_sata;
+ hwreset_t hwreset_sata_oob;
+ hwreset_t hwreset_sata_cold;
+ regulator_t supply_hvdd;
+ regulator_t supply_vddio;
+ regulator_t supply_avdd;
+ regulator_t supply_target_5v;
+ regulator_t supply_target_12v;
+ phy_t phy;
+};
+
+struct sata_pad_calibration {
+ uint32_t gen1_tx_amp;
+ uint32_t gen1_tx_peak;
+ uint32_t gen2_tx_amp;
+ uint32_t gen2_tx_peak;
+};
+
+static const struct sata_pad_calibration tegra124_pad_calibration[] = {
+ {0x18, 0x04, 0x18, 0x0a},
+ {0x0e, 0x04, 0x14, 0x0a},
+ {0x0e, 0x07, 0x1a, 0x0e},
+ {0x14, 0x0e, 0x1a, 0x0e},
+};
+
+#define SATA_CONFIGURATION 0x180
+#define SATA_CONFIGURATION_EN_FPCI (1 << 0)
+
+#define SATA_FPCI_BAR5 0x94
+#define SATA_FPCI_BAR5_START_SHIFT 4
+
+#define SATA_INTR_MASK 0x188
+#define SATA_INTR_MASK_IP_INT_MASK (1 << 16)
+
+#define SCFG_OFFSET 0x1000
+
+#define T_SATA0_CFG_1 0x04
+#define T_SATA0_CFG_1_IO_SPACE (1 << 0)
+#define T_SATA0_CFG_1_MEMORY_SPACE (1 << 1)
+#define T_SATA0_CFG_1_BUS_MASTER (1 << 2)
+#define T_SATA0_CFG_1_SERR (1 << 8)
+
+#define T_SATA0_CFG_9 0x24
+#define T_SATA0_CFG_9_BASE_ADDRESS_SHIFT 13
+
+#define T_SATA0_AHCI_HBA_CAP_BKDR 0x300
+#define T_SATA0_BKDOOR_CC 0x4a4
+#define T_SATA0_CFG_SATA 0x54c
+#define T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN (1 << 12)
+
+#define T_SATA0_CFG_MISC 0x550
+#define T_SATA0_INDEX 0x680
+
+#define T_SATA0_CHX_PHY_CTRL1_GEN1 0x690
+#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK 0xff
+#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT 8
+#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK 0xff
+#define T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT 0
+
+
+#define T_SATA0_CHX_PHY_CTRL1_GEN2 0x694
+#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK 0xff
+#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT 12
+#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK 0xff
+#define T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT 0
+
+#define T_SATA0_CHX_PHY_CTRL2 0x69c
+#define T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1 0x23
+
+#define T_SATA0_CHX_PHY_CTRL11 0x6d0
+#define T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ (0x2800 << 16)
+
+#define FUSE_SATA_CALIB 0x124
+#define FUSE_SATA_CALIB_MASK 0x3
+
+
+#define SATA_AUX_MISC_CNTL 0x1108
+#define SATA_AUX_PAD_PLL_CTRL_0 0x1120
+#define SATA_AUX_PAD_PLL_CTRL_1 0x1124
+#define SATA_AUX_PAD_PLL_CTRL_2 0x1128
+#define SATA_AUX_PAD_PLL_CTRL_3 0x112c
+
+#define T_AHCI_HBA_CCC_PORTS 0x0018
+#define T_AHCI_HBA_CAP_BKDR 0x00A0
+#define T_AHCI_HBA_CAP_BKDR_S64A (1 << 31)
+#define T_AHCI_HBA_CAP_BKDR_SNCQ (1 << 30)
+#define T_AHCI_HBA_CAP_BKDR_SSNTF (1 << 29)
+#define T_AHCI_HBA_CAP_BKDR_SMPS (1 << 28)
+#define T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP (1 << 27)
+#define T_AHCI_HBA_CAP_BKDR_SALP (1 << 26)
+#define T_AHCI_HBA_CAP_BKDR_SAL (1 << 25)
+#define T_AHCI_HBA_CAP_BKDR_SUPP_CLO (1 << 24)
+#define T_AHCI_HBA_CAP_BKDR_INTF_SPD_SUPP(x) (((x) & 0xF) << 20)
+#define T_AHCI_HBA_CAP_BKDR_SUPP_NONZERO_OFFSET (1 << 19)
+#define T_AHCI_HBA_CAP_BKDR_SUPP_AHCI_ONLY (1 << 18)
+#define T_AHCI_HBA_CAP_BKDR_SUPP_PM (1 << 17)
+#define T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING (1 << 16)
+#define T_AHCI_HBA_CAP_BKDR_PIO_MULT_DRQ_BLK (1 << 15)
+#define T_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP (1 << 14)
+#define T_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP (1 << 13)
+#define T_AHCI_HBA_CAP_BKDR_NUM_CMD_SLOTS(x) (((x) & 0x1F) << 8)
+#define T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING (1 << 7)
+#define T_AHCI_HBA_CAP_BKDR_ENCL_MGMT_SUPP (1 << 6)
+#define T_AHCI_HBA_CAP_BKDR_EXT_SATA (1 << 5)
+#define T_AHCI_HBA_CAP_BKDR_NUM_PORTS(x) (((x) & 0xF) << 0)
+
+#define T_AHCI_PORT_BKDR 0x0170
+
+#define T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE_VAL(x) (((x) & 0xFF) << 24)
+#define T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE_VAL(x) (((x) & 0x1F) << 16)
+#define T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE (1 << 15)
+#define T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE (1 << 14)
+#define T_AHCI_PORT_BKDR_PXDEVSLP_DM(x) (((x) & 0xF) << 10)
+#define T_AHCI_PORT_BKDR_PORT_UNCONNECTED (1 << 9)
+#define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_CLAMP_THIS_CH (1 << 8)
+#define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_UNCLAMP (1 << 7)
+#define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_CLAMP (1 << 6)
+#define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_UNCLAMP (1 << 5)
+#define T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_CLAMP (1 << 4)
+#define T_AHCI_PORT_BKDR_HOTPLUG_CAP (1 << 3)
+#define T_AHCI_PORT_BKDR_MECH_SWITCH (1 << 2)
+#define T_AHCI_PORT_BKDR_COLD_PRSN_DET (1 << 1)
+#define T_AHCI_PORT_BKDR_EXT_SATA_SUPP (1 << 0)
+
+static int
+get_fdt_resources(struct tegra_ahci_sc *sc, phandle_t node)
+{
+ int rv;
+
+
+ rv = regulator_get_by_ofw_property(sc->dev, "hvdd-supply",
+ &sc->supply_hvdd );
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'hvdd' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "vddio-supply",
+ &sc->supply_vddio);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'vddio' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "avdd-supply",
+ &sc->supply_avdd);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'avdd' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "target-5v-supply",
+ &sc->supply_target_5v);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'target-5v' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "target-12v-supply",
+ &sc->supply_target_12v);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'target-12v' regulator\n");
+ return (ENXIO);
+ }
+
+ rv = hwreset_get_by_ofw_name(sc->dev, "sata", &sc->hwreset_sata );
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "sata-oob",
+ &sc->hwreset_sata_oob);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata oob' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "sata-cold",
+ &sc->hwreset_sata_cold);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata cold' reset\n");
+ return (ENXIO);
+ }
+
+ rv = phy_get_by_ofw_name(sc->dev, "sata-phy", &sc->phy);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata' phy\n");
+ return (ENXIO);
+ }
+
+ rv = clk_get_by_ofw_name(sc->dev, "sata", &sc->clk_sata);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "sata-oob", &sc->clk_sata_oob);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sata oob' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "cml1", &sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'cml1' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "pll_e", &sc->clk_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pll_e' clock\n");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+static int
+enable_fdt_resources(struct tegra_ahci_sc *sc)
+{
+ int rv;
+
+ rv = regulator_enable(sc->supply_hvdd);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'hvdd' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_vddio);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'vddio' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_avdd);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'avdd' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_target_5v);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'target-5v' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_target_12v);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'sc->target-12v' regulator\n");
+ return (rv);
+ }
+
+ /* Stop clocks */
+ clk_stop(sc->clk_sata);
+ clk_stop(sc->clk_sata_oob);
+ tegra_powergate_power_off(TEGRA_POWERGATE_SAX);
+
+ rv = hwreset_assert(sc->hwreset_sata);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'sata' reset\n");
+ return (rv);
+ }
+ rv = hwreset_assert(sc->hwreset_sata_oob);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'sata oob' reset\n");
+ return (rv);
+ }
+
+ rv = hwreset_assert(sc->hwreset_sata_cold);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'sata cold' reset\n");
+ return (rv);
+ }
+ rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SAX,
+ sc->clk_sata, sc->hwreset_sata);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'SAX' powergate\n");
+ return (rv);
+ }
+
+ rv = clk_enable(sc->clk_sata_oob);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'sata oob' clock\n");
+ return (rv);
+ }
+ rv = clk_enable(sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'cml' clock\n");
+ return (rv);
+ }
+ rv = clk_enable(sc->clk_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'pll e' clock\n");
+ return (rv);
+ }
+
+ rv = hwreset_deassert(sc->hwreset_sata_cold);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot unreset 'sata cold' reset\n");
+ return (rv);
+ }
+ rv = hwreset_deassert(sc->hwreset_sata_oob);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot unreset 'sata oob' reset\n");
+ return (rv);
+ }
+
+ rv = phy_enable(sc->dev, sc->phy);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable SATA phy\n");
+ return (rv);
+ }
+
+ return (0);
+}
+
+static int
+tegra_ahci_ctrl_init(struct tegra_ahci_sc *sc)
+{
+ uint32_t val;
+ const struct sata_pad_calibration *calib;
+
+ val = SATA_RD4(sc, SATA_CONFIGURATION);
+ val |= SATA_CONFIGURATION_EN_FPCI;
+ SATA_WR4(sc, SATA_CONFIGURATION, val);
+
+
+ /* Pad calibration. */
+ val = tegra_fuse_read_4(FUSE_SATA_CALIB);
+ calib = tegra124_pad_calibration + (val & FUSE_SATA_CALIB_MASK);
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 1);
+
+ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
+ val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK <<
+ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT);
+ val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK <<
+ T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT);
+ val |= calib->gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
+ val |= calib->gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1, val);
+
+ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
+ val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK <<
+ T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT);
+ val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK <<
+ T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT);
+ val |= calib->gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT;
+ val |= calib->gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT;
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2, val);
+
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11,
+ T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ);
+
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2,
+ T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1);
+
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 0);
+
+ /* Set device ID. */
+ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA);
+ val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val);
+
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_BKDOOR_CC, 0x01060100);
+
+ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA);
+ val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val);
+
+ /* Enable IO & memory access, bus master mode */
+ val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_1);
+ val |= T_SATA0_CFG_1_IO_SPACE;
+ val |= T_SATA0_CFG_1_MEMORY_SPACE;
+ val |= T_SATA0_CFG_1_BUS_MASTER;
+ val |= T_SATA0_CFG_1_SERR;
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_1, val);
+
+ /* SATA MMIO. */
+ SATA_WR4(sc, SATA_FPCI_BAR5, 0x10000 << SATA_FPCI_BAR5_START_SHIFT);
+ /* AHCI bar */
+ SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_9,
+ 0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT);
+
+ /* Unmask interrupts. */
+ val = SATA_RD4(sc, SATA_INTR_MASK);
+ val |= SATA_INTR_MASK_IP_INT_MASK;
+ SATA_WR4(sc, SATA_INTR_MASK, val);
+
+ return (0);
+}
+
+static int
+tegra_ahci_ctlr_reset(device_t dev)
+{
+ struct tegra_ahci_sc *sc;
+ int rv;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ rv = ahci_ctlr_reset(dev);
+ if (rv != 0)
+ return (0);
+ AHCI_WR4(sc, T_AHCI_HBA_CCC_PORTS, 1);
+
+ /* Overwrite AHCI capabilites. */
+ reg = AHCI_RD4(sc, T_AHCI_HBA_CAP_BKDR);
+ reg &= ~T_AHCI_HBA_CAP_BKDR_NUM_PORTS(~0);
+ reg |= T_AHCI_HBA_CAP_BKDR_NUM_PORTS(0);
+ reg |= T_AHCI_HBA_CAP_BKDR_EXT_SATA;
+ reg |= T_AHCI_HBA_CAP_BKDR_ENCL_MGMT_SUPP;
+ reg |= T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING;
+ reg |= T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING;
+ reg |= T_AHCI_HBA_CAP_BKDR_SUPP_PM;
+ reg |= T_AHCI_HBA_CAP_BKDR_SUPP_CLO;
+ reg |= T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP;
+ AHCI_WR4(sc, T_AHCI_HBA_CAP_BKDR, reg);
+
+ /* Overwrite AHCI portcapabilites. */
+ reg = AHCI_RD4(sc, T_AHCI_PORT_BKDR);
+ reg |= T_AHCI_PORT_BKDR_COLD_PRSN_DET;
+ reg |= T_AHCI_PORT_BKDR_HOTPLUG_CAP;
+ reg |= T_AHCI_PORT_BKDR_EXT_SATA_SUPP;
+ AHCI_WR4(sc, T_AHCI_PORT_BKDR, reg);
+
+ return (0);
+}
+
+static int
+tegra_ahci_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc_copy(dev, "AHCI SATA controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_ahci_attach(device_t dev)
+{
+ struct tegra_ahci_sc *sc;
+ struct ahci_controller *ctlr;
+ phandle_t node;
+ int rv, rid;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ ctlr = &sc->ctlr;
+ node = ofw_bus_get_node(dev);
+
+ ctlr->r_rid = 0;
+ ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &ctlr->r_rid, RF_ACTIVE);
+ if (ctlr->r_mem == NULL)
+ return (ENXIO);
+
+ rid = 1;
+ sc->sata_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &rid, RF_ACTIVE);
+ if (sc->sata_mem == NULL) {
+ rv = ENXIO;
+ goto fail;
+ }
+ rv = get_fdt_resources(sc, node);
+ if (rv != 0) {
+ device_printf(sc->dev, "Failed to allocate FDT resource(s)\n");
+ goto fail;
+ }
+
+ rv = enable_fdt_resources(sc);
+ if (rv != 0) {
+ device_printf(sc->dev, "Failed to enable FDT resource(s)\n");
+ goto fail;
+ }
+ rv = tegra_ahci_ctrl_init(sc);
+ if (rv != 0) {
+ device_printf(sc->dev, "Failed to initialize controller)\n");
+ goto fail;
+ }
+
+ /* Setup controller defaults. */
+ ctlr->msi = 0;
+ ctlr->numirqs = 1;
+ ctlr->ccc = 0;
+
+ /* Reset controller. */
+ rv = tegra_ahci_ctlr_reset(dev);
+ if (rv != 0)
+ goto fail;
+ rv = ahci_attach(dev);
+ return (rv);
+
+fail:
+ /* XXX FDT stuff */
+ if (sc->sata_mem != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->sata_mem);
+ if (ctlr->r_mem != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
+ ctlr->r_mem);
+ return (rv);
+}
+
+static int
+tegra_ahci_detach(device_t dev)
+{
+
+ ahci_detach(dev);
+ return (0);
+}
+
+static int
+tegra_ahci_suspend(device_t dev)
+{
+ struct tegra_ahci_sc *sc = device_get_softc(dev);
+
+ bus_generic_suspend(dev);
+ /* Disable interupts, so the state change(s) doesn't trigger. */
+ ATA_OUTL(sc->ctlr.r_mem, AHCI_GHC,
+ ATA_INL(sc->ctlr.r_mem, AHCI_GHC) & (~AHCI_GHC_IE));
+ return (0);
+}
+
+static int
+tegra_ahci_resume(device_t dev)
+{
+ int res;
+
+ if ((res = tegra_ahci_ctlr_reset(dev)) != 0)
+ return (res);
+ ahci_ctlr_setup(dev);
+ return (bus_generic_resume(dev));
+}
+
+devclass_t genahci_devclass;
+static device_method_t genahci_methods[] = {
+ DEVMETHOD(device_probe, tegra_ahci_probe),
+ DEVMETHOD(device_attach, tegra_ahci_attach),
+ DEVMETHOD(device_detach, tegra_ahci_detach),
+ DEVMETHOD(device_suspend, tegra_ahci_suspend),
+ DEVMETHOD(device_resume, tegra_ahci_resume),
+ DEVMETHOD(bus_print_child, ahci_print_child),
+ DEVMETHOD(bus_alloc_resource, ahci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ahci_release_resource),
+ DEVMETHOD(bus_setup_intr, ahci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ahci_teardown_intr),
+ DEVMETHOD(bus_child_location_str, ahci_child_location_str),
+ DEVMETHOD(bus_get_dma_tag, ahci_get_dma_tag),
+
+ DEVMETHOD_END
+};
+static driver_t genahci_driver = {
+ "ahci",
+ genahci_methods,
+ sizeof(struct tegra_ahci_sc)
+};
+DRIVER_MODULE(genahci, simplebus, genahci_driver, genahci_devclass, NULL, NULL);
diff --git a/sys/arm/nvidia/tegra_efuse.c b/sys/arm/nvidia/tegra_efuse.c
new file mode 100644
index 0000000..ae3f9ef
--- /dev/null
+++ b/sys/arm/nvidia/tegra_efuse.c
@@ -0,0 +1,368 @@
+/*-
+ * Copyright (c) 2015 Michal Meloun
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_efuse.h>
+
+
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_sc)->fuse_begin + (_r))
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-efuse", 1},
+ {NULL, 0}
+};
+
+struct tegra_efuse_softc {
+ device_t dev;
+ struct resource *mem_res;
+
+ int fuse_begin;
+ clk_t clk;
+ hwreset_t reset;
+};
+struct tegra_efuse_softc *dev_sc;
+
+struct tegra_sku_info tegra_sku_info;
+static char *tegra_rev_name[] = {
+ [TEGRA_REVISION_UNKNOWN] = "unknown",
+ [TEGRA_REVISION_A01] = "A01",
+ [TEGRA_REVISION_A02] = "A02",
+ [TEGRA_REVISION_A03] = "A03",
+ [TEGRA_REVISION_A03p] = "A03 prime",
+ [TEGRA_REVISION_A04] = "A04",
+};
+
+/* Tegra30 and later */
+#define FUSE_VENDOR_CODE 0x100
+#define FUSE_FAB_CODE 0x104
+#define FUSE_LOT_CODE_0 0x108
+#define FUSE_LOT_CODE_1 0x10c
+#define FUSE_WAFER_ID 0x110
+#define FUSE_X_COORDINATE 0x114
+#define FUSE_Y_COORDINATE 0x118
+
+/* ---------------------- Tegra 124 specific code & data --------------- */
+#define TEGRA124_FUSE_BEGIN 0x100
+
+#define TEGRA124_CPU_PROCESS_CORNERS 2
+#define TEGRA124_GPU_PROCESS_CORNERS 2
+#define TEGRA124_SOC_PROCESS_CORNERS 2
+
+#define TEGRA124_FUSE_SKU_INFO 0x10
+#define TEGRA124_FUSE_CPU_SPEEDO_0 0x14
+#define TEGRA124_FUSE_CPU_IDDQ 0x18
+#define TEGRA124_FUSE_FT_REV 0x28
+#define TEGRA124_FUSE_CPU_SPEEDO_1 0x2c
+#define TEGRA124_FUSE_CPU_SPEEDO_2 0x30
+#define TEGRA124_FUSE_SOC_SPEEDO_0 0x34
+#define TEGRA124_FUSE_SOC_SPEEDO_1 0x38
+#define TEGRA124_FUSE_SOC_SPEEDO_2 0x3c
+#define TEGRA124_FUSE_SOC_IDDQ 0x40
+#define TEGRA124_FUSE_GPU_IDDQ 0x128
+
+enum {
+ TEGRA124_THRESHOLD_INDEX_0,
+ TEGRA124_THRESHOLD_INDEX_1,
+ TEGRA124_THRESHOLD_INDEX_COUNT,
+};
+
+static uint32_t tegra124_cpu_process_speedos[][TEGRA124_CPU_PROCESS_CORNERS] =
+{
+ {2190, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static uint32_t tegra124_gpu_process_speedos[][TEGRA124_GPU_PROCESS_CORNERS] =
+{
+ {1965, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static uint32_t tegra124_soc_process_speedos[][TEGRA124_SOC_PROCESS_CORNERS] =
+{
+ {2101, UINT_MAX},
+ {0, UINT_MAX},
+};
+
+static void
+tegra124_rev_sku_to_speedo_ids(struct tegra_efuse_softc *sc,
+ struct tegra_sku_info *sku, int *threshold)
+{
+
+ /* Assign to default */
+ sku->cpu_speedo_id = 0;
+ sku->soc_speedo_id = 0;
+ sku->gpu_speedo_id = 0;
+ *threshold = TEGRA124_THRESHOLD_INDEX_0;
+
+ switch (sku->sku_id) {
+ case 0x00: /* Eng sku */
+ case 0x0F:
+ case 0x23:
+ /* Using the default */
+ break;
+ case 0x83:
+ sku->cpu_speedo_id = 2;
+ break;
+
+ case 0x1F:
+ case 0x87:
+ case 0x27:
+ sku->cpu_speedo_id = 2;
+ sku->soc_speedo_id = 0;
+ sku->gpu_speedo_id = 1;
+ *threshold = TEGRA124_THRESHOLD_INDEX_0;
+ break;
+ case 0x81:
+ case 0x21:
+ case 0x07:
+ sku->cpu_speedo_id = 1;
+ sku->soc_speedo_id = 1;
+ sku->gpu_speedo_id = 1;
+ *threshold = TEGRA124_THRESHOLD_INDEX_1;
+ break;
+ case 0x49:
+ case 0x4A:
+ case 0x48:
+ sku->cpu_speedo_id = 4;
+ sku->soc_speedo_id = 2;
+ sku->gpu_speedo_id = 3;
+ *threshold = TEGRA124_THRESHOLD_INDEX_1;
+ break;
+ default:
+ device_printf(sc->dev, " Unknown SKU ID %d\n", sku->sku_id);
+ break;
+ }
+}
+
+
+static void
+tegra124_init_speedo(struct tegra_efuse_softc *sc, struct tegra_sku_info *sku)
+{
+ int i, threshold;
+
+ sku->sku_id = RD4(sc, TEGRA124_FUSE_SKU_INFO);
+ sku->soc_iddq_value = RD4(sc, TEGRA124_FUSE_SOC_IDDQ);
+ sku->cpu_iddq_value = RD4(sc, TEGRA124_FUSE_CPU_IDDQ);
+ sku->gpu_iddq_value = RD4(sc, TEGRA124_FUSE_GPU_IDDQ);
+ sku->soc_speedo_value = RD4(sc, TEGRA124_FUSE_SOC_SPEEDO_0);
+ sku->cpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_0);
+ sku->gpu_speedo_value = RD4(sc, TEGRA124_FUSE_CPU_SPEEDO_2);
+
+ if (sku->cpu_speedo_value == 0) {
+ device_printf(sc->dev, "CPU Speedo value is not fused.\n");
+ return;
+ }
+
+ tegra124_rev_sku_to_speedo_ids(sc, sku, &threshold);
+
+ for (i = 0; i < TEGRA124_SOC_PROCESS_CORNERS; i++) {
+ if (sku->soc_speedo_value <
+ tegra124_soc_process_speedos[threshold][i])
+ break;
+ }
+ sku->soc_process_id = i;
+
+ for (i = 0; i < TEGRA124_CPU_PROCESS_CORNERS; i++) {
+ if (sku->cpu_speedo_value <
+ tegra124_cpu_process_speedos[threshold][i])
+ break;
+ }
+ sku->cpu_process_id = i;
+
+ for (i = 0; i < TEGRA124_GPU_PROCESS_CORNERS; i++) {
+ if (sku->gpu_speedo_value <
+ tegra124_gpu_process_speedos[threshold][i])
+ break;
+ }
+ sku->gpu_process_id = i;
+
+}
+
+/* ----------------- End of Tegra 124 specific code & data --------------- */
+
+uint32_t
+tegra_fuse_read_4(int addr) {
+
+ if (dev_sc == NULL)
+ panic("tegra_fuse_read_4 called too early");
+ return (RD4(dev_sc, addr));
+}
+
+
+static void
+tegra_efuse_dump_sku()
+{
+ printf(" TEGRA SKU Info:\n");
+ printf(" chip_id: %u\n", tegra_sku_info.chip_id);
+ printf(" sku_id: %u\n", tegra_sku_info.sku_id);
+ printf(" cpu_process_id: %u\n", tegra_sku_info.cpu_process_id);
+ printf(" cpu_speedo_id: %u\n", tegra_sku_info.cpu_speedo_id);
+ printf(" cpu_speedo_value: %u\n", tegra_sku_info.cpu_speedo_value);
+ printf(" cpu_iddq_value: %u\n", tegra_sku_info.cpu_iddq_value);
+ printf(" soc_process_id: %u\n", tegra_sku_info.soc_process_id);
+ printf(" soc_speedo_id: %u\n", tegra_sku_info.soc_speedo_id);
+ printf(" soc_speedo_value: %u\n", tegra_sku_info.soc_speedo_value);
+ printf(" soc_iddq_value: %u\n", tegra_sku_info.soc_iddq_value);
+ printf(" gpu_process_id: %u\n", tegra_sku_info.gpu_process_id);
+ printf(" gpu_speedo_id: %u\n", tegra_sku_info.gpu_speedo_id);
+ printf(" gpu_speedo_value: %u\n", tegra_sku_info.gpu_speedo_value);
+ printf(" gpu_iddq_value: %u\n", tegra_sku_info.gpu_iddq_value);
+ printf(" revision: %s\n", tegra_rev_name[tegra_sku_info.revision]);
+}
+
+static int
+tegra_efuse_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_efuse_attach(device_t dev)
+{
+ int rv, rid;
+ phandle_t node;
+ struct tegra_efuse_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+
+ /* Get the memory resource for the register mapping. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot map registers.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* OFW resources. */
+ rv = clk_get_by_ofw_name(dev, "fuse", &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get fuse clock: %d\n", rv);
+ goto fail;
+ }
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable clock: %d\n", rv);
+ goto fail;
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "fuse", &sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get fuse reset\n");
+ goto fail;
+ }
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot clear reset\n");
+ goto fail;
+ }
+
+ /* Tegra124 specific init. */
+ sc->fuse_begin = TEGRA124_FUSE_BEGIN;
+ tegra124_init_speedo(sc, &tegra_sku_info);
+
+ dev_sc = sc;
+
+ if (bootverbose)
+ tegra_efuse_dump_sku();
+ return (bus_generic_attach(dev));
+
+fail:
+ dev_sc = NULL;
+ if (sc->clk != NULL)
+ clk_release(sc->clk);
+ if (sc->reset != NULL)
+ hwreset_release(sc->reset);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (rv);
+}
+
+static int
+tegra_efuse_detach(device_t dev)
+{
+ struct tegra_efuse_softc *sc;
+
+ sc = device_get_softc(dev);
+ dev_sc = NULL;
+ if (sc->clk != NULL)
+ clk_release(sc->clk);
+ if (sc->reset != NULL)
+ hwreset_release(sc->reset);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (bus_generic_detach(dev));
+}
+
+static device_method_t tegra_efuse_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_efuse_probe),
+ DEVMETHOD(device_attach, tegra_efuse_attach),
+ DEVMETHOD(device_detach, tegra_efuse_detach),
+
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(tegra_efuse, tegra_efuse_driver, tegra_efuse_methods,
+ sizeof(struct tegra_efuse_softc));
+static devclass_t tegra_efuse_devclass;
+EARLY_DRIVER_MODULE(tegra_efuse, simplebus, tegra_efuse_driver,
+ tegra_efuse_devclass, 0, 0, BUS_PASS_TIMER);
diff --git a/sys/arm/nvidia/tegra_efuse.h b/sys/arm/nvidia/tegra_efuse.h
new file mode 100644
index 0000000..36804d06
--- /dev/null
+++ b/sys/arm/nvidia/tegra_efuse.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TEGRA_EFUSE_H_
+
+enum tegra_revision {
+ TEGRA_REVISION_UNKNOWN = 0,
+ TEGRA_REVISION_A01,
+ TEGRA_REVISION_A02,
+ TEGRA_REVISION_A03,
+ TEGRA_REVISION_A03p,
+ TEGRA_REVISION_A04,
+};
+
+struct tegra_sku_info {
+ u_int chip_id;
+ u_int sku_id;
+ u_int cpu_process_id;
+ u_int cpu_speedo_id;
+ u_int cpu_speedo_value;
+ u_int cpu_iddq_value;
+ u_int soc_process_id;
+ u_int soc_speedo_id;
+ u_int soc_speedo_value;
+ u_int soc_iddq_value;
+ u_int gpu_process_id;
+ u_int gpu_speedo_id;
+ u_int gpu_speedo_value;
+ u_int gpu_iddq_value;
+ enum tegra_revision revision;
+};
+
+extern struct tegra_sku_info tegra_sku_info;
+uint32_t tegra_fuse_read_4(int addr);
+
+#endif /* _TEGRA_EFUSE_H_ */
diff --git a/sys/arm/nvidia/tegra_ehci.c b/sys/arm/nvidia/tegra_ehci.c
new file mode 100644
index 0000000..e7f7b22
--- /dev/null
+++ b/sys/arm/nvidia/tegra_ehci.c
@@ -0,0 +1,322 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * EHCI driver for Tegra SoCs.
+ */
+#include "opt_bus.h"
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/condvar.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+#include "usbdevs.h"
+
+#define TEGRA_EHCI_REG_OFF 0x100
+#define TEGRA_EHCI_REG_SIZE 0x100
+
+/* Compatible devices. */
+#define TEGRA124_EHCI 1
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-ehci", (uintptr_t)TEGRA124_EHCI},
+ {NULL, 0},
+};
+
+struct tegra_ehci_softc {
+ ehci_softc_t ehci_softc;
+ device_t dev;
+ struct resource *ehci_mem_res; /* EHCI core regs. */
+ struct resource *ehci_irq_res; /* EHCI core IRQ. */
+ int usb_alloc_called;
+ clk_t clk;
+ phy_t phy;
+ hwreset_t reset;
+};
+
+static void
+tegra_ehci_post_reset(struct ehci_softc *ehci_softc)
+{
+ uint32_t usbmode;
+
+ /* Force HOST mode. */
+ usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_LPM);
+ usbmode &= ~EHCI_UM_CM;
+ usbmode |= EHCI_UM_CM_HOST;
+ device_printf(ehci_softc->sc_bus.bdev, "set host controller mode\n");
+ EOWRITE4(ehci_softc, EHCI_USBMODE_LPM, usbmode);
+}
+
+static int
+tegra_ehci_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Nvidia Tegra EHCI controller");
+ return (BUS_PROBE_DEFAULT);
+ }
+ return (ENXIO);
+}
+
+static int
+tegra_ehci_detach(device_t dev)
+{
+ struct tegra_ehci_softc *sc;
+ ehci_softc_t *esc;
+
+ sc = device_get_softc(dev);
+
+ esc = &sc->ehci_softc;
+ if (sc->clk != NULL)
+ clk_release(sc->clk);
+ if (esc->sc_bus.bdev != NULL)
+ device_delete_child(dev, esc->sc_bus.bdev);
+ if (esc->sc_flags & EHCI_SCFLG_DONEINIT)
+ ehci_detach(esc);
+ if (esc->sc_intr_hdl != NULL)
+ bus_teardown_intr(dev, esc->sc_irq_res,
+ esc->sc_intr_hdl);
+ if (sc->ehci_irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0,
+ sc->ehci_irq_res);
+ if (sc->ehci_mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0,
+ sc->ehci_mem_res);
+ if (sc->usb_alloc_called)
+ usb_bus_mem_free_all(&esc->sc_bus, &ehci_iterate_hw_softc);
+
+ /* During module unload there are lots of children leftover. */
+ device_delete_children(dev);
+
+ return (0);
+}
+
+static int
+tegra_ehci_attach(device_t dev)
+{
+ struct tegra_ehci_softc *sc;
+ ehci_softc_t *esc;
+ int rv, rid;
+ uint64_t freq;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+ esc = &sc->ehci_softc;
+
+ /* Allocate resources. */
+ rid = 0;
+ sc->ehci_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->ehci_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rid = 0;
+ sc->ehci_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->ehci_irq_res == NULL) {
+ device_printf(dev, "Cannot allocate IRQ resources\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rv = hwreset_get_by_ofw_name(dev, "usb", &sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get reset\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rv = phy_get_by_ofw_property(sc->dev, "nvidia,phy", &sc->phy);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'nvidia,phy' phy\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rv = clk_get_by_ofw_index(sc->dev, 0, &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get clock\n");
+ goto out;
+ }
+
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable clock\n");
+ goto out;
+ }
+
+ freq = 0;
+ rv = clk_get_freq(sc->clk, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get clock frequency\n");
+ goto out;
+ }
+
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot clear reset: %d\n", rv);
+ rv = ENXIO;
+ goto out;
+ }
+
+ rv = phy_enable(sc->dev, sc->phy);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable phy: %d\n", rv);
+ goto out;
+ }
+
+ /* Fill data for EHCI driver. */
+ esc->sc_vendor_get_port_speed = ehci_get_port_speed_hostc;
+ esc->sc_vendor_post_reset = tegra_ehci_post_reset;
+ esc->sc_io_tag = rman_get_bustag(sc->ehci_mem_res);
+ esc->sc_bus.parent = dev;
+ esc->sc_bus.devices = esc->sc_devices;
+ esc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+ esc->sc_bus.dma_bits = 32;
+
+ /* Allocate all DMA memory. */
+ rv = usb_bus_mem_alloc_all(&esc->sc_bus, USB_GET_DMA_TAG(dev),
+ &ehci_iterate_hw_softc);
+ sc->usb_alloc_called = 1;
+ if (rv != 0) {
+ device_printf(dev, "usb_bus_mem_alloc_all() failed\n");
+ rv = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Set handle to USB related registers subregion used by
+ * generic EHCI driver.
+ */
+ rv = bus_space_subregion(esc->sc_io_tag,
+ rman_get_bushandle(sc->ehci_mem_res),
+ TEGRA_EHCI_REG_OFF, TEGRA_EHCI_REG_SIZE, &esc->sc_io_hdl);
+ if (rv != 0) {
+ device_printf(dev, "Could not create USB memory subregion\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ /* Setup interrupt handler. */
+ rv = bus_setup_intr(dev, sc->ehci_irq_res, INTR_TYPE_BIO, NULL,
+ (driver_intr_t *)ehci_interrupt, esc, &esc->sc_intr_hdl);
+ if (rv != 0) {
+ device_printf(dev, "Could not setup IRQ\n");
+ goto out;
+ }
+
+ /* Add USB bus device. */
+ esc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
+ if (esc->sc_bus.bdev == NULL) {
+ device_printf(dev, "Could not add USB device\n");
+ goto out;
+ }
+ device_set_ivars(esc->sc_bus.bdev, &esc->sc_bus);
+
+ esc->sc_id_vendor = USB_VENDOR_FREESCALE;
+ strlcpy(esc->sc_vendor, "Nvidia", sizeof(esc->sc_vendor));
+
+ /* Set flags that affect ehci_init() behavior. */
+ esc->sc_flags |= EHCI_SCFLG_TT;
+ esc->sc_flags |= EHCI_SCFLG_NORESTERM;
+ rv = ehci_init(esc);
+ if (rv != 0) {
+ device_printf(dev, "USB init failed: %d\n",
+ rv);
+ goto out;
+ }
+ esc->sc_flags |= EHCI_SCFLG_DONEINIT;
+
+ /* Probe the bus. */
+ rv = device_probe_and_attach(esc->sc_bus.bdev);
+ if (rv != 0) {
+ device_printf(dev,
+ "device_probe_and_attach() failed\n");
+ goto out;
+ }
+ return (0);
+
+out:
+ tegra_ehci_detach(dev);
+ return (rv);
+}
+
+static device_method_t ehci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_ehci_probe),
+ DEVMETHOD(device_attach, tegra_ehci_attach),
+ DEVMETHOD(device_detach, tegra_ehci_detach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ DEVMETHOD_END
+};
+
+static driver_t ehci_driver = {
+ "ehci",
+ ehci_methods,
+ sizeof(struct tegra_ehci_softc)
+};
+
+static devclass_t ehci_devclass;
+DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
+MODULE_DEPEND(ehci, usb, 1, 1, 1); \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra_gpio.c b/sys/arm/nvidia/tegra_gpio.c
new file mode 100644
index 0000000..f9a1d4d
--- /dev/null
+++ b/sys/arm/nvidia/tegra_gpio.c
@@ -0,0 +1,480 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Tegra GPIO driver.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define GPIO_LOCK_INIT(_sc) mtx_init(&_sc->sc_mtx, \
+ device_get_nameunit(_sc->sc_dev), "tegra_gpio", MTX_DEF)
+#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
+
+#define GPIO_BANK_OFFS 0x100 /* Bank offset */
+#define GPIO_NUM_BANKS 8 /* Total number per bank */
+#define GPIO_REGS_IN_BANK 4 /* Total registers in bank */
+#define GPIO_PINS_IN_REG 8 /* Total pin in register */
+
+#define GPIO_BANKNUM(n) ((n) / (GPIO_REGS_IN_BANK * GPIO_PINS_IN_REG))
+#define GPIO_PORTNUM(n) (((n) / GPIO_PINS_IN_REG) % GPIO_REGS_IN_BANK)
+#define GPIO_BIT(n) ((n) % GPIO_PINS_IN_REG)
+
+#define GPIO_REGNUM(n) (GPIO_BANKNUM(n) * GPIO_BANK_OFFS + \
+ GPIO_PORTNUM(n) * 4)
+
+#define NGPIO ((GPIO_NUM_BANKS * GPIO_REGS_IN_BANK * GPIO_PINS_IN_REG) - 8)
+
+/* Register offsets */
+#define GPIO_CNF 0x00
+#define GPIO_OE 0x10
+#define GPIO_OUT 0x20
+#define GPIO_IN 0x30
+#define GPIO_INT_STA 0x40
+#define GPIO_INT_ENB 0x50
+#define GPIO_INT_LVL 0x60
+#define GPIO_INT_CLR 0x70
+#define GPIO_MSK_CNF 0x80
+#define GPIO_MSK_OE 0x90
+#define GPIO_MSK_OUT 0xA0
+#define GPIO_MSK_INT_STA 0xC0
+#define GPIO_MSK_INT_ENB 0xD0
+#define GPIO_MSK_INT_LVL 0xE0
+
+char *tegra_gpio_port_names[] = {
+ "A", "B", "C", "D", /* Bank 0 */
+ "E", "F", "G", "H", /* Bank 1 */
+ "I", "J", "K", "L", /* Bank 2 */
+ "M", "N", "O", "P", /* Bank 3 */
+ "Q", "R", "S", "T", /* Bank 4 */
+ "U", "V", "W", "X", /* Bank 5 */
+ "Y", "Z", "AA", "BB", /* Bank 5 */
+ "CC", "DD", "EE" /* Bank 5 */
+};
+
+struct tegra_gpio_softc {
+ device_t dev;
+ device_t sc_busdev;
+ struct mtx sc_mtx;
+ struct resource *mem_res;
+ struct resource *irq_res;
+ void *gpio_ih;
+ int gpio_npins;
+ struct gpio_pin gpio_pins[NGPIO];
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-gpio", 1},
+ {NULL, 0}
+};
+
+static inline void
+gpio_write_masked(struct tegra_gpio_softc *sc, bus_size_t reg,
+ struct gpio_pin *pin, uint32_t val)
+{
+ uint32_t tmp;
+ int bit;
+
+ bit = GPIO_BIT(pin->gp_pin);
+ tmp = 0x100 << bit; /* mask */
+ tmp |= (val & 1) << bit; /* value */
+ bus_write_4(sc->mem_res, reg + GPIO_REGNUM(pin->gp_pin), tmp);
+}
+static inline uint32_t
+gpio_read(struct tegra_gpio_softc *sc, bus_size_t reg, struct gpio_pin *pin)
+{
+ int bit;
+ uint32_t val;
+
+ bit = GPIO_BIT(pin->gp_pin);
+ val = bus_read_4(sc->mem_res, reg + GPIO_REGNUM(pin->gp_pin));
+ return (val >> bit) & 1;
+}
+
+static void
+tegra_gpio_pin_configure(struct tegra_gpio_softc *sc, struct gpio_pin *pin,
+ unsigned int flags)
+{
+
+ if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 0)
+ return;
+
+ /* Manage input/output */
+ pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
+ if (flags & GPIO_PIN_OUTPUT) {
+ pin->gp_flags |= GPIO_PIN_OUTPUT;
+ gpio_write_masked(sc, GPIO_MSK_OE, pin, 1);
+ } else {
+ pin->gp_flags |= GPIO_PIN_INPUT;
+ gpio_write_masked(sc, GPIO_MSK_OE, pin, 0);
+ }
+}
+
+static device_t
+tegra_gpio_get_bus(device_t dev)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->sc_busdev);
+}
+
+static int
+tegra_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = NGPIO - 1;
+ return (0);
+}
+
+static int
+tegra_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ *caps = sc->gpio_pins[pin].gp_caps;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct tegra_gpio_softc *sc;
+ int cnf;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ cnf = gpio_read(sc, GPIO_CNF, &sc->gpio_pins[pin]);
+ if (cnf == 0) {
+ GPIO_UNLOCK(sc);
+ return (ENXIO);
+ }
+ *flags = sc->gpio_pins[pin].gp_flags;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct tegra_gpio_softc *sc;
+ int cnf;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ cnf = gpio_read(sc, GPIO_CNF, &sc->gpio_pins[pin]);
+ if (cnf == 0) {
+ /* XXX - allow this for while ....
+ GPIO_UNLOCK(sc);
+ return (ENXIO);
+ */
+ gpio_write_masked(sc, GPIO_MSK_CNF, &sc->gpio_pins[pin], 1);
+ }
+ tegra_gpio_pin_configure(sc, &sc->gpio_pins[pin], flags);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+ GPIO_LOCK(sc);
+ gpio_write_masked(sc, GPIO_MSK_OUT, &sc->gpio_pins[pin], value);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ *val = gpio_read(sc, GPIO_IN, &sc->gpio_pins[pin]);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (pin >= sc->gpio_npins)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ gpio_write_masked(sc, GPIO_MSK_OE, &sc->gpio_pins[pin],
+ gpio_read(sc, GPIO_IN, &sc->gpio_pins[pin]) ^ 1);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+tegra_gpio_intr(void *arg)
+{
+ struct tegra_gpio_softc *sc;
+ uint32_t val;
+ int i;
+
+ sc = arg;
+ for (i = 0; i < NGPIO; i += GPIO_PINS_IN_REG) {
+ /* Clear interrupt */
+ val = bus_read_4(sc->mem_res, GPIO_INT_STA + GPIO_REGNUM(i));
+ val &= bus_read_4(sc->mem_res, GPIO_INT_ENB + GPIO_REGNUM(i));
+ bus_write_4(sc->mem_res, GPIO_INT_CLR + GPIO_REGNUM(i), val);
+ /* Interrupt handling */
+#ifdef not_yet
+ for (j = 0; j < GPIO_PINS_IN_REG; j++) {
+ if (val & (1 << j))
+ handle_irq(i + j);
+ }
+ */
+#endif
+ }
+ return (FILTER_HANDLED);
+}
+
+static int
+tegra_gpio_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Tegra GPIO Controller");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+tegra_gpio_detach(device_t dev)
+{
+ struct tegra_gpio_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
+
+ gpiobus_detach_bus(dev);
+ if (sc->gpio_ih != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->gpio_ih);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+ mtx_destroy(&sc->sc_mtx);
+
+ return(0);
+}
+
+static int
+tegra_gpio_attach(device_t dev)
+{
+ struct tegra_gpio_softc *sc;
+ int i, rid;
+
+ sc = device_get_softc(dev);
+ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ /* Allocate bus_space resources. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ tegra_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate IRQ resources\n");
+ tegra_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ sc->dev = dev;
+ sc->gpio_npins = NGPIO;
+
+ if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
+ tegra_gpio_intr, NULL, sc, &sc->gpio_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ tegra_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ for (i = 0; i < sc->gpio_npins; i++) {
+ sc->gpio_pins[i].gp_pin = i;
+ sc->gpio_pins[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+ snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "gpio_%s.%d",
+ tegra_gpio_port_names[ i / GPIO_PINS_IN_REG],
+ i % GPIO_PINS_IN_REG);
+ sc->gpio_pins[i].gp_flags =
+ gpio_read(sc, GPIO_OE, &sc->gpio_pins[i]) != 0 ?
+ GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+ }
+
+ sc->sc_busdev = gpiobus_attach_bus(dev);
+ if (sc->sc_busdev == NULL) {
+ tegra_gpio_detach(dev);
+ return (ENXIO);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+tegra_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
+ int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
+{
+
+ if (gcells != 2)
+ return (ERANGE);
+ *pin = gpios[0];
+ *flags= gpios[1];
+ return (0);
+}
+
+static phandle_t
+tegra_gpio_get_node(device_t bus, device_t dev)
+{
+
+ /* We only have one child, the GPIO bus, which needs our own node. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t tegra_gpio_methods[] = {
+ DEVMETHOD(device_probe, tegra_gpio_probe),
+ DEVMETHOD(device_attach, tegra_gpio_attach),
+ DEVMETHOD(device_detach, tegra_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_get_bus, tegra_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, tegra_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, tegra_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, tegra_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, tegra_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, tegra_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, tegra_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, tegra_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, tegra_gpio_pin_toggle),
+ DEVMETHOD(gpio_map_gpios, tegra_map_gpios),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, tegra_gpio_get_node),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra_gpio_driver = {
+ "gpio",
+ tegra_gpio_methods,
+ sizeof(struct tegra_gpio_softc),
+};
+static devclass_t tegra_gpio_devclass;
+
+EARLY_DRIVER_MODULE(tegra_gpio, simplebus, tegra_gpio_driver,
+ tegra_gpio_devclass, 0, 0, 70);
diff --git a/sys/arm/nvidia/tegra_i2c.c b/sys/arm/nvidia/tegra_i2c.c
new file mode 100644
index 0000000..65d8935
--- /dev/null
+++ b/sys/arm/nvidia/tegra_i2c.c
@@ -0,0 +1,804 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * I2C driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "iicbus_if.h"
+
+#define I2C_CNFG 0x000
+#define I2C_CNFG_MSTR_CLR_BUS_ON_TIMEOUT (1 << 15)
+#define I2C_CNFG_DEBOUNCE_CNT(x) (((x) & 0x07) << 12)
+#define I2C_CNFG_NEW_MASTER_FSM (1 << 11)
+#define I2C_CNFG_PACKET_MODE_EN (1 << 10)
+#define I2C_CNFG_SEND (1 << 9)
+#define I2C_CNFG_NOACK (1 << 8)
+#define I2C_CNFG_CMD2 (1 << 7)
+#define I2C_CNFG_CMD1 (1 << 6)
+#define I2C_CNFG_START (1 << 5)
+#define I2C_CNFG_SLV2 (1 << 4)
+#define I2C_CNFG_LENGTH_SHIFT 1
+#define I2C_CNFG_LENGTH_MASK 0x7
+#define I2C_CNFG_A_MOD (1 << 0)
+
+#define I2C_CMD_ADDR0 0x004
+#define I2C_CMD_ADDR1 0x008
+#define I2C_CMD_DATA1 0x00c
+#define I2C_CMD_DATA2 0x010
+#define I2C_STATUS 0x01c
+#define I2C_SL_CNFG 0x020
+#define I2C_SL_RCVD 0x024
+#define I2C_SL_STATUS 0x028
+#define I2C_SL_ADDR1 0x02c
+#define I2C_SL_ADDR2 0x030
+#define I2C_TLOW_SEXT 0x034
+#define I2C_SL_DELAY_COUNT 0x03c
+#define I2C_SL_INT_MASK 0x040
+#define I2C_SL_INT_SOURCE 0x044
+#define I2C_SL_INT_SET 0x048
+#define I2C_TX_PACKET_FIFO 0x050
+#define I2C_RX_FIFO 0x054
+#define I2C_PACKET_TRANSFER_STATUS 0x058
+#define I2C_FIFO_CONTROL 0x05c
+#define I2C_FIFO_CONTROL_SLV_TX_FIFO_TRIG(x) (((x) & 0x07) << 13)
+#define I2C_FIFO_CONTROL_SLV_RX_FIFO_TRIG(x) (((x) & 0x07) << 10)
+#define I2C_FIFO_CONTROL_SLV_TX_FIFO_FLUSH (1 << 9)
+#define I2C_FIFO_CONTROL_SLV_RX_FIFO_FLUSH (1 << 8)
+#define I2C_FIFO_CONTROL_TX_FIFO_TRIG(x) (((x) & 0x07) << 5)
+#define I2C_FIFO_CONTROL_RX_FIFO_TRIG(x) (((x) & 0x07) << 2)
+#define I2C_FIFO_CONTROL_TX_FIFO_FLUSH (1 << 1)
+#define I2C_FIFO_CONTROL_RX_FIFO_FLUSH (1 << 0)
+
+#define I2C_FIFO_STATUS 0x060
+#define I2C_FIFO_STATUS_SLV_XFER_ERR_REASON (1 << 25)
+#define I2C_FIFO_STATUS_TX_FIFO_SLV_EMPTY_CNT(x) (((x) >> 20) & 0xF)
+#define I2C_FIFO_STATUS_RX_FIFO_SLV_FULL_CNT(x) (((x) >> 16) & 0xF)
+#define I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT(x) (((x) >> 4) & 0xF)
+#define I2C_FIFO_STATUS_RX_FIFO_FULL_CNT(x) (((x) >> 0) & 0xF)
+
+#define I2C_INTERRUPT_MASK_REGISTER 0x064
+#define I2C_INTERRUPT_STATUS_REGISTER 0x068
+#define I2C_INT_SLV_ACK_WITHHELD (1 << 28)
+#define I2C_INT_SLV_RD2WR (1 << 27)
+#define I2C_INT_SLV_WR2RD (1 << 26)
+#define I2C_INT_SLV_PKT_XFER_ERR (1 << 25)
+#define I2C_INT_SLV_TX_BUFFER_REQ (1 << 24)
+#define I2C_INT_SLV_RX_BUFFER_FILLED (1 << 23)
+#define I2C_INT_SLV_PACKET_XFER_COMPLETE (1 << 22)
+#define I2C_INT_SLV_TFIFO_OVF (1 << 21)
+#define I2C_INT_SLV_RFIFO_UNF (1 << 20)
+#define I2C_INT_SLV_TFIFO_DATA_REQ (1 << 17)
+#define I2C_INT_SLV_RFIFO_DATA_REQ (1 << 16)
+#define I2C_INT_BUS_CLEAR_DONE (1 << 11)
+#define I2C_INT_TLOW_MEXT_TIMEOUT (1 << 10)
+#define I2C_INT_TLOW_SEXT_TIMEOUT (1 << 9)
+#define I2C_INT_TIMEOUT (1 << 8)
+#define I2C_INT_PACKET_XFER_COMPLETE (1 << 7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1 << 6)
+#define I2C_INT_TFIFO_OVR (1 << 5)
+#define I2C_INT_RFIFO_UNF (1 << 4)
+#define I2C_INT_NOACK (1 << 3)
+#define I2C_INT_ARB_LOST (1 << 2)
+#define I2C_INT_TFIFO_DATA_REQ (1 << 1)
+#define I2C_INT_RFIFO_DATA_REQ (1 << 0)
+#define I2C_ERROR_MASK (I2C_INT_ARB_LOST | I2C_INT_NOACK | \
+ I2C_INT_RFIFO_UNF | I2C_INT_TFIFO_OVR)
+
+#define I2C_CLK_DIVISOR 0x06c
+#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16
+#define I2C_CLK_DIVISOR_STD_FAST_MODE_MASK 0xffff
+#define I2C_CLK_DIVISOR_HSMODE_SHIFT 0
+#define I2C_CLK_DIVISOR_HSMODE_MASK 0xffff
+#define I2C_INTERRUPT_SOURCE_REGISTER 0x070
+#define I2C_INTERRUPT_SET_REGISTER 0x074
+#define I2C_SLV_TX_PACKET_FIFO 0x07c
+#define I2C_SLV_PACKET_STATUS 0x080
+#define I2C_BUS_CLEAR_CONFIG 0x084
+#define I2C_BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD(x) (((x) & 0xFF) << 16)
+#define I2C_BUS_CLEAR_CONFIG_BC_STOP_COND (1 << 2)
+#define I2C_BUS_CLEAR_CONFIG_BC_TERMINATE (1 << 1)
+#define I2C_BUS_CLEAR_CONFIG_BC_ENABLE (1 << 0)
+
+#define I2C_BUS_CLEAR_STATUS 0x088
+#define I2C_BUS_CLEAR_STATUS_BC_STATUS (1 << 0)
+
+#define I2C_CONFIG_LOAD 0x08c
+#define I2C_CONFIG_LOAD_TIMEOUT_CONFIG_LOAD (1 << 2)
+#define I2C_CONFIG_LOAD_SLV_CONFIG_LOAD (1 << 1)
+#define I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD (1 << 0)
+
+#define I2C_INTERFACE_TIMING_0 0x094
+#define I2C_INTERFACE_TIMING_1 0x098
+#define I2C_HS_INTERFACE_TIMING_0 0x09c
+#define I2C_HS_INTERFACE_TIMING_1 0x0a0
+
+/* Protocol header 0 */
+#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
+#define PACKET_HEADER0_HEADER_SIZE_MASK 0x3
+#define PACKET_HEADER0_PACKET_ID_SHIFT 16
+#define PACKET_HEADER0_PACKET_ID_MASK 0xff
+#define PACKET_HEADER0_CONT_ID_SHIFT 12
+#define PACKET_HEADER0_CONT_ID_MASK 0xf
+#define PACKET_HEADER0_PROTOCOL_I2C (1 << 4)
+#define PACKET_HEADER0_TYPE_SHIFT 0
+#define PACKET_HEADER0_TYPE_MASK 0x7
+
+/* I2C header */
+#define I2C_HEADER_HIGHSPEED_MODE (1 << 22)
+#define I2C_HEADER_CONT_ON_NAK (1 << 21)
+#define I2C_HEADER_SEND_START_BYTE (1 << 20)
+#define I2C_HEADER_READ (1 << 19)
+#define I2C_HEADER_10BIT_ADDR (1 << 18)
+#define I2C_HEADER_IE_ENABLE (1 << 17)
+#define I2C_HEADER_REPEAT_START (1 << 16)
+#define I2C_HEADER_CONTINUE_XFER (1 << 15)
+#define I2C_HEADER_MASTER_ADDR_SHIFT 12
+#define I2C_HEADER_MASTER_ADDR_MASK 0x7
+#define I2C_HEADER_SLAVE_ADDR_SHIFT 0
+#define I2C_HEADER_SLAVE_ADDR_MASK 0x3ff
+
+#define I2C_CLK_DIVISOR_STD_FAST_MODE 0x19
+#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8
+
+#define I2C_REQUEST_TIMEOUT (5 * hz)
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
+
+#define LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define SLEEP(_sc, timeout) \
+ mtx_sleep(sc, &sc->mtx, 0, "i2cbuswait", timeout);
+#define LOCK_INIT(_sc) \
+ mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_i2c", MTX_DEF)
+#define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx)
+#define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
+#define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED)
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-i2c", 1},
+ {NULL, 0}
+};
+enum tegra_i2c_xfer_type {
+ XFER_STOP, /* Send stop condition after xfer */
+ XFER_REPEAT_START, /* Send repeated start after xfer */
+ XFER_CONTINUE /* Don't send nothing */
+} ;
+
+struct tegra_i2c_softc {
+ device_t dev;
+ struct mtx mtx;
+
+ struct resource *mem_res;
+ struct resource *irq_res;
+ void *irq_h;
+
+ device_t iicbus;
+ clk_t clk;
+ hwreset_t reset;
+ uint32_t core_freq;
+ uint32_t bus_freq;
+ int bus_inuse;
+
+ struct iic_msg *msg;
+ int msg_idx;
+ uint32_t bus_err;
+ int done;
+};
+
+static int
+tegra_i2c_flush_fifo(struct tegra_i2c_softc *sc)
+{
+ int timeout;
+ uint32_t reg;
+
+ reg = RD4(sc, I2C_FIFO_CONTROL);
+ reg |= I2C_FIFO_CONTROL_TX_FIFO_FLUSH | I2C_FIFO_CONTROL_RX_FIFO_FLUSH;
+ WR4(sc, I2C_FIFO_CONTROL, reg);
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = RD4(sc, I2C_FIFO_CONTROL);
+ reg &= I2C_FIFO_CONTROL_TX_FIFO_FLUSH |
+ I2C_FIFO_CONTROL_RX_FIFO_FLUSH;
+ if (reg == 0)
+ break;
+ DELAY(10);
+ }
+ if (timeout <= 0) {
+ device_printf(sc->dev, "FIFO flush timedout\n");
+ return (ETIMEDOUT);
+ }
+ return (0);
+}
+
+static void
+tegra_i2c_setup_clk(struct tegra_i2c_softc *sc, int clk_freq)
+{
+ int div;
+
+ div = ((sc->core_freq / clk_freq) / 10) - 1;
+ if ((sc->core_freq / (10 * (div + 1))) > clk_freq)
+ div++;
+ if (div > 65535)
+ div = 65535;
+ WR4(sc, I2C_CLK_DIVISOR,
+ (1 << I2C_CLK_DIVISOR_HSMODE_SHIFT) |
+ (div << I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT));
+}
+
+static void
+tegra_i2c_bus_clear(struct tegra_i2c_softc *sc)
+{
+ int timeout;
+ uint32_t reg, status;
+
+ WR4(sc, I2C_BUS_CLEAR_CONFIG,
+ I2C_BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD(18) |
+ I2C_BUS_CLEAR_CONFIG_BC_STOP_COND |
+ I2C_BUS_CLEAR_CONFIG_BC_TERMINATE);
+
+ WR4(sc, I2C_CONFIG_LOAD, I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (RD4(sc, I2C_CONFIG_LOAD) == 0)
+ break;
+ DELAY(10);
+ }
+ if (timeout <= 0)
+ device_printf(sc->dev, "config load timeouted\n");
+ reg = RD4(sc, I2C_BUS_CLEAR_CONFIG);
+ reg |= I2C_BUS_CLEAR_CONFIG_BC_ENABLE;
+ WR4(sc, I2C_BUS_CLEAR_CONFIG,reg);
+
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if ((RD4(sc, I2C_BUS_CLEAR_CONFIG) &
+ I2C_BUS_CLEAR_CONFIG_BC_ENABLE) == 0)
+ break;
+ DELAY(10);
+ }
+ if (timeout <= 0)
+ device_printf(sc->dev, "bus clear timeouted\n");
+
+ status = RD4(sc, I2C_BUS_CLEAR_STATUS);
+ if ((status & I2C_BUS_CLEAR_STATUS_BC_STATUS) == 0)
+ device_printf(sc->dev, "bus clear failed\n");
+}
+
+static int
+tegra_i2c_hw_init(struct tegra_i2c_softc *sc)
+{
+ int rv, timeout;
+
+ /* Reset the core. */
+ rv = hwreset_assert(sc->reset);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert reset\n");
+ return (rv);
+ }
+ DELAY(10);
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot clear reset\n");
+ return (rv);
+ }
+
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
+ WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, 0xFFFFFFFF);
+ WR4(sc, I2C_CNFG, I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+ I2C_CNFG_DEBOUNCE_CNT(2));
+
+ tegra_i2c_setup_clk(sc, sc->bus_freq);
+
+ WR4(sc, I2C_FIFO_CONTROL, I2C_FIFO_CONTROL_TX_FIFO_TRIG(7) |
+ I2C_FIFO_CONTROL_RX_FIFO_TRIG(0));
+
+ WR4(sc, I2C_CONFIG_LOAD, I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (RD4(sc, I2C_CONFIG_LOAD) == 0)
+ break;
+ DELAY(10);
+ }
+ if (timeout <= 0)
+ device_printf(sc->dev, "config load timeouted\n");
+
+ tegra_i2c_bus_clear(sc);
+ return (0);
+}
+
+static int
+tegra_i2c_tx(struct tegra_i2c_softc *sc)
+{
+ uint32_t reg;
+ int cnt, i;
+
+ if (sc->msg_idx >= sc->msg->len)
+ panic("Invalid call to tegra_i2c_tx\n");
+
+ while(sc->msg_idx < sc->msg->len) {
+ reg = RD4(sc, I2C_FIFO_STATUS);
+ if (I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT(reg) == 0)
+ break;
+ cnt = min(4, sc->msg->len - sc->msg_idx);
+ reg = 0;
+ for (i = 0; i < cnt; i++) {
+ reg |= sc->msg->buf[sc->msg_idx] << (i * 8);
+ sc->msg_idx++;
+ }
+ WR4(sc, I2C_TX_PACKET_FIFO, reg);
+ }
+ if (sc->msg_idx >= sc->msg->len)
+ return (0);
+ return (sc->msg->len - sc->msg_idx - 1);
+}
+
+static int
+tegra_i2c_rx(struct tegra_i2c_softc *sc)
+{
+ uint32_t reg;
+ int cnt, i;
+
+ if (sc->msg_idx >= sc->msg->len)
+ panic("Invalid call to tegra_i2c_rx\n");
+
+ while(sc->msg_idx < sc->msg->len) {
+ reg = RD4(sc, I2C_FIFO_STATUS);
+ if (I2C_FIFO_STATUS_RX_FIFO_FULL_CNT(reg) == 0)
+ break;
+ cnt = min(4, sc->msg->len - sc->msg_idx);
+ reg = RD4(sc, I2C_RX_FIFO);
+ for (i = 0; i < cnt; i++) {
+ sc->msg->buf[sc->msg_idx] = (reg >> (i * 8)) & 0xFF;
+ sc->msg_idx++;
+ }
+ }
+
+ if (sc->msg_idx >= sc->msg->len)
+ return (0);
+ return (sc->msg->len - sc->msg_idx - 1);
+}
+
+static void
+tegra_i2c_intr(void *arg)
+{
+ struct tegra_i2c_softc *sc;
+ uint32_t status, reg;
+ int rv;
+
+ sc = (struct tegra_i2c_softc *)arg;
+
+ LOCK(sc);
+ status = RD4(sc, I2C_INTERRUPT_SOURCE_REGISTER);
+ if (sc->msg == NULL) {
+ /* Unexpected interrupt - disable FIFOs, clear reset. */
+ reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
+ reg &= ~I2C_INT_TFIFO_DATA_REQ;
+ reg &= ~I2C_INT_RFIFO_DATA_REQ;
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
+ WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status);
+ UNLOCK(sc);
+ return;
+ }
+
+ if ((status & I2C_ERROR_MASK) != 0) {
+ if (status & I2C_INT_NOACK)
+ sc->bus_err = IIC_ENOACK;
+ if (status & I2C_INT_ARB_LOST)
+ sc->bus_err = IIC_EBUSERR;
+ if ((status & I2C_INT_TFIFO_OVR) ||
+ (status & I2C_INT_RFIFO_UNF))
+ sc->bus_err = IIC_EBUSERR;
+ sc->done = 1;
+ } else if ((status & I2C_INT_RFIFO_DATA_REQ) &&
+ (sc->msg != NULL) && (sc->msg->flags & IIC_M_RD)) {
+ rv = tegra_i2c_rx(sc);
+ if (rv == 0) {
+ reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
+ reg &= ~I2C_INT_RFIFO_DATA_REQ;
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
+ }
+ } else if ((status & I2C_INT_TFIFO_DATA_REQ) &&
+ (sc->msg != NULL) && !(sc->msg->flags & IIC_M_RD)) {
+ rv = tegra_i2c_tx(sc);
+ if (rv == 0) {
+ reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
+ reg &= ~I2C_INT_TFIFO_DATA_REQ;
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
+ }
+ } else if ((status & I2C_INT_RFIFO_DATA_REQ) ||
+ (status & I2C_INT_TFIFO_DATA_REQ)) {
+ device_printf(sc->dev, "Unexpected data interrupt: 0x%08X\n",
+ status);
+ reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER);
+ reg &= ~I2C_INT_TFIFO_DATA_REQ;
+ reg &= ~I2C_INT_RFIFO_DATA_REQ;
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg);
+ }
+ if (status & I2C_INT_PACKET_XFER_COMPLETE)
+ sc->done = 1;
+ WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status);
+ if (sc->done) {
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
+ wakeup(&(sc->done));
+ }
+ UNLOCK(sc);
+}
+
+static void
+tegra_i2c_start_msg(struct tegra_i2c_softc *sc, struct iic_msg *msg,
+ enum tegra_i2c_xfer_type xtype)
+{
+ uint32_t tmp, mask;
+
+ /* Packet header. */
+ tmp = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
+ PACKET_HEADER0_PROTOCOL_I2C |
+ (1 << PACKET_HEADER0_CONT_ID_SHIFT) |
+ (1 << PACKET_HEADER0_PACKET_ID_SHIFT);
+ WR4(sc, I2C_TX_PACKET_FIFO, tmp);
+
+
+ /* Packet size. */
+ WR4(sc, I2C_TX_PACKET_FIFO, msg->len - 1);
+
+ /* I2C header. */
+ tmp = I2C_HEADER_IE_ENABLE;
+ if (xtype == XFER_CONTINUE)
+ tmp |= I2C_HEADER_CONTINUE_XFER;
+ else if (xtype == XFER_REPEAT_START)
+ tmp |= I2C_HEADER_REPEAT_START;
+ tmp |= msg->slave << I2C_HEADER_SLAVE_ADDR_SHIFT;
+ if (msg->flags & IIC_M_RD) {
+ tmp |= I2C_HEADER_READ;
+ tmp |= 1 << I2C_HEADER_SLAVE_ADDR_SHIFT;
+ } else
+ tmp &= ~(1 << I2C_HEADER_SLAVE_ADDR_SHIFT);
+
+ WR4(sc, I2C_TX_PACKET_FIFO, tmp);
+
+ /* Interrupt mask. */
+ mask = I2C_INT_NOACK | I2C_INT_ARB_LOST | I2C_INT_PACKET_XFER_COMPLETE;
+ if (msg->flags & IIC_M_RD)
+ mask |= I2C_INT_RFIFO_DATA_REQ;
+ else
+ mask |= I2C_INT_TFIFO_DATA_REQ;
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, mask);
+}
+
+static int
+tegra_i2c_poll(struct tegra_i2c_softc *sc)
+{
+ int timeout;
+
+ for(timeout = 10000; timeout > 0; timeout--) {
+ UNLOCK(sc);
+ tegra_i2c_intr(sc);
+ LOCK(sc);
+ if (sc->done != 0)
+ break;
+ DELAY(1);
+ }
+ if (timeout <= 0)
+ return (ETIMEDOUT);
+ return (0);
+}
+
+static int
+tegra_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+ int rv, i;
+ struct tegra_i2c_softc *sc;
+ enum tegra_i2c_xfer_type xtype;
+
+ sc = device_get_softc(dev);
+ LOCK(sc);
+
+ /* Get the bus. */
+ while (sc->bus_inuse == 1)
+ SLEEP(sc, 0);
+ sc->bus_inuse = 1;
+
+ rv = 0;
+ for (i = 0; i < nmsgs; i++) {
+ sc->msg = &msgs[i];
+ sc->msg_idx = 0;
+ sc->bus_err = 0;
+ sc->done = 0;
+ /* Check for valid parameters. */
+ if (sc->msg == NULL || sc->msg->buf == NULL ||
+ sc->msg->len == 0) {
+ rv = EINVAL;
+ break;
+ }
+
+ /* Get flags for next transfer. */
+ if (i == (nmsgs - 1)) {
+ if (msgs[i].flags & IIC_M_NOSTOP)
+ xtype = XFER_CONTINUE;
+ else
+ xtype = XFER_STOP;
+ } else {
+ if (msgs[i + 1].flags & IIC_M_NOSTART)
+ xtype = XFER_CONTINUE;
+ else
+ xtype = XFER_REPEAT_START;
+ }
+ tegra_i2c_start_msg(sc, sc->msg, xtype);
+ if (cold)
+ rv = tegra_i2c_poll(sc);
+ else
+ rv = msleep(&sc->done, &sc->mtx, PZERO, "iic",
+ I2C_REQUEST_TIMEOUT);
+
+ WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0);
+ WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, 0xFFFFFFFF);
+ if (rv == 0)
+ rv = sc->bus_err;
+ if (rv != 0)
+ break;
+ }
+
+ if (rv != 0) {
+ tegra_i2c_hw_init(sc);
+ tegra_i2c_flush_fifo(sc);
+ }
+
+ sc->msg = NULL;
+ sc->msg_idx = 0;
+ sc->bus_err = 0;
+ sc->done = 0;
+
+ /* Wake up the processes that are waiting for the bus. */
+ sc->bus_inuse = 0;
+ wakeup(sc);
+ UNLOCK(sc);
+
+ return (rv);
+}
+
+static int
+tegra_i2c_iicbus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ struct tegra_i2c_softc *sc;
+ int busfreq;
+
+ sc = device_get_softc(dev);
+ busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed);
+ sc = device_get_softc(dev);
+ LOCK(sc);
+ tegra_i2c_setup_clk(sc, busfreq);
+ UNLOCK(sc);
+ return (0);
+}
+
+static int
+tegra_i2c_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_i2c_attach(device_t dev)
+{
+ int rv, rid;
+ phandle_t node;
+ struct tegra_i2c_softc *sc;
+ uint64_t freq;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+
+ LOCK_INIT(sc);
+
+ /* Get the memory resource for the register mapping. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot map registers.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate our IRQ resource. */
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate interrupt.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* FDT resources. */
+ rv = clk_get_by_ofw_name(dev, "div-clk", &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get i2c clock: %d\n", rv);
+ goto fail;
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "i2c", &sc->reset);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get i2c reset\n");
+ return (ENXIO);
+ }
+ rv = OF_getencprop(node, "clock-frequency", &sc->bus_freq,
+ sizeof(sc->bus_freq));
+ if (rv != sizeof(sc->bus_freq)) {
+ sc->bus_freq = 100000;
+ goto fail;
+ }
+
+ /* Request maximum frequency for I2C block 136MHz (408MHz / 3). */
+ rv = clk_set_freq(sc->clk, 136000000, CLK_SET_ROUND_DOWN);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set clock frequency\n");
+ goto fail;
+ }
+ rv = clk_get_freq(sc->clk, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get clock frequency\n");
+ goto fail;
+ }
+ sc->core_freq = (uint32_t)freq;
+
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable clock: %d\n", rv);
+ goto fail;
+ }
+
+ /* Init hardware. */
+ rv = tegra_i2c_hw_init(sc);
+ if (rv) {
+ device_printf(dev, "tegra_i2c_activate failed\n");
+ goto fail;
+ }
+
+ /* Setup interrupt. */
+ rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, tegra_i2c_intr, sc, &sc->irq_h);
+ if (rv) {
+ device_printf(dev, "Cannot setup interrupt.\n");
+ goto fail;
+ }
+
+ /* Attach the iicbus. */
+ sc->iicbus = device_add_child(dev, "iicbus", -1);
+ if (sc->iicbus == NULL) {
+ device_printf(dev, "Could not allocate iicbus instance.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* Probe and attach the iicbus. */
+ return (bus_generic_attach(dev));
+
+fail:
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+ LOCK_DESTROY(sc);
+
+ return (rv);
+}
+
+static int
+tegra_i2c_detach(device_t dev)
+{
+ struct tegra_i2c_softc *sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ tegra_i2c_hw_init(sc);
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ LOCK_DESTROY(sc);
+ if (sc->iicbus)
+ rv = device_delete_child(dev, sc->iicbus);
+ return (bus_generic_detach(dev));
+}
+
+static phandle_t
+tegra_i2c_get_node(device_t bus, device_t dev)
+{
+
+ /* Share controller node with iibus device. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t tegra_i2c_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_i2c_probe),
+ DEVMETHOD(device_attach, tegra_i2c_attach),
+ DEVMETHOD(device_detach, tegra_i2c_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+
+ /* OFW methods */
+ DEVMETHOD(ofw_bus_get_node, tegra_i2c_get_node),
+
+ /* iicbus interface */
+ DEVMETHOD(iicbus_callback, iicbus_null_callback),
+ DEVMETHOD(iicbus_reset, tegra_i2c_iicbus_reset),
+ DEVMETHOD(iicbus_transfer, tegra_i2c_transfer),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(iichb, tegra_i2c_driver, tegra_i2c_methods,
+ sizeof(struct tegra_i2c_softc));
+static devclass_t tegra_i2c_devclass;
+EARLY_DRIVER_MODULE(iichb, simplebus, tegra_i2c_driver, tegra_i2c_devclass, 0,
+ 0, 73);
diff --git a/sys/arm/nvidia/tegra_lic.c b/sys/arm/nvidia/tegra_lic.c
new file mode 100644
index 0000000..6228c01
--- /dev/null
+++ b/sys/arm/nvidia/tegra_lic.c
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Local interrupt controller driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <machine/fdt.h>
+#include <machine/intr.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "pic_if.h"
+
+#define LIC_VIRQ_CPU 0x00
+#define LIC_VIRQ_COP 0x04
+#define LIC_VFRQ_CPU 0x08
+#define LIC_VFRQ_COP 0x0c
+#define LIC_ISR 0x10
+#define LIC_FIR 0x14
+#define LIC_FIR_SET 0x18
+#define LIC_FIR_CLR 0x1c
+#define LIC_CPU_IER 0x20
+#define LIC_CPU_IER_SET 0x24
+#define LIC_CPU_IER_CLR 0x28
+#define LIC_CPU_IEP_CLASS 0x2C
+#define LIC_COP_IER 0x30
+#define LIC_COP_IER_SET 0x34
+#define LIC_COP_IER_CLR 0x38
+#define LIC_COP_IEP_CLASS 0x3c
+
+#define WR4(_sc, _b, _r, _v) bus_write_4((_sc)->mem_res[_b], (_r), (_v))
+#define RD4(_sc, _b, _r) bus_read_4((_sc)->mem_res[_b], (_r))
+
+static struct resource_spec lic_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 3, RF_ACTIVE },
+ { SYS_RES_MEMORY, 4, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-ictlr", 1},
+ {NULL, 0}
+};
+
+struct tegra_lic_sc {
+ device_t dev;
+ struct resource *mem_res[nitems(lic_spec)];
+ device_t parent;
+};
+
+static int
+tegra_lic_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_ALLOC_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+tegra_lic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ PIC_DISABLE_INTR(sc->parent, isrc);
+}
+
+static void
+tegra_lic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ PIC_ENABLE_INTR(sc->parent, isrc);
+}
+
+static int
+tegra_lic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_MAP_INTR(sc->parent, data, isrcp));
+}
+
+static int
+tegra_lic_release_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_RELEASE_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+tegra_lic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_SETUP_INTR(sc->parent, isrc, res, data));
+}
+
+static int
+tegra_lic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data));
+}
+
+static void
+tegra_lic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ PIC_PRE_ITHREAD(sc->parent, isrc);
+}
+
+
+static void
+tegra_lic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ PIC_POST_ITHREAD(sc->parent, isrc);
+}
+
+static void
+tegra_lic_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ PIC_POST_FILTER(sc->parent, isrc);
+}
+
+#ifdef SMP
+static int
+tegra_lic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct tegra_lic_sc *sc = device_get_softc(dev);
+
+ return (PIC_BIND_INTR(sc->parent, isrc));
+}
+#endif
+
+static int
+tegra_lic_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_lic_attach(device_t dev)
+{
+ struct tegra_lic_sc *sc;
+ phandle_t node;
+ phandle_t parent_xref;
+ int i, rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+
+ rv = OF_getencprop(node, "interrupt-parent", &parent_xref,
+ sizeof(parent_xref));
+ if (rv <= 0) {
+ device_printf(dev, "Cannot read parent node property\n");
+ goto fail;
+ }
+ sc->parent = OF_device_from_xref(parent_xref);
+ if (sc->parent == NULL) {
+ device_printf(dev, "Cannott find parent controller\n");
+ goto fail;
+ }
+
+ if (bus_alloc_resources(dev, lic_spec, sc->mem_res)) {
+ device_printf(dev, "Cannott allocate resources\n");
+ goto fail;
+ }
+
+ /* Disable all interrupts, route all to irq */
+ for (i = 0; i < nitems(lic_spec); i++) {
+ if (sc->mem_res[i] == NULL)
+ continue;
+ WR4(sc, i, LIC_CPU_IER_CLR, 0xFFFFFFFF);
+ WR4(sc, i, LIC_CPU_IEP_CLASS, 0);
+ }
+
+
+ if (intr_pic_register(dev, OF_xref_from_node(node)) != 0) {
+ device_printf(dev, "Cannot register PIC\n");
+ goto fail;
+ }
+ return (0);
+
+fail:
+ bus_release_resources(dev, lic_spec, sc->mem_res);
+ return (ENXIO);
+}
+
+static int
+tegra_lic_detach(device_t dev)
+{
+ struct tegra_lic_sc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+ for (i = 0; i < nitems(lic_spec); i++) {
+ if (sc->mem_res[i] == NULL)
+ continue;
+ bus_release_resource(dev, SYS_RES_MEMORY, i,
+ sc->mem_res[i]);
+ }
+ return (0);
+}
+
+static device_method_t tegra_lic_methods[] = {
+ DEVMETHOD(device_probe, tegra_lic_probe),
+ DEVMETHOD(device_attach, tegra_lic_attach),
+ DEVMETHOD(device_detach, tegra_lic_detach),
+
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_alloc_intr, tegra_lic_alloc_intr),
+ DEVMETHOD(pic_disable_intr, tegra_lic_disable_intr),
+ DEVMETHOD(pic_enable_intr, tegra_lic_enable_intr),
+ DEVMETHOD(pic_map_intr, tegra_lic_map_intr),
+ DEVMETHOD(pic_release_intr, tegra_lic_release_intr),
+ DEVMETHOD(pic_setup_intr, tegra_lic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, tegra_lic_teardown_intr),
+ DEVMETHOD(pic_pre_ithread, tegra_lic_pre_ithread),
+ DEVMETHOD(pic_post_ithread, tegra_lic_post_ithread),
+ DEVMETHOD(pic_post_filter, tegra_lic_post_filter),
+#ifdef SMP
+ DEVMETHOD(pic_bind_intr, tegra_lic_bind_intr),
+#endif
+ DEVMETHOD_END
+};
+devclass_t tegra_lic_devclass;
+DEFINE_CLASS_0(tegra_lic, tegra_lic_driver, tegra_lic_methods,
+ sizeof(struct tegra_lic_sc));
+EARLY_DRIVER_MODULE(tegra_lic, simplebus, tegra_lic_driver, tegra_lic_devclass,
+ NULL, NULL, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE + 1);
diff --git a/sys/arm/nvidia/tegra_pcie.c b/sys/arm/nvidia/tegra_pcie.c
new file mode 100644
index 0000000..e63ea47
--- /dev/null
+++ b/sys/arm/nvidia/tegra_pcie.c
@@ -0,0 +1,1691 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Nvidia Integrated PCI/PCI-Express controller driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/endian.h>
+
+#include <machine/intr.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include <machine/devmap.h>
+#include <machine/resource.h>
+#include <machine/bus.h>
+
+#include "ofw_bus_if.h"
+#include "pcib_if.h"
+
+#include <arm/nvidia/tegra_pmc.h>
+
+/* --- Move to ofw_pci.c/.h ----------------------- */
+
+struct tegra_pci_range {
+ /* parsed phys.hi */
+ int nonrelocatable;
+ int prefetchable;
+ int aliased;
+ int space_code; /* In native format (not shifted)*/
+ int bus;
+ int device;
+ int function;
+ int reg;
+ pci_addr_t pci_addr; /* PCI Address */
+ bus_addr_t host_addr; /* Host bus address*/
+ bus_size_t size; /* Range size */
+};
+
+static int
+tegra_pci_get_ranges(phandle_t node, struct tegra_pci_range **ranges)
+{
+ int host_address_cells, pci_address_cells, size_cells;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int nranges;
+ int i, j, k;
+ uint32_t flags;
+ uint64_t tmp;
+
+ host_address_cells = 1;
+ pci_address_cells = 3;
+ size_cells = 2;
+ OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
+ sizeof(host_address_cells));
+ OF_getencprop(node, "#address-cells", &pci_address_cells,
+ sizeof(pci_address_cells));
+ OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+ nranges = nbase_ranges / sizeof(cell_t) /
+ (pci_address_cells + host_address_cells + size_cells);
+
+ *ranges = malloc(nranges * sizeof(struct tegra_pci_range),
+ M_DEVBUF, M_WAITOK);
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < nranges; i++) {
+ flags = base_ranges[j++];
+ (*ranges)[i].nonrelocatable =
+ flags & OFW_PCI_PHYS_HI_NONRELOCATABLE ? 1 : 0;
+ (*ranges)[i].prefetchable =
+ flags & OFW_PCI_PHYS_HI_PREFETCHABLE ? 1 : 0;
+ (*ranges)[i].aliased =
+ flags & OFW_PCI_PHYS_HI_ALIASED ? 1 : 0;
+ (*ranges)[i].space_code = flags & OFW_PCI_PHYS_HI_SPACEMASK;
+ (*ranges)[i].bus = OFW_PCI_PHYS_HI_BUS(flags);
+ (*ranges)[i].device = OFW_PCI_PHYS_HI_DEVICE(flags);
+ (*ranges)[i].function = OFW_PCI_PHYS_HI_FUNCTION(flags);
+ (*ranges)[i].reg = flags & OFW_PCI_PHYS_HI_REGISTERMASK;
+
+ tmp = 0;
+ for (k = 0; k < pci_address_cells - 1; k++) {
+ tmp <<= 32;
+ tmp |= base_ranges[j++];
+ }
+ (*ranges)[i].pci_addr = (pci_addr_t)tmp;
+
+ tmp = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ tmp <<= 32;
+ tmp |= base_ranges[j++];
+ }
+ (*ranges)[i].host_addr = (bus_addr_t)tmp;
+ tmp = 0;
+
+ for (k = 0; k < size_cells; k++) {
+ tmp <<= 32;
+ tmp |= base_ranges[j++];
+ }
+ (*ranges)[i].size = (bus_size_t)tmp;
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (nranges);
+}
+
+/* -------------------------------------------------------------------------- */
+#define AFI_AXI_BAR0_SZ 0x000
+#define AFI_AXI_BAR1_SZ 0x004
+#define AFI_AXI_BAR2_SZ 0x008
+#define AFI_AXI_BAR3_SZ 0x00c
+#define AFI_AXI_BAR4_SZ 0x010
+#define AFI_AXI_BAR5_SZ 0x014
+#define AFI_AXI_BAR0_START 0x018
+#define AFI_AXI_BAR1_START 0x01c
+#define AFI_AXI_BAR2_START 0x020
+#define AFI_AXI_BAR3_START 0x024
+#define AFI_AXI_BAR4_START 0x028
+#define AFI_AXI_BAR5_START 0x02c
+#define AFI_FPCI_BAR0 0x030
+#define AFI_FPCI_BAR1 0x034
+#define AFI_FPCI_BAR2 0x038
+#define AFI_FPCI_BAR3 0x03c
+#define AFI_FPCI_BAR4 0x040
+#define AFI_FPCI_BAR5 0x044
+#define AFI_MSI_BAR_SZ 0x060
+#define AFI_MSI_FPCI_BAR_ST 0x064
+#define AFI_MSI_AXI_BAR_ST 0x068
+
+
+#define AFI_AXI_BAR6_SZ 0x134
+#define AFI_AXI_BAR7_SZ 0x138
+#define AFI_AXI_BAR8_SZ 0x13c
+#define AFI_AXI_BAR6_START 0x140
+#define AFI_AXI_BAR7_START 0x144
+#define AFI_AXI_BAR8_START 0x148
+#define AFI_FPCI_BAR6 0x14c
+#define AFI_FPCI_BAR7 0x150
+#define AFI_FPCI_BAR8 0x154
+
+#define AFI_CONFIGURATION 0x0ac
+#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS 0x0b0
+#define AFI_INTR_MASK 0x0b4
+#define AFI_INTR_MASK_MSI_MASK (1 << 8)
+#define AFI_INTR_MASK_INT_MASK (1 << 0)
+
+#define AFI_INTR_CODE 0x0b8
+#define AFI_INTR_CODE_MASK 0xf
+#define AFI_INTR_CODE_INT_CODE_INI_SLVERR 1
+#define AFI_INTR_CODE_INT_CODE_INI_DECERR 2
+#define AFI_INTR_CODE_INT_CODE_TGT_SLVERR 3
+#define AFI_INTR_CODE_INT_CODE_TGT_DECERR 4
+#define AFI_INTR_CODE_INT_CODE_TGT_WRERR 5
+#define AFI_INTR_CODE_INT_CODE_SM_MSG 6
+#define AFI_INTR_CODE_INT_CODE_DFPCI_DECERR 7
+#define AFI_INTR_CODE_INT_CODE_AXI_DECERR 8
+#define AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT 9
+#define AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE 10
+#define AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE 11
+#define AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE 12
+#define AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE 13
+#define AFI_INTR_CODE_INT_CODE_P2P_ERROR 14
+
+
+#define AFI_INTR_SIGNATURE 0x0bc
+#define AFI_UPPER_FPCI_ADDRESS 0x0c0
+#define AFI_SM_INTR_ENABLE 0x0c4
+#define AFI_SM_INTR_RP_DEASSERT (1 << 14)
+#define AFI_SM_INTR_RP_ASSERT (1 << 13)
+#define AFI_SM_INTR_HOTPLUG (1 << 12)
+#define AFI_SM_INTR_PME (1 << 11)
+#define AFI_SM_INTR_FATAL_ERROR (1 << 10)
+#define AFI_SM_INTR_UNCORR_ERROR (1 << 9)
+#define AFI_SM_INTR_CORR_ERROR (1 << 8)
+#define AFI_SM_INTR_INTD_DEASSERT (1 << 7)
+#define AFI_SM_INTR_INTC_DEASSERT (1 << 6)
+#define AFI_SM_INTR_INTB_DEASSERT (1 << 5)
+#define AFI_SM_INTR_INTA_DEASSERT (1 << 4)
+#define AFI_SM_INTR_INTD_ASSERT (1 << 3)
+#define AFI_SM_INTR_INTC_ASSERT (1 << 2)
+#define AFI_SM_INTR_INTB_ASSERT (1 << 1)
+#define AFI_SM_INTR_INTA_ASSERT (1 << 0)
+
+#define AFI_AFI_INTR_ENABLE 0x0c8
+#define AFI_AFI_INTR_ENABLE_CODE(code) (1 << (code))
+
+#define AFI_PCIE_CONFIG 0x0f8
+#define AFI_PCIE_CONFIG_PCIE_DISABLE(x) (1 << ((x) + 1))
+#define AFI_PCIE_CONFIG_PCIE_DISABLE_ALL 0x6
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1 (0x0 << 20)
+#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1 (0x1 << 20)
+
+#define AFI_FUSE 0x104
+#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
+
+#define AFI_PEX0_CTRL 0x110
+#define AFI_PEX1_CTRL 0x118
+#define AFI_PEX2_CTRL 0x128
+#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4)
+#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
+#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
+#define AFI_PEX_CTRL_RST_L (1 << 0)
+
+#define AFI_AXI_BAR6_SZ 0x134
+#define AFI_AXI_BAR7_SZ 0x138
+#define AFI_AXI_BAR8_SZ 0x13c
+#define AFI_AXI_BAR6_START 0x140
+#define AFI_AXI_BAR7_START 0x144
+#define AFI_AXI_BAR8_START 0x148
+#define AFI_FPCI_BAR6 0x14c
+#define AFI_FPCI_BAR7 0x150
+#define AFI_FPCI_BAR8 0x154
+#define AFI_PLLE_CONTROL 0x160
+#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
+#define AFI_PLLE_CONTROL_BYPASS_PCIE2PLLE_CONTROL (1 << 8)
+#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
+#define AFI_PLLE_CONTROL_PCIE2PLLE_CONTROL_EN (1 << 0)
+
+#define AFI_PEXBIAS_CTRL 0x168
+
+/* FPCI Address space */
+#define FPCI_MAP_IO 0xfdfc000000ULL
+#define FPCI_MAP_TYPE0_CONFIG 0xfdfc000000ULL
+#define FPCI_MAP_TYPE1_CONFIG 0xfdff000000ULL
+#define FPCI_MAP_EXT_TYPE0_CONFIG 0xfe00000000ULL
+#define FPCI_MAP_EXT_TYPE1_CONFIG 0xfe10000000ULL
+
+/* Configuration space */
+#define RP_VEND_XP 0x00000F00
+#define RP_VEND_XP_DL_UP (1 << 30)
+
+#define RP_PRIV_MISC 0x00000FE0
+#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+
+#define RP_LINK_CONTROL_STATUS 0x00000090
+#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
+#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+
+#define TEGRA_PCIE_LINKUP_TIMEOUT 200
+
+#define DEBUG
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+/*
+ * Configuration space format:
+ * [27:24] extended register
+ * [23:16] bus
+ * [15:11] slot (device)
+ * [10: 8] function
+ * [ 7: 0] register
+ */
+#define PCI_CFG_EXT_REG(reg) ((((reg) >> 8) & 0x0f) << 24)
+#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16)
+#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11)
+#define PCI_CFG_FUN(fun) (((fun) & 0x07) << 8)
+#define PCI_CFG_BASE_REG(reg) ((reg) & 0xff)
+
+#define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)-pads_mem_res, (_r), (_v))
+#define PADS_RD4(_sc, _r) bus_read_4((_sc)->pads_mem_res, (_r))
+#define AFI_WR4(_sc, _r, _v) bus_write_4((_sc)->afi_mem_res, (_r), (_v))
+#define AFI_RD4(_sc, _r) bus_read_4((_sc)->afi_mem_res, (_r))
+
+static struct {
+ bus_size_t axi_start;
+ bus_size_t fpci_start;
+ bus_size_t size;
+} bars[] = {
+ {AFI_AXI_BAR0_START, AFI_FPCI_BAR0, AFI_AXI_BAR0_SZ}, /* BAR 0 */
+ {AFI_AXI_BAR1_START, AFI_FPCI_BAR1, AFI_AXI_BAR1_SZ}, /* BAR 1 */
+ {AFI_AXI_BAR2_START, AFI_FPCI_BAR2, AFI_AXI_BAR2_SZ}, /* BAR 2 */
+ {AFI_AXI_BAR3_START, AFI_FPCI_BAR3, AFI_AXI_BAR3_SZ}, /* BAR 3 */
+ {AFI_AXI_BAR4_START, AFI_FPCI_BAR4, AFI_AXI_BAR4_SZ}, /* BAR 4 */
+ {AFI_AXI_BAR5_START, AFI_FPCI_BAR5, AFI_AXI_BAR5_SZ}, /* BAR 5 */
+ {AFI_AXI_BAR6_START, AFI_FPCI_BAR6, AFI_AXI_BAR6_SZ}, /* BAR 6 */
+ {AFI_AXI_BAR7_START, AFI_FPCI_BAR7, AFI_AXI_BAR7_SZ}, /* BAR 7 */
+ {AFI_AXI_BAR8_START, AFI_FPCI_BAR8, AFI_AXI_BAR8_SZ}, /* BAR 8 */
+ {AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ}, /* MSI 9 */
+};
+
+/* Compatible devices. */
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-pcie", 1},
+ {NULL, 0},
+};
+
+struct tegra_pcib_port {
+ int enabled;
+ int port_idx; /* chip port index */
+ int num_lanes; /* number of lanes */
+ bus_size_t afi_pex_ctrl; /* offset of afi_pex_ctrl */
+
+ /* Config space properties. */
+ bus_addr_t rp_base_addr; /* PA of config window */
+ bus_size_t rp_size; /* size of config window */
+ bus_space_handle_t cfg_handle; /* handle of config window */
+};
+
+#define TEGRA_PCIB_MAX_PORTS 3
+struct tegra_pcib_softc {
+ device_t dev;
+ struct mtx mtx;
+ struct ofw_bus_iinfo pci_iinfo;
+ struct rman pref_mem_rman;
+ struct rman mem_rman;
+ struct rman io_rman;
+ struct resource *pads_mem_res;
+ struct resource *afi_mem_res;
+ struct resource *cfg_mem_res;
+ struct resource *irq_res;
+ struct resource *msi_irq_res;
+ void *intr_cookie;
+ void *msi_intr_cookie;
+
+ struct tegra_pci_range mem_range;
+ struct tegra_pci_range pref_mem_range;
+ struct tegra_pci_range io_range;
+
+ phy_t phy;
+ clk_t clk_pex;
+ clk_t clk_afi;
+ clk_t clk_pll_e;
+ clk_t clk_cml;
+ hwreset_t hwreset_pex;
+ hwreset_t hwreset_afi;
+ hwreset_t hwreset_pcie_x;
+ regulator_t supply_avddio_pex;
+ regulator_t supply_dvddio_pex;
+ regulator_t supply_avdd_pex_pll;
+ regulator_t supply_hvdd_pex;
+ regulator_t supply_hvdd_pex_pll_e;
+ regulator_t supply_vddio_pex_ctl;
+ regulator_t supply_avdd_pll_erefe;
+
+ int busnr; /* host bridge bus number */
+ uint32_t msi_bitmap;
+ bus_addr_t cfg_base_addr; /* base address of config */
+ bus_size_t cfg_cur_offs; /* currently mapped window */
+ bus_space_handle_t cfg_handle; /* handle of config window */
+ bus_space_tag_t bus_tag; /* tag of config window */
+ int lanes_cfg;
+ int num_ports;
+ struct tegra_pcib_port *ports[TEGRA_PCIB_MAX_PORTS];
+};
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Resource manager
+ */
+static int
+tegra_pcib_rman_init(struct tegra_pcib_softc *sc)
+{
+ int err;
+ char buf[64];
+
+ /* Memory management. */
+ sc->pref_mem_rman.rm_type = RMAN_ARRAY;
+ snprintf(buf, sizeof(buf), "%s prefetchable memory space",
+ device_get_nameunit(sc->dev));
+ sc->pref_mem_rman.rm_descr = strdup(buf, M_DEVBUF);
+ err = rman_init(&sc->pref_mem_rman);
+ if (err)
+ return (err);
+
+ sc->mem_rman.rm_type = RMAN_ARRAY;
+ snprintf(buf, sizeof(buf), "%s non prefetchable memory space",
+ device_get_nameunit(sc->dev));
+ sc->mem_rman.rm_descr = strdup(buf, M_DEVBUF);
+ err = rman_init(&sc->mem_rman);
+ if (err)
+ return (err);
+
+ sc->io_rman.rm_type = RMAN_ARRAY;
+ snprintf(buf, sizeof(buf), "%s I/O space",
+ device_get_nameunit(sc->dev));
+ sc->io_rman.rm_descr = strdup(buf, M_DEVBUF);
+ err = rman_init(&sc->io_rman);
+ if (err) {
+ rman_fini(&sc->mem_rman);
+ return (err);
+ }
+
+ err = rman_manage_region(&sc->pref_mem_rman,
+ sc->pref_mem_range.host_addr,
+ sc->pref_mem_range.host_addr + sc->pref_mem_range.size - 1);
+ if (err)
+ goto error;
+ err = rman_manage_region(&sc->mem_rman,
+ sc->mem_range.host_addr,
+ sc->mem_range.host_addr + sc->mem_range.size - 1);
+ if (err)
+ goto error;
+ err = rman_manage_region(&sc->io_rman,
+ sc->io_range.pci_addr,
+ sc->io_range.pci_addr + sc->io_range.size - 1);
+ if (err)
+ goto error;
+ return (0);
+
+error:
+ rman_fini(&sc->pref_mem_rman);
+ rman_fini(&sc->mem_rman);
+ rman_fini(&sc->io_rman);
+ return (err);
+}
+
+static struct rman *
+tegra_pcib_rman(struct tegra_pcib_softc *sc, int type, u_int flags)
+{
+
+ switch (type) {
+ case SYS_RES_IOPORT:
+ return (&sc->io_rman);
+ case SYS_RES_MEMORY:
+ if (flags & RF_PREFETCHABLE)
+ return (&sc->pref_mem_rman);
+ else
+ return (&sc->mem_rman);
+ default:
+ break;
+ }
+
+ return (NULL);
+}
+
+static struct resource *
+tegra_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct tegra_pcib_softc *sc;
+ struct rman *rm;
+ struct resource *res;
+
+ debugf("%s: enter %d start %#jx end %#jx count %#jx\n", __func__,
+ type, start, end, count);
+ sc = device_get_softc(dev);
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS) {
+ return (pci_domain_alloc_bus(0, child, rid, start, end, count,
+ flags));
+ }
+#endif
+
+ rm = tegra_pcib_rman(sc, type, flags);
+
+ if (rm == NULL) {
+ res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+ type, rid, start, end, count, flags);
+
+ return (res);
+ }
+
+ if (bootverbose) {
+ device_printf(dev,
+ "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
+ start, end, count);
+ }
+
+ res = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (res == NULL)
+ goto fail;
+ rman_set_rid(res, *rid);
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, res)) {
+ rman_release_resource(res);
+ goto fail;
+ }
+ }
+ return (res);
+
+fail:
+ if (bootverbose) {
+ device_printf(dev, "%s FAIL: type=%d, rid=%d, "
+ "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
+ __func__, type, *rid, start, end, count, flags);
+ }
+
+ return (NULL);
+}
+
+static int
+tegra_pcib_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct tegra_pcib_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+ debugf("%s: %d rid %x\n", __func__, type, rid);
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS)
+ return (pci_domain_release_bus(0, child, rid, res));
+#endif
+
+ rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
+ if (rm != NULL) {
+ KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
+ rman_release_resource(res);
+ }
+
+ return (bus_generic_release_resource(dev, child, type, rid, res));
+}
+
+static int
+tegra_pcib_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *res, rman_res_t start, rman_res_t end)
+{
+ struct tegra_pcib_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+ debugf("%s: %d start %jx end %jx \n", __func__, type, start, end);
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS)
+ return (pci_domain_adjust_bus(0, child, res, start, end));
+#endif
+
+ rm = tegra_pcib_rman(sc, type, rman_get_flags(res));
+ if (rm != NULL)
+ return (rman_adjust_resource(res, start, end));
+ return (bus_generic_adjust_resource(dev, child, type, res, start, end));
+}
+extern bus_space_tag_t fdtbus_bs_tag;
+static int
+tegra_pcib_pcie_activate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct tegra_pcib_softc *sc;
+ vm_offset_t start;
+ void *p;
+ int rv;
+
+ sc = device_get_softc(dev);
+ rv = rman_activate_resource(r);
+ if (rv != 0)
+ return (rv);
+ switch(type) {
+ case SYS_RES_IOPORT:
+ start = rman_get_start(r) + sc->io_range.host_addr;
+ break;
+ default:
+ start = rman_get_start(r);
+ rman_get_start(r);
+ break;
+ }
+
+ if (bootverbose)
+ printf("%s: start %zx, len %jd\n", __func__, start,
+ rman_get_size(r));
+
+ p = pmap_mapdev(start, (vm_size_t)rman_get_size(r));
+ rman_set_virtual(r, p);
+ rman_set_bustag(r, fdtbus_bs_tag);
+ rman_set_bushandle(r, (u_long)p);
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * IVARs
+ */
+static int
+tegra_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct tegra_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ *result = sc->busnr;
+ return (0);
+ case PCIB_IVAR_DOMAIN:
+ *result = device_get_unit(dev);
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+tegra_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct tegra_pcib_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->busnr = value;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+tegra_pcib_maxslots(device_t dev)
+{
+ return (16);
+}
+
+
+static int
+tegra_pcib_route_interrupt(device_t bus, device_t dev, int pin)
+{
+ struct tegra_pcib_softc *sc;
+
+ sc = device_get_softc(bus);
+ device_printf(bus, "route pin %d for device %d.%d to %ju\n",
+ pin, pci_get_slot(dev), pci_get_function(dev),
+ rman_get_start(sc->irq_res));
+
+ return (rman_get_start(sc->irq_res));
+}
+
+static int
+tegra_pcbib_map_cfg(struct tegra_pcib_softc *sc, u_int bus, u_int slot,
+ u_int func, u_int reg)
+{
+ bus_size_t offs;
+ int rv;
+
+ offs = sc->cfg_base_addr;
+ offs |= PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) | PCI_CFG_FUN(func) |
+ PCI_CFG_EXT_REG(reg);
+ if ((sc->cfg_handle != 0) && (sc->cfg_cur_offs == offs))
+ return (0);
+ if (sc->cfg_handle != 0)
+ bus_space_unmap(sc->bus_tag, sc->cfg_handle, 0x800);
+
+ rv = bus_space_map(sc->bus_tag, offs, 0x800, 0, &sc->cfg_handle);
+ if (rv != 0)
+ device_printf(sc->dev, "Cannot map config space\n");
+ else
+ sc->cfg_cur_offs = offs;
+ return (rv);
+}
+
+static uint32_t
+tegra_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
+ u_int reg, int bytes)
+{
+ struct tegra_pcib_softc *sc;
+ bus_space_handle_t hndl;
+ uint32_t off;
+ uint32_t val;
+ int rv, i;
+
+ sc = device_get_softc(dev);
+ if (bus == 0) {
+ if (func != 0)
+ return (0xFFFFFFFF);
+ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
+ if ((sc->ports[i] != NULL) &&
+ (sc->ports[i]->port_idx == slot)) {
+ hndl = sc->ports[i]->cfg_handle;
+ off = reg & 0xFFF;
+ break;
+ }
+ }
+ if (i >= TEGRA_PCIB_MAX_PORTS)
+ return (0xFFFFFFFF);
+ } else {
+ rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg);
+ if (rv != 0)
+ return (0xFFFFFFFF);
+ hndl = sc->cfg_handle;
+ off = PCI_CFG_BASE_REG(reg);
+ }
+
+ val = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
+ switch (bytes) {
+ case 4:
+ break;
+ case 2:
+ if (off & 3)
+ val >>= 16;
+ val &= 0xffff;
+ break;
+ case 1:
+ val >>= ((off & 3) << 3);
+ val &= 0xff;
+ break;
+ }
+ return val;
+}
+
+static void
+tegra_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
+ u_int reg, uint32_t val, int bytes)
+{
+ struct tegra_pcib_softc *sc;
+ bus_space_handle_t hndl;
+ uint32_t off;
+ uint32_t val2;
+ int rv, i;
+
+ sc = device_get_softc(dev);
+ if (bus == 0) {
+ if (func != 0)
+ return;
+ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
+ if ((sc->ports[i] != NULL) &&
+ (sc->ports[i]->port_idx == slot)) {
+ hndl = sc->ports[i]->cfg_handle;
+ off = reg & 0xFFF;
+ break;
+ }
+ }
+ if (i >= TEGRA_PCIB_MAX_PORTS)
+ return;
+ } else {
+ rv = tegra_pcbib_map_cfg(sc, bus, slot, func, reg);
+ if (rv != 0)
+ return;
+ hndl = sc->cfg_handle;
+ off = PCI_CFG_BASE_REG(reg);
+ }
+
+ switch (bytes) {
+ case 4:
+ bus_space_write_4(sc->bus_tag, hndl, off, val);
+ break;
+ case 2:
+ val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
+ val2 &= ~(0xffff << ((off & 3) << 3));
+ val2 |= ((val & 0xffff) << ((off & 3) << 3));
+ bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2);
+ break;
+ case 1:
+ val2 = bus_space_read_4(sc->bus_tag, hndl, off & ~3);
+ val2 &= ~(0xff << ((off & 3) << 3));
+ val2 |= ((val & 0xff) << ((off & 3) << 3));
+ bus_space_write_4(sc->bus_tag, hndl, off & ~3, val2);
+ break;
+ }
+}
+
+static int tegra_pci_intr(void *arg)
+{
+ struct tegra_pcib_softc *sc = arg;
+ uint32_t code, signature;
+
+ code = bus_read_4(sc->afi_mem_res, AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
+ signature = bus_read_4(sc->afi_mem_res, AFI_INTR_SIGNATURE);
+ bus_write_4(sc->afi_mem_res, AFI_INTR_CODE, 0);
+ if (code == AFI_INTR_CODE_INT_CODE_SM_MSG)
+ return(FILTER_STRAY);
+
+ printf("tegra_pci_intr: code %x sig %x\n", code, signature);
+ return (FILTER_HANDLED);
+}
+
+#if defined(TEGRA_PCI_MSI)
+static int
+tegra_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
+ uint32_t *data)
+{
+ struct tegra_pcib_softc *sc;
+
+ sc = device_get_softc(dev);
+ irq = irq - MSI_IRQ;
+
+ /* validate parameters */
+ if (isclr(&sc->msi_bitmap, irq)) {
+ device_printf(dev, "invalid MSI 0x%x\n", irq);
+ return (EINVAL);
+ }
+
+ tegra_msi_data(irq, addr, data);
+
+ debugf("%s: irq: %d addr: %jx data: %x\n",
+ __func__, irq, *addr, *data);
+
+ return (0);
+}
+
+static int
+tegra_pcib_alloc_msi(device_t dev, device_t child, int count,
+ int maxcount __unused, int *irqs)
+{
+ struct tegra_pcib_softc *sc;
+ u_int start = 0, i;
+
+ if (powerof2(count) == 0 || count > MSI_IRQ_NUM)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+
+ for (start = 0; (start + count) < MSI_IRQ_NUM; start++) {
+ for (i = start; i < start + count; i++) {
+ if (isset(&sc->msi_bitmap, i))
+ break;
+ }
+ if (i == start + count)
+ break;
+ }
+
+ if ((start + count) == MSI_IRQ_NUM) {
+ mtx_unlock(&sc->mtx);
+ return (ENXIO);
+ }
+
+ for (i = start; i < start + count; i++) {
+ setbit(&sc->msi_bitmap, i);
+ irqs[i] = MSI_IRQ + i;
+ }
+ debugf("%s: start: %x count: %x\n", __func__, start, count);
+
+ mtx_unlock(&sc->mtx);
+ return (0);
+}
+
+static int
+tegra_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
+{
+ struct tegra_pcib_softc *sc;
+ u_int i;
+
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
+
+ for (i = 0; i < count; i++)
+ clrbit(&sc->msi_bitmap, irqs[i] - MSI_IRQ);
+
+ mtx_unlock(&sc->mtx);
+ return (0);
+}
+#endif
+
+static bus_size_t
+tegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port)
+{
+ if (port >= TEGRA_PCIB_MAX_PORTS)
+ panic("invalid port number: %d\n", port);
+
+ if (port == 0)
+ return (AFI_PEX0_CTRL);
+ else if (port == 1)
+ return (AFI_PEX1_CTRL);
+ else if (port == 2)
+ return (AFI_PEX2_CTRL);
+ else
+ panic("invalid port number: %d\n", port);
+}
+
+static int
+tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc)
+{
+ int rv;
+
+ rv = hwreset_assert(sc->hwreset_pcie_x);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'pcie_x' reset\n");
+ return (rv);
+ }
+ rv = hwreset_assert(sc->hwreset_afi);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'afi' reset\n");
+ return (rv);
+ }
+ rv = hwreset_assert(sc->hwreset_pex);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot assert 'pex' reset\n");
+ return (rv);
+ }
+
+ tegra_powergate_power_off(TEGRA_POWERGATE_PCX);
+
+ /* Power supplies. */
+ rv = regulator_enable(sc->supply_avddio_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'avddio_pex' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_dvddio_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'dvddio_pex' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_avdd_pex_pll);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'avdd-pex-pll' regulator\n");
+ return (rv);
+ }
+
+ rv = regulator_enable(sc->supply_hvdd_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'hvdd-pex-supply' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_hvdd_pex_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'hvdd-pex-pll-e-supply' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_vddio_pex_ctl);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'vddio-pex-ctl' regulator\n");
+ return (rv);
+ }
+ rv = regulator_enable(sc->supply_avdd_pll_erefe);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'avdd-pll-erefe-supply' regulator\n");
+ return (rv);
+ }
+
+ rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX,
+ sc->clk_pex, sc->hwreset_pex);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'PCX' powergate\n");
+ return (rv);
+ }
+
+ rv = hwreset_deassert(sc->hwreset_afi);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot unreset 'afi' reset\n");
+ return (rv);
+ }
+
+ rv = clk_enable(sc->clk_afi);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'afi' clock\n");
+ return (rv);
+ }
+
+ rv = clk_enable(sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'cml' clock\n");
+ return (rv);
+ }
+
+ rv = clk_enable(sc->clk_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'pll_e' clock\n");
+ return (rv);
+ }
+ return (0);
+}
+
+static struct tegra_pcib_port *
+tegra_pcib_parse_port(struct tegra_pcib_softc *sc, phandle_t node)
+{
+ struct tegra_pcib_port *port;
+ uint32_t tmp[5];
+ char tmpstr[6];
+ int rv;
+
+ port = malloc(sizeof(struct tegra_pcib_port), M_DEVBUF, M_WAITOK);
+
+ rv = OF_getprop(node, "status", tmpstr, sizeof(tmpstr));
+ if (rv <= 0 || strcmp(tmpstr, "okay") == 0 ||
+ strcmp(tmpstr, "ok") == 0)
+ port->enabled = 1;
+ else
+ port->enabled = 0;
+
+ rv = OF_getencprop(node, "assigned-addresses", tmp, sizeof(tmp));
+ if (rv != sizeof(tmp)) {
+ device_printf(sc->dev, "Cannot parse assigned-address: %d\n",
+ rv);
+ goto fail;
+ }
+ port->rp_base_addr = tmp[2];
+ port->rp_size = tmp[4];
+ port->port_idx = OFW_PCI_PHYS_HI_DEVICE(tmp[0]) - 1;
+ if (port->port_idx >= TEGRA_PCIB_MAX_PORTS) {
+ device_printf(sc->dev, "Invalid port index: %d\n",
+ port->port_idx);
+ goto fail;
+ }
+ /* XXX - TODO:
+ * Implement proper function for parsing pci "reg" property:
+ * - it have PCI bus format
+ * - its relative to matching "assigned-addresses"
+ */
+ rv = OF_getencprop(node, "reg", tmp, sizeof(tmp));
+ if (rv != sizeof(tmp)) {
+ device_printf(sc->dev, "Cannot parse reg: %d\n", rv);
+ goto fail;
+ }
+ port->rp_base_addr += tmp[2];
+
+ rv = OF_getencprop(node, "nvidia,num-lanes", &port->num_lanes,
+ sizeof(port->num_lanes));
+ if (rv != sizeof(port->num_lanes)) {
+ device_printf(sc->dev, "Cannot parse nvidia,num-lanes: %d\n",
+ rv);
+ goto fail;
+ }
+ if (port->num_lanes > 4) {
+ device_printf(sc->dev, "Invalid nvidia,num-lanes: %d\n",
+ port->num_lanes);
+ goto fail;
+ }
+
+ port->afi_pex_ctrl = tegra_pcib_pex_ctrl(sc, port->port_idx);
+ sc->lanes_cfg |= port->num_lanes << (4 * port->port_idx);
+
+ return (port);
+fail:
+ free(port, M_DEVBUF);
+ return (NULL);
+}
+
+
+static int
+tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node)
+{
+ phandle_t child;
+ struct tegra_pcib_port *port;
+ int rv;
+
+ /* Power supplies. */
+ rv = regulator_get_by_ofw_property(sc->dev, "avddio-pex-supply",
+ &sc->supply_avddio_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'avddio-pex' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "dvddio-pex-supply",
+ &sc->supply_dvddio_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'dvddio-pex' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "avdd-pex-pll-supply",
+ &sc->supply_avdd_pex_pll);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'avdd-pex-pll' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-supply",
+ &sc->supply_hvdd_pex);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'hvdd-pex' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "hvdd-pex-pll-e-supply",
+ &sc->supply_hvdd_pex_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'hvdd-pex-pll-e' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "vddio-pex-ctl-supply",
+ &sc->supply_vddio_pex_ctl);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'vddio-pex-ctl' regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, "avdd-pll-erefe-supply",
+ &sc->supply_avdd_pll_erefe);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get 'avdd-pll-erefe' regulator\n");
+ return (ENXIO);
+ }
+
+ /* Resets. */
+ rv = hwreset_get_by_ofw_name(sc->dev, "pex", &sc->hwreset_pex);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pex' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "afi", &sc->hwreset_afi);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'afi' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "pcie_x", &sc->hwreset_pcie_x);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pcie_x' reset\n");
+ return (ENXIO);
+ }
+
+ /* Clocks. */
+ rv = clk_get_by_ofw_name(sc->dev, "pex", &sc->clk_pex);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pex' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "afi", &sc->clk_afi);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'afi' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "pll_e", &sc->clk_pll_e);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pll_e' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "cml", &sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'cml' clock\n");
+ return (ENXIO);
+ }
+
+ /* Phy. */
+ rv = phy_get_by_ofw_name(sc->dev, "pcie", &sc->phy);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pcie' phy\n");
+ return (ENXIO);
+ }
+
+ /* Ports */
+ sc->num_ports = 0;
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ port = tegra_pcib_parse_port(sc, child);
+ if (port == NULL) {
+ device_printf(sc->dev, "Cannot parse PCIe port node\n");
+ return (ENXIO);
+ }
+ sc->ports[sc->num_ports++] = port;
+ }
+
+ return (0);
+}
+
+static int
+tegra_pcib_decode_ranges(struct tegra_pcib_softc *sc,
+ struct tegra_pci_range *ranges, int nranges)
+{
+ int i;
+
+ for (i = 2; i < nranges; i++) {
+ if (ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_IO) {
+ if (sc->io_range.size != 0) {
+ device_printf(sc->dev,
+ "Duplicated IO range found in DT\n");
+ return (ENXIO);
+ }
+ sc->io_range = ranges[i];
+ }
+ if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
+ !ranges[i].prefetchable) {
+ if (sc->mem_range.size != 0) {
+ device_printf(sc->dev,
+ "Duplicated memory range found in DT\n");
+ return (ENXIO);
+ }
+ sc->mem_range = ranges[i];
+ }
+ if ((ranges[i].space_code == OFW_PCI_PHYS_HI_SPACE_MEM32) &&
+ ranges[i].prefetchable) {
+ if (sc->pref_mem_range.size != 0) {
+ device_printf(sc->dev,
+ "Duplicated memory range found in DT\n");
+ return (ENXIO);
+ }
+ sc->pref_mem_range = ranges[i];
+ }
+ }
+ if ((sc->io_range.size == 0) || (sc->mem_range.size == 0)
+ || (sc->pref_mem_range.size == 0)) {
+ device_printf(sc->dev,
+ " Not all required ranges are found in DT\n");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+/*
+ * Hardware config.
+ */
+static int
+tegra_pcib_wait_for_link(struct tegra_pcib_softc *sc,
+ struct tegra_pcib_port *port)
+{
+ uint32_t reg;
+ int i;
+
+
+ /* Setup link detection. */
+ reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
+ RP_PRIV_MISC, 4);
+ reg &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
+ reg |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
+ tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0,
+ RP_PRIV_MISC, reg, 4);
+
+ for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) {
+ reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
+ RP_VEND_XP, 4);
+ if (reg & RP_VEND_XP_DL_UP)
+ break;
+
+ }
+ if (i <= 0)
+ return (ETIMEDOUT);
+
+ for (i = TEGRA_PCIE_LINKUP_TIMEOUT; i > 0; i--) {
+ reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
+ RP_LINK_CONTROL_STATUS, 4);
+ if (reg & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
+ break;
+
+ }
+ if (i <= 0)
+ return (ETIMEDOUT);
+ return (0);
+}
+
+static void
+tegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num)
+{
+ struct tegra_pcib_port *port;
+ uint32_t reg;
+ int rv;
+
+ port = sc->ports[port_num];
+
+ /* Put port to reset. */
+ reg = AFI_RD4(sc, port->afi_pex_ctrl);
+ reg &= ~AFI_PEX_CTRL_RST_L;
+ AFI_WR4(sc, port->afi_pex_ctrl, reg);
+ AFI_RD4(sc, port->afi_pex_ctrl);
+ DELAY(10);
+
+ /* Enable clocks. */
+ reg |= AFI_PEX_CTRL_REFCLK_EN;
+ reg |= AFI_PEX_CTRL_CLKREQ_EN;
+ reg |= AFI_PEX_CTRL_OVERRIDE_EN;
+ AFI_WR4(sc, port->afi_pex_ctrl, reg);
+ AFI_RD4(sc, port->afi_pex_ctrl);
+ DELAY(100);
+
+ /* Release reset. */
+ reg |= AFI_PEX_CTRL_RST_L;
+ AFI_WR4(sc, port->afi_pex_ctrl, reg);
+
+ rv = tegra_pcib_wait_for_link(sc, port);
+ if (bootverbose)
+ device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n",
+ port->port_idx, port->num_lanes,
+ port->num_lanes > 1 ? "s": "",
+ rv == 0 ? "up": "down");
+}
+
+
+static void
+tegra_pcib_port_disable(struct tegra_pcib_softc *sc, uint32_t port_num)
+{
+ struct tegra_pcib_port *port;
+ uint32_t reg;
+
+ port = sc->ports[port_num];
+
+ /* Put port to reset. */
+ reg = AFI_RD4(sc, port->afi_pex_ctrl);
+ reg &= ~AFI_PEX_CTRL_RST_L;
+ AFI_WR4(sc, port->afi_pex_ctrl, reg);
+ AFI_RD4(sc, port->afi_pex_ctrl);
+ DELAY(10);
+
+ /* Disable clocks. */
+ reg &= ~AFI_PEX_CTRL_CLKREQ_EN;
+ reg &= ~AFI_PEX_CTRL_REFCLK_EN;
+ AFI_WR4(sc, port->afi_pex_ctrl, reg);
+
+ if (bootverbose)
+ device_printf(sc->dev, " port %d (%d lane%s): Disabled\n",
+ port->port_idx, port->num_lanes,
+ port->num_lanes > 1 ? "s": "");
+}
+
+static void
+tegra_pcib_set_bar(struct tegra_pcib_softc *sc, int bar, uint32_t axi,
+ uint64_t fpci, uint32_t size, int is_memory)
+{
+ uint32_t fpci_reg;
+ uint32_t axi_reg;
+ uint32_t size_reg;
+
+ axi_reg = axi & ~0xFFF;
+ size_reg = size >> 12;
+ fpci_reg = (uint32_t)(fpci >> 8) & ~0xF;
+ fpci_reg |= is_memory ? 0x1 : 0x0;
+ AFI_WR4(sc, bars[bar].axi_start, axi_reg);
+ AFI_WR4(sc, bars[bar].size, size_reg);
+ AFI_WR4(sc, bars[bar].fpci_start, fpci_reg);
+}
+
+static int
+tegra_pcib_enable(struct tegra_pcib_softc *sc, uint32_t port)
+{
+ int rv;
+ int i;
+ uint32_t reg;
+
+ rv = tegra_pcib_enable_fdt_resources(sc);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable FDT resources\n");
+ return (rv);
+ }
+ /* Enable PLLE control. */
+ reg = AFI_RD4(sc, AFI_PLLE_CONTROL);
+ reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
+ reg |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
+ AFI_WR4(sc, AFI_PLLE_CONTROL, reg);
+
+ /* Set bias pad. */
+ AFI_WR4(sc, AFI_PEXBIAS_CTRL, 0);
+
+ /* Configure mode and ports. */
+ reg = AFI_RD4(sc, AFI_PCIE_CONFIG);
+ reg &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
+ if (sc->lanes_cfg == 0x14) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "Using x1,x4 configuration\n");
+ reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR4_1;
+ } else if (sc->lanes_cfg == 0x12) {
+ if (bootverbose)
+ device_printf(sc->dev,
+ "Using x1,x2 configuration\n");
+ reg |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_XBAR2_1;
+ } else {
+ device_printf(sc->dev,
+ "Unsupported lanes configuration: 0x%X\n", sc->lanes_cfg);
+ }
+ reg |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL;
+ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
+ if ((sc->ports[i] != NULL))
+ reg &=
+ ~AFI_PCIE_CONFIG_PCIE_DISABLE(sc->ports[i]->port_idx);
+ }
+ AFI_WR4(sc, AFI_PCIE_CONFIG, reg);
+
+ /* Enable Gen2 support. */
+ reg = AFI_RD4(sc, AFI_FUSE);
+ reg &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+ AFI_WR4(sc, AFI_FUSE, reg);
+
+ /* Enable PCIe phy. */
+ rv = phy_enable(sc->dev, sc->phy);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable phy\n");
+ return (rv);
+ }
+
+ rv = hwreset_deassert(sc->hwreset_pcie_x);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n");
+ return (rv);
+ }
+
+ /* Enable config space. */
+ reg = AFI_RD4(sc, AFI_CONFIGURATION);
+ reg |= AFI_CONFIGURATION_EN_FPCI;
+ AFI_WR4(sc, AFI_CONFIGURATION, reg);
+
+ /* Enable AFI errors. */
+ reg = 0;
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_SLVERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_INI_DECERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_SLVERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_DECERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_TGT_WRERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_SM_MSG);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_DFPCI_DECERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_AXI_DECERR);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_FPCI_TIMEOUT);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_PRSNT_SENSE);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_PE_CLKREQ_SENSE);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_CLKCLAMP_SENSE);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_RDY4PD_SENSE);
+ reg |= AFI_AFI_INTR_ENABLE_CODE(AFI_INTR_CODE_INT_CODE_P2P_ERROR);
+ AFI_WR4(sc, AFI_AFI_INTR_ENABLE, reg);
+ AFI_WR4(sc, AFI_SM_INTR_ENABLE, 0xffffffff);
+
+ /* Enable INT, disable MSI. */
+ AFI_WR4(sc, AFI_INTR_MASK, AFI_INTR_MASK_INT_MASK);
+
+ /* Mask all FPCI errors. */
+ AFI_WR4(sc, AFI_FPCI_ERROR_MASKS, 0);
+
+ /* Setup AFI translation windows. */
+ /* BAR 0 - type 1 extended configuration. */
+ tegra_pcib_set_bar(sc, 0, rman_get_start(sc->cfg_mem_res),
+ FPCI_MAP_EXT_TYPE1_CONFIG, rman_get_size(sc->cfg_mem_res), 0);
+
+ /* BAR 1 - downstream I/O. */
+ tegra_pcib_set_bar(sc, 1, sc->io_range.host_addr, FPCI_MAP_IO,
+ sc->io_range.size, 0);
+
+ /* BAR 2 - downstream prefetchable memory 1:1. */
+ tegra_pcib_set_bar(sc, 2, sc->pref_mem_range.host_addr,
+ sc->pref_mem_range.host_addr, sc->pref_mem_range.size, 1);
+
+ /* BAR 3 - downstream not prefetchable memory 1:1 .*/
+ tegra_pcib_set_bar(sc, 3, sc->mem_range.host_addr,
+ sc->mem_range.host_addr, sc->mem_range.size, 1);
+
+ /* BAR 3-8 clear. */
+ tegra_pcib_set_bar(sc, 4, 0, 0, 0, 0);
+ tegra_pcib_set_bar(sc, 5, 0, 0, 0, 0);
+ tegra_pcib_set_bar(sc, 6, 0, 0, 0, 0);
+ tegra_pcib_set_bar(sc, 7, 0, 0, 0, 0);
+ tegra_pcib_set_bar(sc, 8, 0, 0, 0, 0);
+
+ /* MSI BAR - clear. */
+ tegra_pcib_set_bar(sc, 9, 0, 0, 0, 0);
+ return(0);
+}
+
+static int
+tegra_pcib_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+ device_set_desc(dev, "Nvidia Integrated PCI/PCI-E Controller");
+ return (BUS_PROBE_DEFAULT);
+ }
+ return (ENXIO);
+}
+
+static int
+tegra_pcib_attach(device_t dev)
+{
+ struct tegra_pcib_softc *sc;
+ phandle_t node;
+ uint32_t unit;
+ int rv;
+ int rid;
+ int nranges;
+ struct tegra_pci_range *ranges;
+ struct tegra_pcib_port *port;
+ int i;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ unit = fdt_get_unit(dev);
+ mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF);
+
+
+ node = ofw_bus_get_node(dev);
+
+ rv = tegra_pcib_parse_fdt_resources(sc, node);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get FDT resources\n");
+ return (rv);
+ }
+
+ nranges = tegra_pci_get_ranges(node, &ranges);
+ if (nranges != 5) {
+ device_printf(sc->dev, "Unexpected number of ranges: %d\n",
+ nranges);
+ rv = ENXIO;
+ goto out;
+ }
+
+ /* Allocate bus_space resources. */
+ rid = 0;
+ sc->pads_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->pads_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate PADS register\n");
+ rv = ENXIO;
+ goto out;
+ }
+ /*
+ * XXX - FIXME
+ * tag for config space is not filled when RF_ALLOCATED flag is used.
+ */
+ sc->bus_tag = rman_get_bustag(sc->pads_mem_res);
+
+ rid = 1;
+ sc->afi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->afi_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate AFI register\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rid = 2;
+ sc->cfg_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ALLOCATED);
+ if (sc->cfg_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate config space memory\n");
+ rv = ENXIO;
+ goto out;
+ }
+ sc->cfg_base_addr = rman_get_start(sc->cfg_mem_res);
+
+
+ /* Map RP slots */
+ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
+ if (sc->ports[i] == NULL)
+ continue;
+ port = sc->ports[i];
+ rv = bus_space_map(sc->bus_tag, port->rp_base_addr,
+ port->rp_size, 0, &port->cfg_handle);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot allocate memory for "
+ "port: %d\n", i);
+ rv = ENXIO;
+ goto out;
+ }
+ }
+
+ /*
+ * Get PCI interrupt info.
+ */
+ ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(pcell_t));
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate IRQ resources\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ rid = 1;
+ sc->msi_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate MSI IRQ resources\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+ tegra_pci_intr, NULL, sc, &sc->intr_cookie)) {
+ device_printf(dev, "cannot setup interrupt handler\n");
+ rv = ENXIO;
+ goto out;
+ }
+
+ /* Memory management. */
+ rv = tegra_pcib_decode_ranges(sc, ranges, nranges);
+ if (rv != 0)
+ goto out;
+
+ rv = tegra_pcib_rman_init(sc);
+ if (rv != 0)
+ goto out;
+ free(ranges, M_DEVBUF);
+ ranges = NULL;
+
+ /*
+ * Enable PCIE device.
+ */
+ rv = tegra_pcib_enable(sc, unit);
+ if (rv != 0)
+ goto out;
+ for (i = 0; i < TEGRA_PCIB_MAX_PORTS; i++) {
+ if (sc->ports[i] == NULL)
+ continue;
+ if (sc->ports[i]->enabled)
+ tegra_pcib_port_enable(sc, i);
+ else
+ tegra_pcib_port_disable(sc, i);
+ }
+
+ device_add_child(dev, "pci", -1);
+
+ return (bus_generic_attach(dev));
+
+out:
+ if (ranges != NULL)
+ free(ranges, M_DEVBUF);
+
+ return (rv);
+}
+
+
+static device_method_t tegra_pcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_pcib_probe),
+ DEVMETHOD(device_attach, tegra_pcib_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_read_ivar, tegra_pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, tegra_pcib_write_ivar),
+ DEVMETHOD(bus_alloc_resource, tegra_pcib_alloc_resource),
+ DEVMETHOD(bus_adjust_resource, tegra_pcib_adjust_resource),
+ DEVMETHOD(bus_release_resource, tegra_pcib_release_resource),
+ DEVMETHOD(bus_activate_resource, tegra_pcib_pcie_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, tegra_pcib_maxslots),
+ DEVMETHOD(pcib_read_config, tegra_pcib_read_config),
+ DEVMETHOD(pcib_write_config, tegra_pcib_write_config),
+ DEVMETHOD(pcib_route_interrupt, tegra_pcib_route_interrupt),
+
+#if defined(TEGRA_PCI_MSI)
+ DEVMETHOD(pcib_alloc_msi, tegra_pcib_alloc_msi),
+ DEVMETHOD(pcib_release_msi, tegra_pcib_release_msi),
+ DEVMETHOD(pcib_map_msi, tegra_pcib_map_msi),
+#endif
+
+ /* OFW bus interface */
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra_pcib_driver = {
+ "pcib",
+ tegra_pcib_methods,
+ sizeof(struct tegra_pcib_softc),
+};
+
+devclass_t pcib_devclass;
+
+DRIVER_MODULE(pcib, simplebus, tegra_pcib_driver, pcib_devclass, 0, 0); \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra_pinmux.c b/sys/arm/nvidia/tegra_pinmux.c
new file mode 100644
index 0000000..6123746
--- /dev/null
+++ b/sys/arm/nvidia/tegra_pinmux.c
@@ -0,0 +1,804 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Pin multiplexer driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+/* Pin multipexor register. */
+#define TEGRA_MUX_FUNCTION_MASK 0x03
+#define TEGRA_MUX_FUNCTION_SHIFT 0
+#define TEGRA_MUX_PUPD_MASK 0x03
+#define TEGRA_MUX_PUPD_SHIFT 2
+#define TEGRA_MUX_TRISTATE_SHIFT 4
+#define TEGRA_MUX_ENABLE_INPUT_SHIFT 5
+#define TEGRA_MUX_OPEN_DRAIN_SHIFT 6
+#define TEGRA_MUX_LOCK_SHIFT 7
+#define TEGRA_MUX_IORESET_SHIFT 8
+#define TEGRA_MUX_RCV_SEL_SHIFT 9
+
+
+/* Pin goup register. */
+#define TEGRA_GRP_HSM_SHIFT 2
+#define TEGRA_GRP_SCHMT_SHIFT 3
+#define TEGRA_GRP_DRV_TYPE_SHIFT 6
+#define TEGRA_GRP_DRV_TYPE_MASK 0x03
+#define TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT 28
+#define TEGRA_GRP_DRV_DRVDN_SLWR_MASK 0x03
+#define TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT 30
+#define TEGRA_GRP_DRV_DRVUP_SLWF_MASK 0x03
+
+struct pinmux_softc {
+ device_t dev;
+ struct resource *pad_mem_res;
+ struct resource *mux_mem_res;
+ struct resource *mipi_mem_res;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-pinmux", 1},
+ {NULL, 0},
+};
+
+enum prop_id {
+ PROP_ID_PULL,
+ PROP_ID_TRISTATE,
+ PROP_ID_ENABLE_INPUT,
+ PROP_ID_OPEN_DRAIN,
+ PROP_ID_LOCK,
+ PROP_ID_IORESET,
+ PROP_ID_RCV_SEL,
+ PROP_ID_HIGH_SPEED_MODE,
+ PROP_ID_SCHMITT,
+ PROP_ID_LOW_POWER_MODE,
+ PROP_ID_DRIVE_DOWN_STRENGTH,
+ PROP_ID_DRIVE_UP_STRENGTH,
+ PROP_ID_SLEW_RATE_FALLING,
+ PROP_ID_SLEW_RATE_RISING,
+ PROP_ID_DRIVE_TYPE,
+
+ PROP_ID_MAX_ID
+};
+
+/* Numeric based parameters. */
+static const struct prop_name {
+ const char *name;
+ enum prop_id id;
+} prop_names[] = {
+ {"nvidia,pull", PROP_ID_PULL},
+ {"nvidia,tristate", PROP_ID_TRISTATE},
+ {"nvidia,enable-input", PROP_ID_ENABLE_INPUT},
+ {"nvidia,open-drain", PROP_ID_OPEN_DRAIN},
+ {"nvidia,lock", PROP_ID_LOCK},
+ {"nvidia,io-reset", PROP_ID_IORESET},
+ {"nvidia,rcv-sel", PROP_ID_RCV_SEL},
+ {"nvidia,high-speed-mode", PROP_ID_HIGH_SPEED_MODE},
+ {"nvidia,schmitt", PROP_ID_SCHMITT},
+ {"nvidia,low-power-mode", PROP_ID_LOW_POWER_MODE},
+ {"nvidia,pull-down-strength", PROP_ID_DRIVE_DOWN_STRENGTH},
+ {"nvidia,pull-up-strength", PROP_ID_DRIVE_UP_STRENGTH},
+ {"nvidia,slew-rate-falling", PROP_ID_SLEW_RATE_FALLING},
+ {"nvidia,slew-rate-rising", PROP_ID_SLEW_RATE_RISING},
+ {"nvidia,drive-type", PROP_ID_DRIVE_TYPE},
+};
+
+/*
+ * configuration for one pin group.
+ */
+struct pincfg {
+ char *function;
+ int params[PROP_ID_MAX_ID];
+};
+#define GPIO_BANK_A 0
+#define GPIO_BANK_B 1
+#define GPIO_BANK_C 2
+#define GPIO_BANK_D 3
+#define GPIO_BANK_E 4
+#define GPIO_BANK_F 5
+#define GPIO_BANK_G 6
+#define GPIO_BANK_H 7
+#define GPIO_BANK_I 8
+#define GPIO_BANK_J 9
+#define GPIO_BANK_K 10
+#define GPIO_BANK_L 11
+#define GPIO_BANK_M 12
+#define GPIO_BANK_N 13
+#define GPIO_BANK_O 14
+#define GPIO_BANK_P 15
+#define GPIO_BANK_Q 16
+#define GPIO_BANK_R 17
+#define GPIO_BANK_S 18
+#define GPIO_BANK_T 19
+#define GPIO_BANK_U 20
+#define GPIO_BANK_V 21
+#define GPIO_BANK_W 22
+#define GPIO_BANK_X 23
+#define GPIO_BANK_Y 24
+#define GPIO_BANK_Z 25
+#define GPIO_BANK_AA 26
+#define GPIO_BANK_BB 27
+#define GPIO_BANK_CC 28
+#define GPIO_BANK_DD 29
+#define GPIO_BANK_EE 30
+#define GPIO_BANK_FF 31
+#define GPIO_NUM(b, p) (8 * (b) + (p))
+
+struct tegra_mux {
+ char *name;
+ bus_size_t reg;
+ char *functions[4];
+ int gpio_num;
+};
+
+#define GMUX(r, gb, gi, nm, f1, f2, f3, f4) \
+{ \
+ .name = #nm, \
+ .reg = r, \
+ .gpio_num = GPIO_NUM(GPIO_BANK_##gb, gi), \
+ .functions = {#f1, #f2, #f3, #f4}, \
+}
+
+#define FMUX(r, nm, f1, f2, f3, f4) \
+{ \
+ .name = #nm, \
+ .reg = r, \
+ .gpio_num = -1, \
+ .functions = {#f1, #f2, #f3, #f4}, \
+}
+
+static const struct tegra_mux pin_mux_tbl[] = {
+ GMUX(0x000, O, 1, ulpi_data0_po1, spi3, hsi, uarta, ulpi),
+ GMUX(0x004, O, 2, ulpi_data1_po2, spi3, hsi, uarta, ulpi),
+ GMUX(0x008, O, 3, ulpi_data2_po3, spi3, hsi, uarta, ulpi),
+ GMUX(0x00C, O, 4, ulpi_data3_po4, spi3, hsi, uarta, ulpi),
+ GMUX(0x010, O, 5, ulpi_data4_po5, spi2, hsi, uarta, ulpi),
+ GMUX(0x014, O, 6, ulpi_data5_po6, spi2, hsi, uarta, ulpi),
+ GMUX(0x018, O, 7, ulpi_data6_po7, spi2, hsi, uarta, ulpi),
+ GMUX(0x01C, O, 0, ulpi_data7_po0, spi2, hsi, uarta, ulpi),
+ GMUX(0x020, P, 9, ulpi_clk_py0, spi1, spi5, uartd, ulpi),
+ GMUX(0x024, P, 1, ulpi_dir_py1, spi1, spi5, uartd, ulpi),
+ GMUX(0x028, P, 2, ulpi_nxt_py2, spi1, spi5, uartd, ulpi),
+ GMUX(0x02C, P, 3, ulpi_stp_py3, spi1, spi5, uartd, ulpi),
+ GMUX(0x030, P, 0, dap3_fs_pp0, i2s2, spi5, displaya, displayb),
+ GMUX(0x034, P, 1, dap3_din_pp1, i2s2, spi5, displaya, displayb),
+ GMUX(0x038, P, 2, dap3_dout_pp2, i2s2, spi5, displaya, rsvd4),
+ GMUX(0x03C, P, 3, dap3_sclk_pp3, i2s2, spi5, rsvd3, displayb),
+ GMUX(0x040, V, 0, pv0, rsvd1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x044, V, 1, pv1, rsvd1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x048, Z, 0, sdmmc1_clk_pz0, sdmmc1, clk12, rsvd3, rsvd4),
+ GMUX(0x04C, Z, 1, sdmmc1_cmd_pz1, sdmmc1, spdif, spi4, uarta),
+ GMUX(0x050, Y, 4, sdmmc1_dat3_py4, sdmmc1, spdif, spi4, uarta),
+ GMUX(0x054, Y, 5, sdmmc1_dat2_py5, sdmmc1, pwm0, spi4, uarta),
+ GMUX(0x058, Y, 6, sdmmc1_dat1_py6, sdmmc1, pwm1, spi4, uarta),
+ GMUX(0x05C, Y, 7, sdmmc1_dat0_py7, sdmmc1, rsvd2, spi4, uarta),
+ GMUX(0x068, W, 5, clk2_out_pw5, extperiph2, rsvd2, rsvd3, rsvd4),
+ GMUX(0x06C, CC, 5, clk2_req_pcc5, dap, rsvd2, rsvd3, rsvd4),
+ GMUX(0x110, N, 7, hdmi_int_pn7, rsvd1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x114, V, 4, ddc_scl_pv4, i2c4, rsvd2, rsvd3, rsvd4),
+ GMUX(0x118, V, 5, ddc_sda_pv5, i2c4, rsvd2, rsvd3, rsvd4),
+ GMUX(0x164, V, 3, uart2_rxd_pc3, irda, spdif, uarta, spi4),
+ GMUX(0x168, C, 2, uart2_txd_pc2, irda, spdif, uarta, spi4),
+ GMUX(0x16C, J, 6, uart2_rts_n_pj6, uarta, uartb, gmi, spi4),
+ GMUX(0x170, J, 5, uart2_cts_n_pj5, uarta, uartb, gmi, spi4),
+ GMUX(0x174, W, 6, uart3_txd_pw6, uartc, rsvd2, gmi, spi4),
+ GMUX(0x178, W, 7, uart3_rxd_pw7, uartc, rsvd2, gmi, spi4),
+ GMUX(0x17C, S, 1, uart3_cts_n_pa1, uartc, sdmmc1, dtv, gmi),
+ GMUX(0x180, C, 0, uart3_rts_n_pc0, uartc, pwm0, dtv, gmi),
+ GMUX(0x184, U, 0, pu0, owr, uarta, gmi, rsvd4),
+ GMUX(0x188, U, 1, pu1, rsvd1, uarta, gmi, rsvd4),
+ GMUX(0x18C, U, 2, pu2, rsvd1, uarta, gmi, rsvd4),
+ GMUX(0x190, U, 3, pu3, pwm0, uarta, gmi, displayb),
+ GMUX(0x194, U, 4, pu4, pwm1, uarta, gmi, displayb),
+ GMUX(0x198, U, 5, pu5, pwm2, uarta, gmi, displayb),
+ GMUX(0x19C, U, 6, pu6, pwm3, uarta, rsvd3, gmi),
+ GMUX(0x1A0, C, 5, gen1_i2c_sda_pc5, i2c1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x1A4, C, 4, gen1_i2c_scl_pc4, i2c1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x1A8, P, 3, dap4_fs_pp4, i2s3, gmi, dtv, rsvd4),
+ GMUX(0x1AC, P, 4, dap4_din_pp5, i2s3, gmi, rsvd3, rsvd4),
+ GMUX(0x1B0, P, 5, dap4_dout_pp6, i2s3, gmi, dtv, rsvd4),
+ GMUX(0x1B4, P, 7, dap4_sclk_pp7, i2s3, gmi, rsvd3, rsvd4),
+ GMUX(0x1B8, P, 0, clk3_out_pee0, extperiph3, rsvd2, rsvd3, rsvd4),
+ GMUX(0x1BC, EE, 1, clk3_req_pee1, dev3, rsvd2, rsvd3, rsvd4),
+ GMUX(0x1C0, C, 7, pc7, rsvd1, rsvd2, gmi, gmi_alt),
+ GMUX(0x1C4, I, 5, pi5, sdmmc2, rsvd2, gmi, rsvd4),
+ GMUX(0x1C8, I, 7, pi7, rsvd1, trace, gmi, dtv),
+ GMUX(0x1CC, K, 0, pk0, rsvd1, sdmmc3, gmi, soc),
+ GMUX(0x1D0, K, 1, pk1, sdmmc2, trace, gmi, rsvd4),
+ GMUX(0x1D4, J, 0, pj0, rsvd1, rsvd2, gmi, usb),
+ GMUX(0x1D8, J, 2, pj2, rsvd1, rsvd2, gmi, soc),
+ GMUX(0x1DC, K, 3, pk3, sdmmc2, trace, gmi, ccla),
+ GMUX(0x1E0, K, 4, pk4, sdmmc2, rsvd2, gmi, gmi_alt),
+ GMUX(0x1E4, K, 2, pk2, rsvd1, rsvd2, gmi, rsvd4),
+ GMUX(0x1E8, I, 3, pi3, rsvd1, rsvd2, gmi, spi4),
+ GMUX(0x1EC, I, 6, pi6, rsvd1, rsvd2, gmi, sdmmc2),
+ GMUX(0x1F0, G, 0, pg0, rsvd1, rsvd2, gmi, rsvd4),
+ GMUX(0x1F4, G, 1, pg1, rsvd1, rsvd2, gmi, rsvd4),
+ GMUX(0x1F8, G, 2, pg2, rsvd1, trace, gmi, rsvd4),
+ GMUX(0x1FC, G, 3, pg3, rsvd1, trace, gmi, rsvd4),
+ GMUX(0x200, G, 4, pg4, rsvd1, tmds, gmi, spi4),
+ GMUX(0x204, G, 5, pg5, rsvd1, rsvd2, gmi, spi4),
+ GMUX(0x208, G, 6, pg6, rsvd1, rsvd2, gmi, spi4),
+ GMUX(0x20C, G, 7, pg7, rsvd1, rsvd2, gmi, spi4),
+ GMUX(0x210, H, 0, ph0, pwm0, trace, gmi, dtv),
+ GMUX(0x214, H, 1, ph1, pwm1, tmds, gmi, displaya),
+ GMUX(0x218, H, 2, ph2, pwm2, tmds, gmi, cldvfs),
+ GMUX(0x21C, H, 3, ph3, pwm3, spi4, gmi, cldvfs),
+ GMUX(0x220, H, 4, ph4, sdmmc2, rsvd2, gmi, rsvd4),
+ GMUX(0x224, H, 5, ph5, sdmmc2, rsvd2, gmi, rsvd4),
+ GMUX(0x228, H, 6, ph6, sdmmc2, trace, gmi, dtv),
+ GMUX(0x22C, H, 7, ph7, sdmmc2, trace, gmi, dtv),
+ GMUX(0x230, J, 7, pj7, uartd, rsvd2, gmi, gmi_alt),
+ GMUX(0x234, B, 0, pb0, uartd, rsvd2, gmi, rsvd4),
+ GMUX(0x238, B, 1, pb1, uartd, rsvd2, gmi, rsvd4),
+ GMUX(0x23C, K, 7, pk7, uartd, rsvd2, gmi, rsvd4),
+ GMUX(0x240, I, 0, pi0, rsvd1, rsvd2, gmi, rsvd4),
+ GMUX(0x244, I, 1, pi1, rsvd1, rsvd2, gmi, rsvd4),
+ GMUX(0x248, I, 2, pi2, sdmmc2, trace, gmi, rsvd4),
+ GMUX(0x24C, I, 4, pi4, spi4, trace, gmi, displaya),
+ GMUX(0x250, T, 5, gen2_i2c_scl_pt5, i2c2, rsvd2, gmi, rsvd4),
+ GMUX(0x254, T, 6, gen2_i2c_sda_pt6, i2c2, rsvd2, gmi, rsvd4),
+ GMUX(0x258, CC, 4, sdmmc4_clk_pcc4, sdmmc4, rsvd2, gmi, rsvd4),
+ GMUX(0x25C, T, 7, sdmmc4_cmd_pt7, sdmmc4, rsvd2, gmi, rsvd4),
+ GMUX(0x260, AA, 0, sdmmc4_dat0_paa0, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x264, AA, 1, sdmmc4_dat1_paa1, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x268, AA, 2, sdmmc4_dat2_paa2, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x26C, AA, 3, sdmmc4_dat3_paa3, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x270, AA, 4, sdmmc4_dat4_paa4, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x274, AA, 5, sdmmc4_dat5_paa5, sdmmc4, spi3, rsvd3, rsvd4),
+ GMUX(0x278, AA, 6, sdmmc4_dat6_paa6, sdmmc4, spi3, gmi, rsvd4),
+ GMUX(0x27C, AA, 7, sdmmc4_dat7_paa7, sdmmc4, rsvd2, gmi, rsvd4),
+ GMUX(0x284, CC, 0, cam_mclk_pcc0, vi, vi_alt1, vi_alt3, sdmmc2),
+ GMUX(0x288, CC, 1, pcc1, i2s4, rsvd2, rsvd3, sdmmc2),
+ GMUX(0x28C, BB, 0, pbb0, vgp6, vimclk2, sdmmc2, vimclk2_alt),
+ GMUX(0x290, BB, 1, cam_i2c_scl_pbb1, vgp1, i2c3, rsvd3, sdmmc2),
+ GMUX(0x294, BB, 2, cam_i2c_sda_pbb2, vgp2, i2c3, rsvd3, sdmmc2),
+ GMUX(0x298, BB, 3, pbb3, vgp3, displaya, displayb, sdmmc2),
+ GMUX(0x29C, BB, 4, pbb4, vgp4, displaya, displayb, sdmmc2),
+ GMUX(0x2A0, BB, 5, pbb5, vgp5, displaya, rsvd3, sdmmc2),
+ GMUX(0x2A4, BB, 6, pbb6, i2s4, rsvd2, displayb, sdmmc2),
+ GMUX(0x2A8, BB, 7, pbb7, i2s4, rsvd2, rsvd3, sdmmc2),
+ GMUX(0x2AC, CC, 2, pcc2, i2s4, rsvd2, sdmmc3, sdmmc2),
+ FMUX(0x2B0, jtag_rtck, rtck, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2B4, Z, 6, pwr_i2c_scl_pz6, i2cpwr, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2B8, Z, 7, pwr_i2c_sda_pz7, i2cpwr, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2BC, R, 0, kb_row0_pr0, kbc, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2C0, R, 1, kb_row1_pr1, kbc, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2C4, R, 2, kb_row2_pr2, kbc, rsvd2, rsvd3, rsvd4),
+ GMUX(0x2C8, R, 3, kb_row3_pr3, kbc, displaya, sys, displayb),
+ GMUX(0x2CC, R, 4, kb_row4_pr4, kbc, displaya, rsvd3, displayb),
+ GMUX(0x2D0, R, 5, kb_row5_pr5, kbc, displaya, rsvd3, displayb),
+ GMUX(0x2D4, R, 6, kb_row6_pr6, kbc, displaya, displaya_alt, displayb),
+ GMUX(0x2D8, R, 7, kb_row7_pr7, kbc, rsvd2, cldvfs, uarta),
+ GMUX(0x2DC, S, 0, kb_row8_ps0, kbc, rsvd2, cldvfs, uarta),
+ GMUX(0x2E0, S, 1, kb_row9_ps1, kbc, rsvd2, rsvd3, uarta),
+ GMUX(0x2E4, S, 2, kb_row10_ps2, kbc, rsvd2, rsvd3, uarta),
+ GMUX(0x2E8, S, 3, kb_row11_ps3, kbc, rsvd2, rsvd3, irda),
+ GMUX(0x2EC, S, 4, kb_row12_ps4, kbc, rsvd2, rsvd3, irda),
+ GMUX(0x2F0, S, 5, kb_row13_ps5, kbc, rsvd2, spi2, rsvd4),
+ GMUX(0x2F4, S, 6, kb_row14_ps6, kbc, rsvd2, spi2, rsvd4),
+ GMUX(0x2F8, S, 7, kb_row15_ps7, kbc, soc, rsvd3, rsvd4),
+ GMUX(0x2FC, Q, 0, kb_col0_pq0, kbc, rsvd2, spi2, rsvd4),
+ GMUX(0x300, Q, 1, kb_col1_pq1, kbc, rsvd2, spi2, rsvd4),
+ GMUX(0x304, Q, 2, kb_col2_pq2, kbc, rsvd2, spi2, rsvd4),
+ GMUX(0x308, Q, 3, kb_col3_pq3, kbc, displaya, pwm2, uarta),
+ GMUX(0x30C, Q, 4, kb_col4_pq4, kbc, owr, sdmmc3, uarta),
+ GMUX(0x310, Q, 5, kb_col5_pq5, kbc, rsvd2, sdmmc3, rsvd4),
+ GMUX(0x314, Q, 6, kb_col6_pq6, kbc, rsvd2, spi2, uartd),
+ GMUX(0x318, Q, 7, kb_col7_pq7, kbc, rsvd2, spi2, uartd),
+ GMUX(0x31C, A, 0, clk_32k_out_pa0, blink, soc, rsvd3, rsvd4),
+ FMUX(0x324, core_pwr_req, pwron, rsvd2, rsvd3, rsvd4),
+ FMUX(0x328, cpu_pwr_req, cpu, rsvd2, rsvd3, rsvd4),
+ FMUX(0x32C, pwr_int_n, pmi, rsvd2, rsvd3, rsvd4),
+ FMUX(0x330, clk_32k_in, clk, rsvd2, rsvd3, rsvd4),
+ FMUX(0x334, owr, owr, rsvd2, rsvd3, rsvd4),
+ GMUX(0x338, N, 0, dap1_fs_pn0, i2s0, hda, gmi, rsvd4),
+ GMUX(0x33C, N, 1, dap1_din_pn1, i2s0, hda, gmi, rsvd4),
+ GMUX(0x340, N, 2, dap1_dout_pn2, i2s0, hda, gmi, sata),
+ GMUX(0x344, N, 3, dap1_sclk_pn3, i2s0, hda, gmi, rsvd4),
+ GMUX(0x348, EE, 2, dap_mclk1_req_pee2, dap, dap1, sata, rsvd4),
+ GMUX(0x34C, W, 4, dap_mclk1_pw4, extperiph1, dap2, rsvd3, rsvd4),
+ GMUX(0x350, K, 6, spdif_in_pk6, spdif, rsvd2, rsvd3, i2c3),
+ GMUX(0x354, K, 5, spdif_out_pk5, spdif, rsvd2, rsvd3, i2c3),
+ GMUX(0x358, A, 2, dap2_fs_pa2, i2s1, hda, gmi, rsvd4),
+ GMUX(0x35C, A, 4, dap2_din_pa4, i2s1, hda, gmi, rsvd4),
+ GMUX(0x360, A, 5, dap2_dout_pa5, i2s1, hda, gmi, rsvd4),
+ GMUX(0x364, A, 3, dap2_sclk_pa3, i2s1, hda, gmi, rsvd4),
+ GMUX(0x368, X, 0, dvfs_pwm_px0, spi6, cldvfs, gmi, rsvd4),
+ GMUX(0x36C, X, 1, gpio_x1_aud_px1, spi6, rsvd2, gmi, rsvd4),
+ GMUX(0x370, X, 3, gpio_x3_aud_px3, spi6, spi1, gmi, rsvd4),
+ GMUX(0x374, X, 2, dvfs_clk_px2, spi6, cldvfs, gmi, rsvd4),
+ GMUX(0x378, X, 4, gpio_x4_aud_px4, gmi, spi1, spi2, dap2),
+ GMUX(0x37C, X, 5, gpio_x5_aud_px5, gmi, spi1, spi2, rsvd4),
+ GMUX(0x380, X, 6, gpio_x6_aud_px6, spi6, spi1, spi2, gmi),
+ GMUX(0x384, X, 7, gpio_x7_aud_px7, rsvd1, spi1, spi2, rsvd4),
+ GMUX(0x390, A, 6, sdmmc3_clk_pa6, sdmmc3, rsvd2, rsvd3, spi3),
+ GMUX(0x394, A, 7, sdmmc3_cmd_pa7, sdmmc3, pwm3, uarta, spi3),
+ GMUX(0x398, B, 7, sdmmc3_dat0_pb7, sdmmc3, rsvd2, rsvd3, spi3),
+ GMUX(0x39C, B, 6, sdmmc3_dat1_pb6, sdmmc3, pwm2, uarta, spi3),
+ GMUX(0x3A0, B, 5, sdmmc3_dat2_pb5, sdmmc3, pwm1, displaya, spi3),
+ GMUX(0x3A4, B, 4, sdmmc3_dat3_pb4, sdmmc3, pwm0, displayb, spi3),
+ GMUX(0x3BC, DD, 1, pex_l0_rst_n_pdd1, pe0, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3C0, DD, 2, pex_l0_clkreq_n_pdd2, pe0, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3C4, DD, 3, pex_wake_n_pdd3, pe, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3CC, DD, 5, pex_l1_rst_n_pdd5, pe1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3D0, DD, 6, pex_l1_clkreq_n_pdd6, pe1, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3E0, EE, 3, hdmi_cec_pee3, cec, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3E4, V, 3, sdmmc1_wp_n_pv3, sdmmc1, clk12, spi4, uarta),
+ GMUX(0x3E8, V, 2, sdmmc3_cd_n_pv2, sdmmc3, owr, rsvd3, rsvd4),
+ GMUX(0x3EC, W, 2, gpio_w2_aud_pw2, spi6, rsvd2, spi2, i2c1),
+ GMUX(0x3F0, W, 3, gpio_w3_aud_pw3, spi6, spi1, spi2, i2c1),
+ GMUX(0x3F4, N, 4, usb_vbus_en0_pn4, usb, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3F8, N, 5, usb_vbus_en1_pn5, usb, rsvd2, rsvd3, rsvd4),
+ GMUX(0x3FC, EE, 5, sdmmc3_clk_lb_in_pee5, sdmmc3, rsvd2, rsvd3, rsvd4),
+ GMUX(0x400, EE, 4, sdmmc3_clk_lb_out_pee4, sdmmc3, rsvd2, rsvd3, rsvd4),
+ FMUX(0x404, gmi_clk_lb, sdmmc2, rsvd2, gmi, rsvd4),
+ FMUX(0x408, reset_out_n, rsvd1, rsvd2, rsvd3, reset_out_n),
+ GMUX(0x40C, T, 0, kb_row16_pt0, kbc, rsvd2, rsvd3, uartc),
+ GMUX(0x410, T, 1, kb_row17_pt1, kbc, rsvd2, rsvd3, uartc),
+ GMUX(0x414, FF, 1, usb_vbus_en2_pff1, usb, rsvd2, rsvd3, rsvd4),
+ GMUX(0x418, FF, 2, pff2, sata, rsvd2, rsvd3, rsvd4),
+ GMUX(0x430, FF, 0, dp_hpd_pff0, dp, rsvd2, rsvd3, rsvd4),
+};
+
+struct tegra_grp {
+ char *name;
+ bus_size_t reg;
+ int drvdn_shift;
+ int drvdn_mask;
+ int drvup_shift;
+ int drvup_mask;
+};
+
+#define GRP(r, nm, dn_s, dn_w, up_s, up_w) \
+{ \
+ .name = #nm, \
+ .reg = r - 0x868, \
+ .drvdn_shift = dn_s, \
+ .drvdn_mask = (1 << dn_w) - 1, \
+ .drvup_shift = up_s, \
+ .drvup_mask = (1 << dn_w) - 1, \
+}
+
+/* Use register offsets from TRM */
+static const struct tegra_grp pin_grp_tbl[] = {
+ GRP(0x868, ao1, 12, 5, 20, 5),
+ GRP(0x86C, ao2, 12, 5, 20, 5),
+ GRP(0x870, at1, 12, 7, 20, 7),
+ GRP(0x874, at2, 12, 7, 20, 7),
+ GRP(0x878, at3, 12, 7, 20, 7),
+ GRP(0x87C, at4, 12, 7, 20, 7),
+ GRP(0x880, at5, 14, 5, 19, 5),
+ GRP(0x884, cdev1, 12, 5, 20, 5),
+ GRP(0x888, cdev2, 12, 5, 20, 5),
+ GRP(0x890, dap1, 12, 5, 20, 5),
+ GRP(0x894, dap2, 12, 5, 20, 5),
+ GRP(0x898, dap3, 12, 5, 20, 5),
+ GRP(0x89C, dap4, 12, 5, 20, 5),
+ GRP(0x8A0, dbg, 12, 5, 20, 5),
+ GRP(0x8B0, sdio3, 12, 7, 20, 7),
+ GRP(0x8B4, spi, 12, 5, 20, 5),
+ GRP(0x8B8, uaa, 12, 5, 20, 5),
+ GRP(0x8BC, uab, 12, 5, 20, 5),
+ GRP(0x8C0, uart2, 12, 5, 20, 5),
+ GRP(0x8C4, uart3, 12, 5, 20, 5),
+ GRP(0x8EC, sdio1, 12, 7, 20, 7),
+ GRP(0x8FC, ddc, 12, 5, 20, 5),
+ GRP(0x900, gma, 14, 5, 20, 5),
+ GRP(0x910, gme, 14, 5, 19, 5),
+ GRP(0x914, gmf, 14, 5, 19, 5),
+ GRP(0x918, gmg, 14, 5, 19, 5),
+ GRP(0x91C, gmh, 14, 5, 19, 5),
+ GRP(0x920, owr, 12, 5, 20, 5),
+ GRP(0x924, uda, 12, 5, 20, 5),
+ GRP(0x928, gpv, 12, 5, 20, 5),
+ GRP(0x92C, dev3, 12, 5, 20, 5),
+ GRP(0x938, cec, 12, 5, 20, 5),
+ GRP(0x994, at6, 12, 7, 20, 7),
+ GRP(0x998, dap5, 12, 5, 20, 5),
+ GRP(0x99C, usb_vbus_en, 12, 5, 20, 5),
+ GRP(0x9A8, ao3, 12, 5, -1, 0),
+ GRP(0x9B0, ao0, 12, 5, 20, 5),
+ GRP(0x9B4, hv0, 12, 5, -1, 0),
+ GRP(0x9C4, sdio4, 12, 5, 20, 5),
+ GRP(0x9C8, ao4, 12, 7, 20, 7),
+};
+
+static const struct tegra_grp *
+pinmux_search_grp(char *grp_name)
+{
+ int i;
+
+ for (i = 0; i < nitems(pin_grp_tbl); i++) {
+ if (strcmp(grp_name, pin_grp_tbl[i].name) == 0)
+ return (&pin_grp_tbl[i]);
+ }
+ return (NULL);
+}
+
+static const struct tegra_mux *
+pinmux_search_mux(char *pin_name)
+{
+ int i;
+
+ for (i = 0; i < nitems(pin_mux_tbl); i++) {
+ if (strcmp(pin_name, pin_mux_tbl[i].name) == 0)
+ return (&pin_mux_tbl[i]);
+ }
+ return (NULL);
+}
+
+static int
+pinmux_mux_function(const struct tegra_mux *mux, char *fnc_name)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (strcmp(fnc_name, mux->functions[i]) == 0)
+ return (i);
+ }
+ return (-1);
+}
+
+static int
+pinmux_config_mux(struct pinmux_softc *sc, char *pin_name,
+ const struct tegra_mux *mux, struct pincfg *cfg)
+{
+ int tmp;
+ uint32_t reg;
+
+ reg = bus_read_4(sc->mux_mem_res, mux->reg);
+
+ if (cfg->function != NULL) {
+ tmp = pinmux_mux_function(mux, cfg->function);
+ if (tmp == -1) {
+ device_printf(sc->dev,
+ "Unknown function %s for pin %s\n", cfg->function,
+ pin_name);
+ return (ENXIO);
+ }
+ reg &= ~(TEGRA_MUX_FUNCTION_MASK << TEGRA_MUX_FUNCTION_SHIFT);
+ reg |= (tmp & TEGRA_MUX_FUNCTION_MASK) <<
+ TEGRA_MUX_FUNCTION_SHIFT;
+ }
+ if (cfg->params[PROP_ID_PULL] != -1) {
+ reg &= ~(TEGRA_MUX_PUPD_MASK << TEGRA_MUX_PUPD_SHIFT);
+ reg |= (cfg->params[PROP_ID_PULL] & TEGRA_MUX_PUPD_MASK) <<
+ TEGRA_MUX_PUPD_SHIFT;
+ }
+ if (cfg->params[PROP_ID_TRISTATE] != -1) {
+ reg &= ~(1 << TEGRA_MUX_TRISTATE_SHIFT);
+ reg |= (cfg->params[PROP_ID_TRISTATE] & 1) <<
+ TEGRA_MUX_TRISTATE_SHIFT;
+ }
+ if (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] != -1) {
+ reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
+ reg |= (cfg->params[TEGRA_MUX_ENABLE_INPUT_SHIFT] & 1) <<
+ TEGRA_MUX_ENABLE_INPUT_SHIFT;
+ }
+ if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) {
+ reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
+ reg |= (cfg->params[PROP_ID_ENABLE_INPUT] & 1) <<
+ TEGRA_MUX_ENABLE_INPUT_SHIFT;
+ }
+ if (cfg->params[PROP_ID_ENABLE_INPUT] != -1) {
+ reg &= ~(1 << TEGRA_MUX_ENABLE_INPUT_SHIFT);
+ reg |= (cfg->params[PROP_ID_OPEN_DRAIN] & 1) <<
+ TEGRA_MUX_ENABLE_INPUT_SHIFT;
+ }
+ if (cfg->params[PROP_ID_LOCK] != -1) {
+ reg &= ~(1 << TEGRA_MUX_LOCK_SHIFT);
+ reg |= (cfg->params[PROP_ID_LOCK] & 1) <<
+ TEGRA_MUX_LOCK_SHIFT;
+ }
+ if (cfg->params[PROP_ID_IORESET] != -1) {
+ reg &= ~(1 << TEGRA_MUX_IORESET_SHIFT);
+ reg |= (cfg->params[PROP_ID_IORESET] & 1) <<
+ TEGRA_MUX_IORESET_SHIFT;
+ }
+ if (cfg->params[PROP_ID_RCV_SEL] != -1) {
+ reg &= ~(1 << TEGRA_MUX_RCV_SEL_SHIFT);
+ reg |= (cfg->params[PROP_ID_RCV_SEL] & 1) <<
+ TEGRA_MUX_RCV_SEL_SHIFT;
+ }
+ bus_write_4(sc->mux_mem_res, mux->reg, reg);
+ return (0);
+}
+
+static int
+pinmux_config_grp(struct pinmux_softc *sc, char *grp_name,
+ const struct tegra_grp *grp, struct pincfg *cfg)
+{
+ uint32_t reg;
+
+ reg = bus_read_4(sc->pad_mem_res, grp->reg);
+
+ if (cfg->params[PROP_ID_HIGH_SPEED_MODE] != -1) {
+ reg &= ~(1 << TEGRA_GRP_HSM_SHIFT);
+ reg |= (cfg->params[PROP_ID_HIGH_SPEED_MODE] & 1) <<
+ TEGRA_GRP_HSM_SHIFT;
+ }
+ if (cfg->params[PROP_ID_SCHMITT] != -1) {
+ reg &= ~(1 << TEGRA_GRP_SCHMT_SHIFT);
+ reg |= (cfg->params[PROP_ID_SCHMITT] & 1) <<
+ TEGRA_GRP_SCHMT_SHIFT;
+ }
+ if (cfg->params[PROP_ID_DRIVE_TYPE] != -1) {
+ reg &= ~(TEGRA_GRP_DRV_TYPE_MASK << TEGRA_GRP_DRV_TYPE_SHIFT);
+ reg |= (cfg->params[PROP_ID_DRIVE_TYPE] &
+ TEGRA_GRP_DRV_TYPE_MASK) << TEGRA_GRP_DRV_TYPE_SHIFT;
+ }
+ if (cfg->params[PROP_ID_SLEW_RATE_RISING] != -1) {
+ reg &= ~(TEGRA_GRP_DRV_DRVDN_SLWR_MASK <<
+ TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT);
+ reg |= (cfg->params[PROP_ID_SLEW_RATE_RISING] &
+ TEGRA_GRP_DRV_DRVDN_SLWR_MASK) <<
+ TEGRA_GRP_DRV_DRVDN_SLWR_SHIFT;
+ }
+ if (cfg->params[PROP_ID_SLEW_RATE_FALLING] != -1) {
+ reg &= ~(TEGRA_GRP_DRV_DRVUP_SLWF_MASK <<
+ TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT);
+ reg |= (cfg->params[PROP_ID_SLEW_RATE_FALLING] &
+ TEGRA_GRP_DRV_DRVUP_SLWF_MASK) <<
+ TEGRA_GRP_DRV_DRVUP_SLWF_SHIFT;
+ }
+ if ((cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] != -1) &&
+ (grp->drvdn_mask != -1)) {
+ reg &= ~(grp->drvdn_shift << grp->drvdn_mask);
+ reg |= (cfg->params[PROP_ID_DRIVE_DOWN_STRENGTH] &
+ grp->drvdn_mask) << grp->drvdn_shift;
+ }
+ if ((cfg->params[PROP_ID_DRIVE_UP_STRENGTH] != -1) &&
+ (grp->drvup_mask != -1)) {
+ reg &= ~(grp->drvup_shift << grp->drvup_mask);
+ reg |= (cfg->params[PROP_ID_DRIVE_UP_STRENGTH] &
+ grp->drvup_mask) << grp->drvup_shift;
+ }
+ bus_write_4(sc->pad_mem_res, grp->reg, reg);
+ return (0);
+}
+
+static int
+pinmux_config_node(struct pinmux_softc *sc, char *pin_name, struct pincfg *cfg)
+{
+ const struct tegra_mux *mux;
+ const struct tegra_grp *grp;
+ uint32_t reg;
+ int rv;
+
+ /* Handle MIPI special case first */
+ if (strcmp(pin_name, "dsi_b") == 0) {
+ if (cfg->function == NULL) {
+ /* nothing to set */
+ return (0);
+ }
+ reg = bus_read_4(sc->mipi_mem_res, 0); /* register 0x820 */
+ if (strcmp(cfg->function, "csi") == 0)
+ reg &= ~(1 << 1);
+ else if (strcmp(cfg->function, "dsi_b") == 0)
+ reg |= (1 << 1);
+ bus_write_4(sc->mipi_mem_res, 0, reg); /* register 0x820 */
+ }
+
+ /* Handle pin muxes */
+ mux = pinmux_search_mux(pin_name);
+ if (mux != NULL) {
+ if (mux->gpio_num != -1) {
+ /* XXXX TODO: Reserve gpio here */
+ }
+ rv = pinmux_config_mux(sc, pin_name, mux, cfg);
+ return (rv);
+ }
+
+ /* Handle pin groups */
+ grp = pinmux_search_grp(pin_name);
+ if (grp != NULL) {
+ rv = pinmux_config_grp(sc, pin_name, grp, cfg);
+ return (rv);
+ }
+
+ device_printf(sc->dev, "Unknown pin: %s\n", pin_name);
+ return (ENXIO);
+}
+
+static int
+pinmux_read_node(struct pinmux_softc *sc, phandle_t node, struct pincfg *cfg,
+ char **pins, int *lpins)
+{
+ int rv, i;
+
+ *lpins = OF_getprop_alloc(node, "nvidia,pins", 1, (void **)pins);
+ if (*lpins <= 0)
+ return (ENOENT);
+
+ /* Read function (mux) settings. */
+ rv = OF_getprop_alloc(node, "nvidia,function", 1,
+ (void **)&cfg->function);
+ if (rv <= 0)
+ cfg->function = NULL;
+
+ /* Read numeric properties. */
+ for (i = 0; i < PROP_ID_MAX_ID; i++) {
+ rv = OF_getencprop(node, prop_names[i].name, &cfg->params[i],
+ sizeof(cfg->params[i]));
+ if (rv <= 0)
+ cfg->params[i] = -1;
+ }
+ return (0);
+}
+
+static int
+pinmux_process_node(struct pinmux_softc *sc, phandle_t node)
+{
+ struct pincfg cfg;
+ char *pins, *pname;
+ int i, len, lpins, rv;
+
+ rv = pinmux_read_node(sc, node, &cfg, &pins, &lpins);
+ if (rv != 0)
+ return (rv);
+
+ len = 0;
+ pname = pins;
+ do {
+ i = strlen(pname) + 1;
+ rv = pinmux_config_node(sc, pname, &cfg);
+ if (rv != 0)
+ device_printf(sc->dev,
+ "Cannot configure pin: %s: %d\n", pname, rv);
+
+ len += i;
+ pname += i;
+ } while (len < lpins);
+
+ if (pins != NULL)
+ free(pins, M_OFWPROP);
+ if (cfg.function != NULL)
+ free(cfg.function, M_OFWPROP);
+ return (rv);
+}
+
+static int pinmux_configure(device_t dev, phandle_t cfgxref)
+{
+ struct pinmux_softc *sc;
+ phandle_t node, cfgnode;
+ int rv;
+
+ sc = device_get_softc(dev);
+ cfgnode = OF_node_from_xref(cfgxref);
+
+
+ for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {
+ if (!fdt_is_enabled(node))
+ continue;
+ rv = pinmux_process_node(sc, node);
+ }
+ return (0);
+}
+
+static int
+pinmux_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Tegra pin configuration");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+pinmux_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static int
+pinmux_attach(device_t dev)
+{
+ struct pinmux_softc * sc;
+ int rid;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ rid = 0;
+ sc->pad_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->pad_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ rid = 1;
+ sc->mux_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mux_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ rid = 2;
+ sc->mipi_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mipi_mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ /* Register as a pinctrl device and process default configuration */
+ fdt_pinctrl_register(dev, NULL);
+ fdt_pinctrl_configure_by_name(dev, "boot");
+
+ return (0);
+}
+
+
+static device_method_t tegra_pinmux_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, pinmux_probe),
+ DEVMETHOD(device_attach, pinmux_attach),
+ DEVMETHOD(device_detach, pinmux_detach),
+
+ /* fdt_pinctrl interface */
+ DEVMETHOD(fdt_pinctrl_configure,pinmux_configure),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra_pinmux_driver = {
+ "tegra_pinmux",
+ tegra_pinmux_methods,
+ sizeof(struct pinmux_softc),
+};
+
+static devclass_t tegra_pinmux_devclass;
+
+EARLY_DRIVER_MODULE(tegra_pinmux, simplebus, tegra_pinmux_driver,
+ tegra_pinmux_devclass, 0, 0, 71);
diff --git a/sys/arm/nvidia/tegra_pmc.h b/sys/arm/nvidia/tegra_pmc.h
new file mode 100644
index 0000000..933c408
--- /dev/null
+++ b/sys/arm/nvidia/tegra_pmc.h
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TEGRA_PMC_H_
+#define _TEGRA_PMC_H_
+
+enum tegra_suspend_mode {
+ TEGRA_SUSPEND_NONE = 0,
+ TEGRA_SUSPEND_LP2, /* CPU voltage off */
+ TEGRA_SUSPEND_LP1, /* CPU voltage off, DRAM self-refresh */
+ TEGRA_SUSPEND_LP0, /* CPU + core voltage off, DRAM self-refresh */
+};
+
+/* PARTIDs for powergate */
+enum tegra_powergate_id {
+ TEGRA_POWERGATE_CRAIL = 0,
+ TEGRA_POWERGATE_TD = 1,
+ TEGRA_POWERGATE_VE = 2,
+ TEGRA_POWERGATE_PCX = 3,
+ TEGRA_POWERGATE_VDE = 4,
+ TEGRA_POWERGATE_L2C = 5,
+ TEGRA_POWERGATE_MPE = 6,
+ TEGRA_POWERGATE_HEG = 7,
+ TEGRA_POWERGATE_SAX = 8,
+ TEGRA_POWERGATE_CE1 = 9,
+ TEGRA_POWERGATE_CE2 = 10,
+ TEGRA_POWERGATE_CE3 = 11,
+ TEGRA_POWERGATE_CELP = 12,
+ /* */
+ TEGRA_POWERGATE_CE0 = 14,
+ TEGRA_POWERGATE_C0NC = 15,
+ TEGRA_POWERGATE_C1NC = 16,
+ TEGRA_POWERGATE_SOR = 17,
+ TEGRA_POWERGATE_DIS = 18,
+ TEGRA_POWERGATE_DISB = 19,
+ TEGRA_POWERGATE_XUSBA = 20,
+ TEGRA_POWERGATE_XUSBB = 21,
+ TEGRA_POWERGATE_XUSBC = 22,
+ TEGRA_POWERGATE_VIC = 23,
+ TEGRA_POWERGATE_IRAM = 24,
+ /* */
+ TEGRA_POWERGATE_3D = 32
+
+};
+
+/* PARTIDs for power rails */
+enum tegra_powerrail_id {
+ TEGRA_IO_RAIL_CSIA = 0,
+ TEGRA_IO_RAIL_CSIB = 1,
+ TEGRA_IO_RAIL_DSI = 2,
+ TEGRA_IO_RAIL_MIPI_BIAS = 3,
+ TEGRA_IO_RAIL_PEX_BIAS = 4,
+ TEGRA_IO_RAIL_PEX_CLK1 = 5,
+ TEGRA_IO_RAIL_PEX_CLK2 = 6,
+ TEGRA_IO_RAIL_USB0 = 9,
+ TEGRA_IO_RAIL_USB1 = 10,
+ TEGRA_IO_RAIL_USB2 = 11,
+ TEGRA_IO_RAIL_USB_BIAS = 12,
+ TEGRA_IO_RAIL_NAND = 13,
+ TEGRA_IO_RAIL_UART = 14,
+ TEGRA_IO_RAIL_BB = 15,
+ TEGRA_IO_RAIL_AUDIO = 17,
+ TEGRA_IO_RAIL_HSIC = 19,
+ TEGRA_IO_RAIL_COMP = 22,
+ TEGRA_IO_RAIL_HDMI = 28,
+ TEGRA_IO_RAIL_PEX_CNTRL = 32,
+ TEGRA_IO_RAIL_SDMMC1 = 33,
+ TEGRA_IO_RAIL_SDMMC3 = 34,
+ TEGRA_IO_RAIL_SDMMC4 = 35,
+ TEGRA_IO_RAIL_CAM = 36,
+ TEGRA_IO_RAIL_RES = 37,
+ TEGRA_IO_RAIL_HV = 38,
+ TEGRA_IO_RAIL_DSIB = 39,
+ TEGRA_IO_RAIL_DSIC = 40,
+ TEGRA_IO_RAIL_DSID = 41,
+ TEGRA_IO_RAIL_CSIE = 44,
+ TEGRA_IO_RAIL_LVDS = 57,
+ TEGRA_IO_RAIL_SYS_DDC = 58,
+};
+
+int tegra_powergate_is_powered(enum tegra_powergate_id id);
+int tegra_powergate_power_on(enum tegra_powergate_id id);
+int tegra_powergate_power_off(enum tegra_powergate_id id);
+int tegra_powergate_remove_clamping(enum tegra_powergate_id id);
+int tegra_powergate_sequence_power_up(enum tegra_powergate_id id,
+ clk_t clk, hwreset_t rst);
+int tegra_io_rail_power_on(int tegra_powerrail_id);
+int tegra_io_rail_power_off(int tegra_powerrail_id);
+
+#endif /*_TEGRA_PMC_H_*/ \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra_rtc.c b/sys/arm/nvidia/tegra_rtc.c
new file mode 100644
index 0000000..c15ded3
--- /dev/null
+++ b/sys/arm/nvidia/tegra_rtc.c
@@ -0,0 +1,303 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * RTC driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clock_if.h"
+
+#define RTC_CONTROL 0x00
+#define RTC_BUSY 0x04
+#define RTC_BUSY_STATUS (1 << 0)
+#define RTC_SECONDS 0x08
+#define RTC_SHADOW_SECONDS 0x0c
+#define RTC_MILLI_SECONDS 0x10
+#define RTC_SECONDS_ALARM0 0x14
+#define RTC_SECONDS_ALARM1 0x18
+#define RTC_MILLI_SECONDS_ALARM 0x1c
+#define RTC_SECONDS_COUNTDOWN_ALARM 0x20
+#define RTC_MILLI_SECONDS_COUNTDOW_ALARM 0x24
+#define RTC_INTR_MASK 0x28
+#define RTC_INTR_MSEC_CDN_ALARM (1 << 4)
+#define RTC_INTR_SEC_CDN_ALARM (1 << 3)
+#define RTC_INTR_MSEC_ALARM (1 << 2)
+#define RTC_INTR_SEC_ALARM1 (1 << 1)
+#define RTC_INTR_SEC_ALARM0 (1 << 0)
+
+#define RTC_INTR_STATUS 0x2c
+#define RTC_INTR_SOURCE 0x30
+#define RTC_INTR_SET 0x34
+#define RTC_CORRECTION_FACTOR 0x38
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
+
+#define LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define SLEEP(_sc, timeout) \
+ mtx_sleep(sc, &sc->mtx, 0, "rtcwait", timeout);
+#define LOCK_INIT(_sc) \
+ mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_rtc", MTX_DEF)
+#define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx)
+#define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED)
+#define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED)
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-rtc", 1},
+ {NULL, 0}
+};
+
+struct tegra_rtc_softc {
+ device_t dev;
+ struct mtx mtx;
+
+ struct resource *mem_res;
+ struct resource *irq_res;
+ void *irq_h;
+
+ clk_t clk;
+ uint32_t core_freq;
+};
+
+static void
+tegra_rtc_wait(struct tegra_rtc_softc *sc)
+{
+ int timeout;
+
+ for (timeout = 500; timeout >0; timeout--) {
+ if ((RD4(sc, RTC_BUSY) & RTC_BUSY_STATUS) == 0)
+ break;
+ DELAY(1);
+ }
+ if (timeout <= 0)
+ device_printf(sc->dev, "Device busy timeouted\n");
+
+}
+
+/*
+ * Get the time of day clock and return it in ts.
+ * Return 0 on success, an error number otherwise.
+ */
+static int
+tegra_rtc_gettime(device_t dev, struct timespec *ts)
+{
+ struct tegra_rtc_softc *sc;
+ struct timeval tv;
+ uint32_t msec, sec;
+
+ sc = device_get_softc(dev);
+
+ LOCK(sc);
+ msec = RD4(sc, RTC_MILLI_SECONDS);
+ sec = RD4(sc, RTC_SHADOW_SECONDS);
+ UNLOCK(sc);
+ tv.tv_sec = sec;
+ tv.tv_usec = msec * 1000;
+ TIMEVAL_TO_TIMESPEC(&tv, ts);
+ return (0);
+}
+
+
+static int
+tegra_rtc_settime(device_t dev, struct timespec *ts)
+{
+ struct tegra_rtc_softc *sc;
+ struct timeval tv;
+
+ sc = device_get_softc(dev);
+
+ LOCK(sc);
+ TIMESPEC_TO_TIMEVAL(&tv, ts);
+ tegra_rtc_wait(sc);
+ WR4(sc, RTC_SECONDS, tv.tv_sec);
+ UNLOCK(sc);
+
+ return (0);
+}
+
+
+static void
+tegra_rtc_intr(void *arg)
+{
+ struct tegra_rtc_softc *sc;
+ uint32_t status;
+
+ sc = (struct tegra_rtc_softc *)arg;
+ LOCK(sc);
+ status = RD4(sc, RTC_INTR_STATUS);
+ WR4(sc, RTC_INTR_STATUS, status);
+ UNLOCK(sc);
+}
+
+static int
+tegra_rtc_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_rtc_attach(device_t dev)
+{
+ int rv, rid;
+ struct tegra_rtc_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ LOCK_INIT(sc);
+
+ /* Get the memory resource for the register mapping. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot map registers.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate our IRQ resource. */
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate interrupt.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ /* OFW resources. */
+ rv = clk_get_by_ofw_index(dev, 0, &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get i2c clock: %d\n", rv);
+ goto fail;
+ }
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable clock: %d\n", rv);
+ goto fail;
+ }
+
+ /* Init hardware. */
+ WR4(sc, RTC_SECONDS_ALARM0, 0);
+ WR4(sc, RTC_SECONDS_ALARM1, 0);
+ WR4(sc, RTC_INTR_STATUS, 0xFFFFFFFF);
+ WR4(sc, RTC_INTR_MASK, 0);
+
+ /* Setup interrupt */
+ rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, tegra_rtc_intr, sc, &sc->irq_h);
+ if (rv) {
+ device_printf(dev, "Cannot setup interrupt.\n");
+ goto fail;
+ }
+
+ /*
+ * Register as a time of day clock with 1-second resolution.
+ *
+ * XXXX Not yet, we don't have support for multiple RTCs
+ */
+ /* clock_register(dev, 1000000); */
+
+ return (bus_generic_attach(dev));
+
+fail:
+ if (sc->clk != NULL)
+ clk_release(sc->clk);
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+ LOCK_DESTROY(sc);
+
+ return (rv);
+}
+
+static int
+tegra_rtc_detach(device_t dev)
+{
+ struct tegra_rtc_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->irq_h != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ LOCK_DESTROY(sc);
+ return (bus_generic_detach(dev));
+}
+
+static device_method_t tegra_rtc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_rtc_probe),
+ DEVMETHOD(device_attach, tegra_rtc_attach),
+ DEVMETHOD(device_detach, tegra_rtc_detach),
+
+ /* clock interface */
+ DEVMETHOD(clock_gettime, tegra_rtc_gettime),
+ DEVMETHOD(clock_settime, tegra_rtc_settime),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(tegra_rtc, tegra_rtc_driver, tegra_rtc_methods,
+ sizeof(struct tegra_rtc_softc));
+static devclass_t tegra_rtc_devclass;
+DRIVER_MODULE(tegra_rtc, simplebus, tegra_rtc_driver, tegra_rtc_devclass, 0, 0);
diff --git a/sys/arm/nvidia/tegra_sdhci.c b/sys/arm/nvidia/tegra_sdhci.c
new file mode 100644
index 0000000..e2ec063
--- /dev/null
+++ b/sys/arm/nvidia/tegra_sdhci.c
@@ -0,0 +1,465 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * SDHCI driver glue for NVIDIA Tegra family
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/callout.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
+#include <sys/time.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/sdhci/sdhci.h>
+
+#include "sdhci_if.h"
+
+/* Tegra SDHOST controller vendor register definitions */
+#define SDMMC_VENDOR_CLOCK_CNTRL 0x100
+#define VENDOR_CLOCK_CNTRL_CLK_SHIFT 8
+#define VENDOR_CLOCK_CNTRL_CLK_MASK 0xFF
+#define SDMMC_VENDOR_SYS_SW_CNTRL 0x104
+#define SDMMC_VENDOR_CAP_OVERRIDES 0x10C
+#define SDMMC_VENDOR_BOOT_CNTRL 0x110
+#define SDMMC_VENDOR_BOOT_ACK_TIMEOUT 0x114
+#define SDMMC_VENDOR_BOOT_DAT_TIMEOUT 0x118
+#define SDMMC_VENDOR_DEBOUNCE_COUNT 0x11C
+#define SDMMC_VENDOR_MISC_CNTRL 0x120
+#define VENDOR_MISC_CTRL_ENABLE_SDR104 0x8
+#define VENDOR_MISC_CTRL_ENABLE_SDR50 0x10
+#define VENDOR_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
+#define VENDOR_MISC_CTRL_ENABLE_DDR50 0x200
+#define SDMMC_MAX_CURRENT_OVERRIDE 0x124
+#define SDMMC_MAX_CURRENT_OVERRIDE_HI 0x128
+#define SDMMC_VENDOR_CLK_GATE_HYSTERESIS_COUNT 0x1D0
+#define SDMMC_VENDOR_PHWRESET_VAL0 0x1D4
+#define SDMMC_VENDOR_PHWRESET_VAL1 0x1D8
+#define SDMMC_VENDOR_PHWRESET_VAL2 0x1DC
+#define SDMMC_SDMEMCOMPPADCTRL_0 0x1E0
+#define SDMMC_AUTO_CAL_CONFIG 0x1E4
+#define SDMMC_AUTO_CAL_INTERVAL 0x1E8
+#define SDMMC_AUTO_CAL_STATUS 0x1EC
+#define SDMMC_SDMMC_MCCIF_FIFOCTRL 0x1F4
+#define SDMMC_TIMEOUT_WCOAL_SDMMC 0x1F8
+
+/* Compatible devices. */
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-sdhci", 1},
+ {NULL, 0},
+};
+
+struct tegra_sdhci_softc {
+ device_t dev;
+ struct resource * mem_res;
+ struct resource * irq_res;
+ void * intr_cookie;
+ u_int quirks; /* Chip specific quirks */
+ u_int caps; /* If we override SDHCI_CAPABILITIES */
+ uint32_t max_clk; /* Max possible freq */
+ clk_t clk;
+ hwreset_t reset;
+ gpio_pin_t gpio_cd;
+ gpio_pin_t gpio_wp;
+ gpio_pin_t gpio_power;
+
+ int force_card_present;
+ struct sdhci_slot slot;
+
+};
+
+static inline uint32_t
+RD4(struct tegra_sdhci_softc *sc, bus_size_t off)
+{
+
+ return (bus_read_4(sc->mem_res, off));
+}
+
+static uint8_t
+tegra_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (bus_read_1(sc->mem_res, off));
+}
+
+static uint16_t
+tegra_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (bus_read_2(sc->mem_res, off));
+}
+
+static uint32_t
+tegra_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+{
+ struct tegra_sdhci_softc *sc;
+ uint32_t val32;
+
+ sc = device_get_softc(dev);
+ val32 = bus_read_4(sc->mem_res, off);
+ /* Force the card-present state if necessary. */
+ if (off == SDHCI_PRESENT_STATE && sc->force_card_present)
+ val32 |= SDHCI_CARD_PRESENT;
+ return (val32);
+}
+
+static void
+tegra_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+ uint32_t *data, bus_size_t count)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_read_multi_4(sc->mem_res, off, data, count);
+}
+
+static void
+tegra_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+ uint8_t val)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_1(sc->mem_res, off, val);
+}
+
+static void
+tegra_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+ uint16_t val)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_2(sc->mem_res, off, val);
+}
+
+static void
+tegra_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+ uint32_t val)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_4(sc->mem_res, off, val);
+}
+
+static void
+tegra_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+ uint32_t *data, bus_size_t count)
+{
+ struct tegra_sdhci_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_write_multi_4(sc->mem_res, off, data, count);
+}
+
+static void
+tegra_sdhci_intr(void *arg)
+{
+ struct tegra_sdhci_softc *sc = arg;
+
+ sdhci_generic_intr(&sc->slot);
+ RD4(sc, SDHCI_INT_STATUS);
+}
+
+static int
+tegra_generic_get_ro(device_t brdev, device_t reqdev)
+{
+
+ return (0);
+}
+
+static int
+tegra_sdhci_probe(device_t dev)
+{
+ struct tegra_sdhci_softc *sc;
+ phandle_t node;
+ pcell_t cid;
+ const struct ofw_compat_data *cd;
+
+ sc = device_get_softc(dev);
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_is_compatible(dev, "nvidia,tegra124-sdhci")) {
+ device_set_desc(dev, "Tegra SDHCI controller");
+ } else
+ return (ENXIO);
+ cd = ofw_bus_search_compatible(dev, compat_data);
+ if (cd->ocd_data == 0)
+ return (ENXIO);
+
+ node = ofw_bus_get_node(dev);
+
+ /* Allow dts to patch quirks, slots, and max-frequency. */
+ if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0)
+ sc->quirks = cid;
+ if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0)
+ sc->max_clk = cid;
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tegra_sdhci_attach(device_t dev)
+{
+ struct tegra_sdhci_softc *sc;
+ int rid, rv;
+ uint64_t freq;
+ phandle_t node, prop;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (!sc->irq_res) {
+ device_printf(dev, "cannot allocate interrupt\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+ NULL, tegra_sdhci_intr, sc, &sc->intr_cookie)) {
+ device_printf(dev, "cannot setup interrupt handler\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rv = hwreset_get_by_ofw_name(sc->dev, "sdhci", &sc->reset);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'sdhci' reset\n");
+ goto fail;
+ }
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot unreset 'sdhci' reset\n");
+ goto fail;
+ }
+
+ gpio_pin_get_by_ofw_property(sc->dev, "cd-gpios", &sc->gpio_cd);
+ gpio_pin_get_by_ofw_property(sc->dev, "power-gpios", &sc->gpio_power);
+ gpio_pin_get_by_ofw_property(sc->dev, "wp-gpios", &sc->gpio_wp);
+
+ rv = clk_get_by_ofw_index(dev, 0, &sc->clk);
+ if (rv != 0) {
+
+ device_printf(dev, "Cannot get clock\n");
+ goto fail;
+ }
+
+ rv = clk_get_by_ofw_index(dev, 0, &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get clock\n");
+ goto fail;
+ }
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable clock\n");
+ goto fail;
+ }
+ rv = clk_set_freq(sc->clk, 48000000, CLK_SET_ROUND_DOWN);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set clock\n");
+ }
+ rv = clk_get_freq(sc->clk, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get clock frequency\n");
+ goto fail;
+ }
+ if (bootverbose)
+ device_printf(dev, " Base MMC clock: %lld\n", freq);
+
+ /* Fill slot information. */
+ sc->max_clk = (int)freq;
+ sc->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+ SDHCI_QUIRK_MISSING_CAPS;
+
+ /* Limit real slot capabilities. */
+ sc->caps = RD4(sc, SDHCI_CAPABILITIES);
+ if (OF_getencprop(node, "bus-width", &prop, sizeof(prop)) > 0) {
+ sc->caps &= ~(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
+ switch (prop) {
+ case 8:
+ sc->caps |= MMC_CAP_8_BIT_DATA;
+ /* FALLTHROUGH */
+ case 4:
+ sc->caps |= MMC_CAP_4_BIT_DATA;
+ break;
+ case 1:
+ break;
+ default:
+ device_printf(dev, "Bad bus-width value %u\n", prop);
+ break;
+ }
+ }
+ if (OF_hasprop(node, "non-removable"))
+ sc->force_card_present = 1;
+ /*
+ * Clear clock field, so SDHCI driver uses supplied frequency.
+ * in sc->slot.max_clk
+ */
+ sc->caps &= ~SDHCI_CLOCK_V3_BASE_MASK;
+
+ sc->slot.quirks = sc->quirks;
+ sc->slot.max_clk = sc->max_clk;
+ sc->slot.caps = sc->caps;
+
+ rv = sdhci_init_slot(dev, &sc->slot, 0);
+ if (rv != 0) {
+ goto fail;
+ }
+
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+ sdhci_start_slot(&sc->slot);
+
+ return (0);
+
+fail:
+ if (sc->gpio_cd != NULL)
+ gpio_pin_release(sc->gpio_cd);
+ if (sc->gpio_wp != NULL)
+ gpio_pin_release(sc->gpio_wp);
+ if (sc->gpio_power != NULL)
+ gpio_pin_release(sc->gpio_power);
+ if (sc->clk != NULL)
+ clk_release(sc->clk);
+ if (sc->reset != NULL)
+ hwreset_release(sc->reset);
+ if (sc->intr_cookie != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (rv);
+}
+
+static int
+tegra_sdhci_detach(device_t dev)
+{
+ struct tegra_sdhci_softc *sc = device_get_softc(dev);
+ struct sdhci_slot *slot = &sc->slot;
+
+ bus_generic_detach(dev);
+ clk_release(sc->clk);
+ bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
+ bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
+ sc->irq_res);
+
+ sdhci_cleanup_slot(slot);
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem_res),
+ sc->mem_res);
+ return (0);
+}
+
+static device_method_t tegra_sdhci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_sdhci_probe),
+ DEVMETHOD(device_attach, tegra_sdhci_attach),
+ DEVMETHOD(device_detach, tegra_sdhci_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar),
+ DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar),
+
+ /* MMC bridge interface */
+ DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
+ DEVMETHOD(mmcbr_request, sdhci_generic_request),
+ DEVMETHOD(mmcbr_get_ro, tegra_generic_get_ro),
+ DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
+ DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
+
+ /* SDHCI registers accessors */
+ DEVMETHOD(sdhci_read_1, tegra_sdhci_read_1),
+ DEVMETHOD(sdhci_read_2, tegra_sdhci_read_2),
+ DEVMETHOD(sdhci_read_4, tegra_sdhci_read_4),
+ DEVMETHOD(sdhci_read_multi_4, tegra_sdhci_read_multi_4),
+ DEVMETHOD(sdhci_write_1, tegra_sdhci_write_1),
+ DEVMETHOD(sdhci_write_2, tegra_sdhci_write_2),
+ DEVMETHOD(sdhci_write_4, tegra_sdhci_write_4),
+ DEVMETHOD(sdhci_write_multi_4, tegra_sdhci_write_multi_4),
+
+ { 0, 0 }
+};
+
+static devclass_t tegra_sdhci_devclass;
+
+static driver_t tegra_sdhci_driver = {
+ "sdhci_tegra",
+ tegra_sdhci_methods,
+ sizeof(struct tegra_sdhci_softc),
+};
+
+DRIVER_MODULE(sdhci_tegra, simplebus, tegra_sdhci_driver, tegra_sdhci_devclass,
+ 0, 0);
+MODULE_DEPEND(sdhci_tegra, sdhci, 1, 1, 1);
+DRIVER_MODULE(mmc, sdhci_tegra, mmc_driver, mmc_devclass, NULL, NULL);
diff --git a/sys/arm/nvidia/tegra_soctherm.c b/sys/arm/nvidia/tegra_soctherm.c
new file mode 100644
index 0000000..3102173
--- /dev/null
+++ b/sys/arm/nvidia/tegra_soctherm.c
@@ -0,0 +1,696 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Thermometer and thermal zones driver for Tegra SoCs.
+ * Calibration data and algo are taken from Linux, because this part of SoC
+ * is undocumented in TRM.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/nvidia/tegra_efuse.h>
+#include <gnu/dts/include/dt-bindings/thermal/tegra124-soctherm.h>
+#include "tegra_soctherm_if.h"
+
+/* Per sensors registers - base is 0x0c0*/
+#define TSENSOR_CONFIG0 0x000
+#define TSENSOR_CONFIG0_TALL(x) (((x) & 0xFFFFF) << 8)
+#define TSENSOR_CONFIG0_STATUS_CLR (1 << 5)
+#define TSENSOR_CONFIG0_TCALC_OVERFLOW (1 << 4)
+#define TSENSOR_CONFIG0_OVERFLOW (1 << 3)
+#define TSENSOR_CONFIG0_CPTR_OVERFLOW (1 << 2)
+#define TSENSOR_CONFIG0_RO_SEL (1 << 1)
+#define TSENSOR_CONFIG0_STOP (1 << 0)
+
+#define TSENSOR_CONFIG1 0x004
+#define TSENSOR_CONFIG1_TEMP_ENABLE (1U << 31)
+#define TSENSOR_CONFIG1_TEN_COUNT(x) (((x) & 0x3F) << 24)
+#define TSENSOR_CONFIG1_TIDDQ_EN(x) (((x) & 0x3F) << 15)
+#define TSENSOR_CONFIG1_TSAMPLE(x) (((x) & 0x3FF) << 0)
+
+#define TSENSOR_CONFIG2 0x008
+#define TSENSOR_CONFIG2_THERMA(x) (((x) & 0xFFFF) << 16)
+#define TSENSOR_CONFIG2_THERMB(x) (((x) & 0xFFFF) << 0)
+
+#define TSENSOR_STATUS0 0x00c
+#define TSENSOR_STATUS0_CAPTURE_VALID (1U << 31)
+#define TSENSOR_STATUS0_CAPTURE(x) (((x) >> 0) & 0xffff)
+
+#define TSENSOR_STATUS1 0x010
+#define TSENSOR_STATUS1_TEMP_VALID (1U << 31)
+#define TSENSOR_STATUS1_TEMP(x) (((x) >> 0) & 0xffff)
+
+#define TSENSOR_STATUS2 0x014
+#define TSENSOR_STATUS2_TEMP_MAX(x) (((x) >> 16) & 0xffff)
+#define TSENSOR_STATUS2_TEMP_MIN(x) (((x) >> 0) & 0xffff)
+
+/* Global registers */
+#define TSENSOR_PDIV 0x1c0
+#define TSENSOR_PDIV_T124 0x8888
+#define TSENSOR_HOTSPOT_OFF 0x1c4
+#define TSENSOR_HOTSPOT_OFF_T124 0x00060600
+#define TSENSOR_TEMP1 0x1c8
+#define TSENSOR_TEMP2 0x1cc
+
+/* Readbacks */
+#define READBACK_VALUE_MASK 0xff00
+#define READBACK_VALUE_SHIFT 8
+#define READBACK_ADD_HALF (1 << 7)
+#define READBACK_NEGATE (1 << 0)
+
+
+/* Fuses */
+#define FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT 0
+#define FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS 13
+#define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
+#define FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS 13
+
+#define FUSE_TSENSOR8_CALIB 0x180
+#define FUSE_TSENSOR8_CALIB_CP_TS_BASE(x) (((x) >> 0) & 0x3ff)
+#define FUSE_TSENSOR8_CALIB_FT_TS_BASE(x) (((x) >> 10) & 0x7ff)
+
+#define FUSE_SPARE_REALIGNMENT_REG 0x1fc
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT 0
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS 6
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 21
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS 5
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP(x) (((x) >> 0) & 0x3f)
+#define FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT(x) (((x) >> 21) & 0x1f)
+
+
+#define NOMINAL_CALIB_FT_T124 105
+#define NOMINAL_CALIB_CP_T124 25
+
+#define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
+#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
+
+static struct sysctl_ctx_list soctherm_sysctl_ctx;
+
+struct soctherm_shared_cal {
+ uint32_t base_cp;
+ uint32_t base_ft;
+ int32_t actual_temp_cp;
+ int32_t actual_temp_ft;
+};
+struct tsensor_cfg {
+ uint32_t tall;
+ uint32_t tsample;
+ uint32_t tiddq_en;
+ uint32_t ten_count;
+ uint32_t pdiv;
+ uint32_t tsample_ate;
+ uint32_t pdiv_ate;
+};
+
+struct tsensor {
+ char *name;
+ int id;
+ struct tsensor_cfg *cfg;
+ bus_addr_t sensor_base;
+ bus_addr_t calib_fuse;
+ int fuse_corr_alpha;
+ int fuse_corr_beta;
+
+ int16_t therm_a;
+ int16_t therm_b;
+};
+
+struct soctherm_softc {
+ device_t dev;
+ struct resource *mem_res;
+ struct resource *irq_res;
+ void *irq_ih;
+
+ clk_t tsensor_clk;
+ clk_t soctherm_clk;
+ hwreset_t reset;
+
+ int ntsensors;
+ struct tsensor *tsensors;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-soctherm", 1},
+ {NULL, 0},
+};
+
+static struct tsensor_cfg t124_tsensor_config = {
+ .tall = 16300,
+ .tsample = 120,
+ .tiddq_en = 1,
+ .ten_count = 1,
+ .pdiv = 8,
+ .tsample_ate = 480,
+ .pdiv_ate = 8
+};
+
+
+static struct tsensor t124_tsensors[] = {
+ {
+ .name = "cpu0",
+ .id = TEGRA124_SOCTHERM_SENSOR_CPU,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x0c0,
+ .calib_fuse = 0x098,
+ .fuse_corr_alpha = 1135400,
+ .fuse_corr_beta = -6266900,
+ },
+ {
+ .name = "cpu1",
+ .id = -1,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x0e0,
+ .calib_fuse = 0x084,
+ .fuse_corr_alpha = 1122220,
+ .fuse_corr_beta = -5700700,
+ },
+ {
+ .name = "cpu2",
+ .id = -1,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x100,
+ .calib_fuse = 0x088,
+ .fuse_corr_alpha = 1127000,
+ .fuse_corr_beta = -6768200,
+ },
+ {
+ .name = "cpu3",
+ .id = -1,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x120,
+ .calib_fuse = 0x12c,
+ .fuse_corr_alpha = 1110900,
+ .fuse_corr_beta = -6232000,
+ },
+ {
+ .name = "mem0",
+ .id = TEGRA124_SOCTHERM_SENSOR_MEM,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x140,
+ .calib_fuse = 0x158,
+ .fuse_corr_alpha = 1122300,
+ .fuse_corr_beta = -5936400,
+ },
+ {
+ .name = "mem1",
+ .id = -1,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x160,
+ .calib_fuse = 0x15c,
+ .fuse_corr_alpha = 1145700,
+ .fuse_corr_beta = -7124600,
+ },
+ {
+ .name = "gpu",
+ .id = TEGRA124_SOCTHERM_SENSOR_GPU,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x180,
+ .calib_fuse = 0x154,
+ .fuse_corr_alpha = 1120100,
+ .fuse_corr_beta = -6000500,
+ },
+ {
+ .name = "pllX",
+ .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
+ .cfg = &t124_tsensor_config,
+ .sensor_base = 0x1a0,
+ .calib_fuse = 0x160,
+ .fuse_corr_alpha = 1106500,
+ .fuse_corr_beta = -6729300,
+ },
+};
+
+/* Extract signed integer bitfield from register */
+static int
+extract_signed(uint32_t reg, int shift, int bits)
+{
+ int32_t val;
+ uint32_t mask;
+
+ mask = (1 << bits) - 1;
+ val = ((reg >> shift) & mask) << (32 - bits);
+ val >>= 32 - bits;
+ return ((int32_t)val);
+}
+
+static inline int64_t div64_s64_precise(int64_t a, int64_t b)
+{
+ int64_t r, al;
+
+ al = a << 16;
+ r = (al * 2 + 1) / (2 * b);
+ return r >> 16;
+}
+
+static void
+get_shared_cal(struct soctherm_softc *sc, struct soctherm_shared_cal *cal)
+{
+ uint32_t val;
+ int calib_cp, calib_ft;
+
+ val = tegra_fuse_read_4(FUSE_TSENSOR8_CALIB);
+ cal->base_cp = FUSE_TSENSOR8_CALIB_CP_TS_BASE(val);
+ cal->base_ft = FUSE_TSENSOR8_CALIB_FT_TS_BASE(val);
+
+ val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
+ calib_ft = extract_signed(val,
+ FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT,
+ FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS);
+ calib_cp = extract_signed(val,
+ FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
+ FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
+
+ cal->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + calib_cp;
+ cal->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + calib_ft;
+#ifdef DEBUG
+ printf("%s: base_cp: %u, base_ft: %d,"
+ " actual_temp_cp: %d, actual_temp_ft: %d\n",
+ __func__, cal->base_cp, cal->base_ft,
+ cal->actual_temp_cp, cal->actual_temp_ft);
+#endif
+}
+
+
+static void
+tsensor_calibration(struct tsensor *sensor, struct soctherm_shared_cal *shared)
+{
+ uint32_t val;
+ int mult, div, calib_cp, calib_ft;
+ int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
+ int temp_a, temp_b;
+ int64_t tmp;
+
+ val = tegra_fuse_read_4(sensor->calib_fuse);
+ calib_cp = extract_signed(val,
+ FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
+ FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
+ actual_tsensor_cp = shared->base_cp * 64 + calib_cp;
+
+ calib_ft = extract_signed(val,
+ FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
+ FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
+ actual_tsensor_ft = shared->base_ft * 32 + calib_ft;
+
+ delta_sens = actual_tsensor_ft - actual_tsensor_cp;
+ delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
+ mult = sensor->cfg->pdiv * sensor->cfg->tsample_ate;
+ div = sensor->cfg->tsample * sensor->cfg->pdiv_ate;
+
+
+ temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
+ (int64_t) delta_sens * div);
+
+ tmp = (int64_t)actual_tsensor_ft * shared->actual_temp_cp -
+ (int64_t)actual_tsensor_cp * shared->actual_temp_ft;
+ temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
+
+ temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
+ 1000000);
+ temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
+ sensor->fuse_corr_beta, 1000000);
+ sensor->therm_a = (int16_t)temp_a;
+ sensor->therm_b = (int16_t)temp_b;
+#ifdef DEBUG
+ printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
+ " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
+ __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
+ calib_cp, calib_cp, calib_ft, calib_ft);
+ printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
+ (uint16_t)sensor->therm_a, temp_a,
+ (uint16_t)sensor->therm_b, sensor->therm_b);
+#endif
+}
+
+static void
+soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor,
+ struct soctherm_shared_cal *shared_cal)
+{
+ uint32_t val;
+
+ tsensor_calibration(sensor, shared_cal);
+
+ val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
+ val |= TSENSOR_CONFIG0_STOP;
+ val |= TSENSOR_CONFIG0_STATUS_CLR;
+ WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
+
+ val = TSENSOR_CONFIG0_TALL(sensor->cfg->tall);
+ val |= TSENSOR_CONFIG0_STOP;
+ WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
+
+ val = TSENSOR_CONFIG1_TSAMPLE(sensor->cfg->tsample - 1);
+ val |= TSENSOR_CONFIG1_TIDDQ_EN(sensor->cfg->tiddq_en);
+ val |= TSENSOR_CONFIG1_TEN_COUNT(sensor->cfg->ten_count);
+ val |= TSENSOR_CONFIG1_TEMP_ENABLE;
+ WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
+
+ val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
+ TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
+ WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
+
+ val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
+ val &= ~TSENSOR_CONFIG0_STOP;
+ WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
+#ifdef DEBUG
+ printf(" Sensor: %s cfg:0x%08X, 0x%08X, 0x%08X,"
+ " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
+ );
+#endif
+}
+
+static int
+soctherm_convert_raw(uint32_t val)
+{
+ int32_t t;
+
+ t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
+ if (val & READBACK_ADD_HALF)
+ t += 500;
+ if (val & READBACK_NEGATE)
+ t *= -1;
+
+ return t;
+}
+
+static int
+soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
+{
+ int timeout;
+ uint32_t val;
+
+
+ /* wait for valid sample */
+ for (timeout = 1000; timeout > 0; timeout--) {
+ val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
+ if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
+ break;
+ DELAY(100);
+ }
+ if (timeout <= 0)
+ device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
+ *temp = soctherm_convert_raw(val);
+#ifdef DEBUG
+ printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
+ printf(" Sensor: %s cfg:0x%08X, 0x%08X, 0x%08X,"
+ " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
+ RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
+ RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
+ );
+#endif
+ return 0;
+}
+
+static int
+soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
+{
+ struct soctherm_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+ /* The direct sensor map starts at 0x100 */
+ if (id >= 0x100) {
+ id -= 0x100;
+ if (id >= sc->ntsensors)
+ return (ERANGE);
+ return(soctherm_read_temp(sc, sc->tsensors + id, val));
+ }
+ /* Linux (DT) compatible thermal zones */
+ for (i = 0; i < sc->ntsensors; i++) {
+ if (sc->tsensors->id == id)
+ return(soctherm_read_temp(sc, sc->tsensors + id, val));
+ }
+ return (ERANGE);
+}
+
+static int
+soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
+{
+ struct soctherm_softc *sc;
+ int val;
+ int rv;
+ int id;
+
+ /* Write request */
+ if (req->newptr != NULL)
+ return (EINVAL);
+
+ sc = arg1;
+ id = arg2;
+
+ if (id >= sc->ntsensors)
+ return (ERANGE);
+ rv = soctherm_read_temp(sc, sc->tsensors + id, &val);
+ if (rv != 0)
+ return (rv);
+
+ val = val / 100;
+ val += 2731;
+ rv = sysctl_handle_int(oidp, &val, 0, req);
+ return (rv);
+}
+
+static int
+soctherm_init_sysctl(struct soctherm_softc *sc)
+{
+ int i;
+ struct sysctl_oid *oid, *tmp;
+
+ sysctl_ctx_init(&soctherm_sysctl_ctx);
+ /* create node for hw.temp */
+ oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
+ CTLFLAG_RD, NULL, "");
+ if (oid == NULL)
+ return (ENXIO);
+
+ /* Add sensors */
+ for (i = sc->ntsensors - 1; i >= 0; i--) {
+ tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
+ SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
+ CTLTYPE_INT | CTLFLAG_RD, sc, i,
+ soctherm_sysctl_temperature, "IK", "SoC Temperature");
+ if (tmp == NULL)
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+soctherm_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Tegra temperature sensors");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+soctherm_attach(device_t dev)
+{
+ struct soctherm_softc *sc;
+ phandle_t node;
+ int i, rid, rv;
+ struct soctherm_shared_cal shared_calib;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(sc->dev);
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ goto fail;
+ }
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "Cannot allocate IRQ resources\n");
+ goto fail;
+ }
+
+/*
+ if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
+ soctherm_intr, NULL, sc, &sc->irq_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ goto fail;
+ }
+*/
+
+ /* OWF resources */
+ rv = hwreset_get_by_ofw_name(dev, "soctherm", &sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get fuse reset\n");
+ goto fail;
+ }
+ rv = clk_get_by_ofw_name(dev, "tsensor", &sc->tsensor_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
+ goto fail;
+ }
+ rv = clk_get_by_ofw_name(dev, "soctherm", &sc->soctherm_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
+ goto fail;
+ }
+
+ rv = hwreset_assert(sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot assert reset\n");
+ goto fail;
+ }
+ rv = clk_enable(sc->tsensor_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
+ goto fail;
+ }
+ rv = clk_enable(sc->soctherm_clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
+ goto fail;
+ }
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot clear reset\n");
+ goto fail;
+ }
+
+ /* Tegra 124 */
+ sc->tsensors = t124_tsensors;
+ sc->ntsensors = nitems(t124_tsensors);
+ get_shared_cal(sc, &shared_calib);
+
+ WR4(sc, TSENSOR_PDIV, TSENSOR_PDIV_T124);
+ WR4(sc, TSENSOR_HOTSPOT_OFF, TSENSOR_HOTSPOT_OFF_T124);
+
+ for (i = 0; i < sc->ntsensors; i++)
+ soctherm_init_tsensor(sc, sc->tsensors + i, &shared_calib);
+
+ rv = soctherm_init_sysctl(sc);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot initialize sysctls\n");
+ goto fail;
+ }
+
+ OF_device_register_xref(OF_xref_from_node(node), dev);
+ return (bus_generic_attach(dev));
+
+fail:
+ if (sc->irq_ih != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
+ sysctl_ctx_free(&soctherm_sysctl_ctx);
+ if (sc->tsensor_clk != NULL)
+ clk_release(sc->tsensor_clk);
+ if (sc->soctherm_clk != NULL)
+ clk_release(sc->soctherm_clk);
+ if (sc->reset != NULL)
+ hwreset_release(sc->reset);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (ENXIO);
+}
+
+static int
+soctherm_detach(device_t dev)
+{
+ struct soctherm_softc *sc;
+ sc = device_get_softc(dev);
+
+ if (sc->irq_ih != NULL)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
+ sysctl_ctx_free(&soctherm_sysctl_ctx);
+ if (sc->tsensor_clk != NULL)
+ clk_release(sc->tsensor_clk);
+ if (sc->soctherm_clk != NULL)
+ clk_release(sc->soctherm_clk);
+ if (sc->reset != NULL)
+ hwreset_release(sc->reset);
+ if (sc->irq_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+ return (ENXIO);
+}
+
+static device_method_t tegra_soctherm_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, soctherm_probe),
+ DEVMETHOD(device_attach, soctherm_attach),
+ DEVMETHOD(device_detach, soctherm_detach),
+
+ /* SOCTHERM interface */
+ DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
+
+ DEVMETHOD_END
+};
+
+static devclass_t tegra_soctherm_devclass;
+DEFINE_CLASS_0(tegra_soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
+ sizeof(struct soctherm_softc));
+EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
+tegra_soctherm_devclass, 0, 0, 79);
diff --git a/sys/arm/nvidia/tegra_soctherm_if.m b/sys/arm/nvidia/tegra_soctherm_if.m
new file mode 100644
index 0000000..55ae044
--- /dev/null
+++ b/sys/arm/nvidia/tegra_soctherm_if.m
@@ -0,0 +1,42 @@
+#-
+# Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#include <machine/bus.h>
+
+INTERFACE tegra_soctherm;
+
+
+/**
+ * Read temperature
+ */
+METHOD int get_temperature{
+ device_t dev;
+ device_t consumer;
+ uintptr_t id;
+ int *val;
+};
diff --git a/sys/arm/nvidia/tegra_uart.c b/sys/arm/nvidia/tegra_uart.c
new file mode 100644
index 0000000..86972f0
--- /dev/null
+++ b/sys/arm/nvidia/tegra_uart.c
@@ -0,0 +1,251 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * UART driver for Tegra SoCs.
+ */
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_cpu_fdt.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_ns8250.h>
+#include <dev/ic/ns16550.h>
+
+#include "uart_if.h"
+
+/*
+ * High-level UART interface.
+ */
+struct tegra_softc {
+ struct ns8250_softc ns8250_base;
+ clk_t clk;
+ hwreset_t reset;
+};
+
+/*
+ * UART class interface.
+ */
+static int
+tegra_uart_attach(struct uart_softc *sc)
+{
+ int rv;
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas = &sc->sc_bas;
+
+ rv = ns8250_bus_attach(sc);
+ if (rv != 0)
+ return (rv);
+
+ ns8250->ier_rxbits = 0x1d;
+ ns8250->ier_mask = 0xc0;
+ ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask;
+ ns8250->ier |= ns8250->ier_rxbits;
+ uart_setreg(bas, REG_IER, ns8250->ier);
+ uart_barrier(bas);
+ return (0);
+}
+
+static void
+tegra_uart_grab(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ u_char ier;
+
+ /*
+ * turn off all interrupts to enter polling mode. Leave the
+ * saved mask alone. We'll restore whatever it was in ungrab.
+ * All pending interrupt signals are reset when IER is set to 0.
+ */
+ uart_lock(sc->sc_hwmtx);
+ ier = uart_getreg(bas, REG_IER);
+ uart_setreg(bas, REG_IER, ier & ns8250->ier_mask);
+ uart_setreg(bas, REG_FCR, 0);
+ uart_barrier(bas);
+ uart_unlock(sc->sc_hwmtx);
+}
+
+static void
+tegra_uart_ungrab(struct uart_softc *sc)
+{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+ struct uart_bas *bas = &sc->sc_bas;
+
+ /*
+ * Restore previous interrupt mask
+ */
+ uart_lock(sc->sc_hwmtx);
+ uart_setreg(bas, REG_FCR, ns8250->fcr);
+ uart_setreg(bas, REG_IER, ns8250->ier);
+ uart_barrier(bas);
+ uart_unlock(sc->sc_hwmtx);
+}
+
+static kobj_method_t tegra_methods[] = {
+ KOBJMETHOD(uart_probe, ns8250_bus_probe),
+ KOBJMETHOD(uart_attach, tegra_uart_attach),
+ KOBJMETHOD(uart_detach, ns8250_bus_detach),
+ KOBJMETHOD(uart_flush, ns8250_bus_flush),
+ KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
+ KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl),
+ KOBJMETHOD(uart_ipend, ns8250_bus_ipend),
+ KOBJMETHOD(uart_param, ns8250_bus_param),
+ KOBJMETHOD(uart_receive, ns8250_bus_receive),
+ KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
+ KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_grab, tegra_uart_grab),
+ KOBJMETHOD(uart_ungrab, tegra_uart_ungrab),
+ KOBJMETHOD_END
+};
+
+static struct uart_class tegra_uart_class = {
+ "tegra class",
+ tegra_methods,
+ sizeof(struct tegra_softc),
+ .uc_ops = &uart_ns8250_ops,
+ .uc_range = 8,
+ .uc_rclk = 0,
+};
+
+/* Compatible devices. */
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra124-uart", (uintptr_t)&tegra_uart_class},
+ {NULL, (uintptr_t)NULL},
+};
+
+UART_FDT_CLASS(compat_data);
+
+/*
+ * UART Driver interface.
+ */
+static int
+uart_fdt_get_shift1(phandle_t node)
+{
+ pcell_t shift;
+
+ if ((OF_getencprop(node, "reg-shift", &shift, sizeof(shift))) <= 0)
+ shift = 2;
+ return ((int)shift);
+}
+
+static int
+tegra_uart_probe(device_t dev)
+{
+ struct tegra_softc *sc;
+ phandle_t node;
+ uint64_t freq;
+ int shift;
+ int rv;
+ const struct ofw_compat_data *cd;
+
+ sc = device_get_softc(dev);
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ cd = ofw_bus_search_compatible(dev, compat_data);
+ if (cd->ocd_data == 0)
+ return (ENXIO);
+ sc->ns8250_base.base.sc_class = (struct uart_class *)cd->ocd_data;
+
+ rv = hwreset_get_by_ofw_name(dev, "serial", &sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'serial' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_deassert(sc->reset);
+ if (rv != 0) {
+ device_printf(dev, "Cannot unreset 'serial' reset\n");
+ return (ENXIO);
+ }
+
+ node = ofw_bus_get_node(dev);
+ shift = uart_fdt_get_shift1(node);
+ rv = clk_get_by_ofw_index(dev, 0, &sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get UART clock: %d\n", rv);
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable UART clock: %d\n", rv);
+ return (ENXIO);
+ }
+ rv = clk_get_freq(sc->clk, &freq);
+ if (rv != 0) {
+ device_printf(dev, "Cannot enable UART clock: %d\n", rv);
+ return (ENXIO);
+ }
+ return (uart_bus_probe(dev, shift, (int)freq, 0, 0));
+}
+
+static int
+tegra_uart_detach(device_t dev)
+{
+ struct tegra_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->clk != NULL) {
+ clk_release(sc->clk);
+ }
+
+ return (uart_bus_detach(dev));
+}
+
+static device_method_t tegra_uart_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, tegra_uart_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, tegra_uart_detach),
+ { 0, 0 }
+};
+
+static driver_t tegra_uart_driver = {
+ uart_driver_name,
+ tegra_uart_bus_methods,
+ sizeof(struct tegra_softc),
+};
+
+DRIVER_MODULE(tegra_uart, simplebus, tegra_uart_driver, uart_devclass,
+ 0, 0); \ No newline at end of file
diff --git a/sys/arm/nvidia/tegra_usbphy.c b/sys/arm/nvidia/tegra_usbphy.c
new file mode 100644
index 0000000..40c0714
--- /dev/null
+++ b/sys/arm/nvidia/tegra_usbphy.c
@@ -0,0 +1,839 @@
+/*-
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+
+/*
+ * USB phy driver for Tegra SoCs.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/phy/phy.h>
+#include <dev/extres/regulator/regulator.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_pinctrl.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "phy_if.h"
+
+#define CTRL_ICUSB_CTRL 0x15c
+#define ICUSB_CTR_IC_ENB1 (1 << 3)
+
+#define CTRL_USB_USBMODE 0x1f8
+#define USB_USBMODE_MASK (3 << 0)
+#define USB_USBMODE_HOST (3 << 0)
+#define USB_USBMODE_DEVICE (2 << 0)
+
+#define CTRL_USB_HOSTPC1_DEVLC 0x1b4
+#define USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
+#define USB_HOSTPC1_DEVLC_STS (1 << 28)
+#define USB_HOSTPC1_DEVLC_PHCD (1 << 22)
+
+
+#define IF_USB_SUSP_CTRL 0x400
+#define FAST_WAKEUP_RESP (1 << 26)
+#define UTMIP_SUSPL1_SET (1 << 25)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+#define USB_SUSP_SET (1 << 14)
+#define UTMIP_PHY_ENB (1 << 12)
+#define UTMIP_RESET (1 << 11)
+#define USB_SUSP_POL (1 << 10)
+#define USB_PHY_CLK_VALID_INT_ENB (1 << 9)
+#define USB_PHY_CLK_VALID_INT_STS (1 << 8)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define USB_CLKEN (1 << 6)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_RESUME_EN (1 << 2)
+#define USB_WAKEUP_INT_ENB (1 << 1)
+#define USB_WAKEUP_INT_STS (1 << 0)
+
+#define IF_USB_PHY_VBUS_SENSORS 0x404
+#define B_SESS_END_SW_VALUE (1 << 4)
+#define B_SESS_END_SW_EN (1 << 3)
+
+
+#define UTMIP_XCVR_CFG0 0x808
+#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25)
+#define UTMIP_XCVR_SETUP_MSB(x) ((((x) & 0x70) >> 4) << 22)
+#define UTMIP_XCVR_LSBIAS_SEL (1 << 21)
+#define UTMIP_XCVR_DISCON_METHOD (1 << 20)
+#define UTMIP_FORCE_PDZI_POWERUP (1 << 19)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_FORCE_PD2_POWERUP (1 << 17)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PD_POWERUP (1 << 15)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_XCVR_TERMEN (1 << 13)
+#define UTMIP_XCVR_HSLOOPBACK (1 << 12)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_FSSLEW(x) (((x) & 0x3) << 6)
+#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4)
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+
+#define UTMIP_BIAS_CFG0 0x80C
+#define UTMIP_IDDIG_C_VAL (1 << 30)
+#define UTMIP_IDDIG_C_SEL (1 << 29)
+#define UTMIP_IDDIG_B_VAL (1 << 28)
+#define UTMIP_IDDIG_B_SEL (1 << 27)
+#define UTMIP_IDDIG_A_VAL (1 << 26)
+#define UTMIP_IDDIG_A_SEL (1 << 25)
+#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24)
+#define UTMIP_IDPD_VAL (1 << 23)
+#define UTMIP_IDPD_SEL (1 << 22)
+#define UTMIP_IDDIG_VAL (1 << 21)
+#define UTMIP_IDDIG_SEL (1 << 20)
+#define UTMIP_GPI_VAL (1 << 19)
+#define UTMIP_GPI_SEL (1 << 18)
+#define UTMIP_ACTIVE_TERM_OFFSET(x) (((x) & 0x7) << 15)
+#define UTMIP_ACTIVE_PULLUP_OFFSET(x) (((x) & 0x7) << 12)
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+#define UTMIP_VBUS_LEVEL_LEVEL(x) (((x) & 0x3) << 8)
+#define UTMIP_SESS_LEVEL_LEVEL(x) (((x) & 0x3) << 6)
+#define UTMIP_HSCHIRP_LEVEL(x) (((x) & 0x3) << 4)
+#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2)
+#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0)
+
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_KEEP_PATT_ON_ACTIVE(x) (((x) & 0x3) << 30)
+#define UTMIP_ALLOW_CONSEC_UPDN (1 << 29)
+#define UTMIP_REALIGN_ON_NEW_PKT (1 << 28)
+#define UTMIP_PCOUNT_UPDN_DIV(x) (((x) & 0xf) << 24)
+#define UTMIP_SQUELCH_EOP_DLY(x) (((x) & 0x7) << 21)
+#define UTMIP_NO_STRIPPING (1 << 20)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_ELASTIC_OVERRUN_DISABLE (1 << 9)
+#define UTMIP_ELASTIC_UNDERRUN_DISABLE (1 << 8)
+#define UTMIP_PASS_CHIRP (1 << 7)
+#define UTMIP_PASS_FEEDBACK (1 << 6)
+#define UTMIP_PCOUNT_INERTIA(x) (((x) & 0x3) << 4)
+#define UTMIP_PHASE_ADJUST(x) (((x) & 0x3) << 2)
+#define UTMIP_THREE_SYNCBITS (1 << 1)
+#define UTMIP_USE4SYNC_TRAN (1 << 0)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1F) << 1)
+#define UTMIP_HS_ALLOW_KEEP_ALIVE (1 << 0)
+
+#define UTMIP_TX_CFG0 0x820
+#define UTMIP_FS_PREAMBLE_J (1 << 19)
+#define UTMIP_FS_POSTAMBLE_OUTPUT_ENABLE (1 << 18)
+#define UTMIP_FS_PREAMBLE_OUTPUT_ENABLE (1 << 17)
+#define UTMIP_FSLS_ALLOW_SOP_TX_STUFF_ERR (1 << 16)
+#define UTMIP_HS_READY_WAIT_FOR_VALID (1 << 15)
+#define UTMIP_HS_TX_IPG_DLY(x) (((x) & 0x1f) << 10)
+#define UTMIP_HS_DISCON_EOP_ONLY (1 << 9)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+#define UTMIP_HS_POSTAMBLE_OUTPUT_ENABLE (1 << 7)
+#define UTMIP_HS_PREAMBLE_OUTPUT_ENABLE (1 << 6)
+#define UTMIP_SIE_RESUME_ON_LINESTATE (1 << 5)
+#define UTMIP_SOF_ON_NO_STUFF (1 << 4)
+#define UTMIP_SOF_ON_NO_ENCODE (1 << 3)
+#define UTMIP_NO_STUFFING (1 << 2)
+#define UTMIP_NO_ENCODING (1 << 1)
+#define UTMIP_NO_SYNC_NO_EOP (1 << 0)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_KEEP_XCVR_PD_ON_SOFT_DISCON (1 << 25)
+#define UTMIP_ALLOW_LS_ON_SOFT_DISCON (1 << 24)
+#define UTMIP_FORCE_FS_DISABLE_ON_DEV_CHIRP (1 << 23)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+#define UTMIP_LS_TO_FS_SKIP_4MS (1 << 21)
+#define UTMIP_INJECT_ERROR_TYPE(x) (((x) & 0x3) << 19)
+#define UTMIP_FORCE_HS_CLOCK_ON (1 << 18)
+#define UTMIP_DISABLE_HS_TERM (1 << 17)
+#define UTMIP_FORCE_HS_TERM (1 << 16)
+#define UTMIP_DISABLE_PULLUP_DP (1 << 15)
+#define UTMIP_DISABLE_PULLUP_DM (1 << 14)
+#define UTMIP_DISABLE_PULLDN_DP (1 << 13)
+#define UTMIP_DISABLE_PULLDN_DM (1 << 12)
+#define UTMIP_FORCE_PULLUP_DP (1 << 11)
+#define UTMIP_FORCE_PULLUP_DM (1 << 10)
+#define UTMIP_FORCE_PULLDN_DP (1 << 9)
+#define UTMIP_FORCE_PULLDN_DM (1 << 8)
+#define UTMIP_STABLE_COUNT(x) (((x) & 0x7) << 5)
+#define UTMIP_STABLE_ALL (1 << 4)
+#define UTMIP_NO_FREE_ON_SUSPEND (1 << 3)
+#define UTMIP_NEVER_FREE_RUNNING_TERMS (1 << 2)
+#define UTMIP_ALWAYS_FREE_RUNNING_TERMS (1 << 1)
+#define UTMIP_COMB_TERMS (1 << 0)
+
+#define UTMIP_MISC_CFG1 0x828
+#define UTMIP_PHY_XTAL_CLOCKEN (1 << 30)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82C
+#define UTMIP_BIAS_DEBOUNCE_B(x) (((x) & 0xffff) << 16)
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_CHRG_DEBOUNCE_TIMESCALE(x) (((x) & 0x1f) << 8)
+#define UTMIP_OP_I_SRC_ENG (1 << 5)
+#define UTMIP_ON_SRC_ENG (1 << 4)
+#define UTMIP_OP_SRC_ENG (1 << 3)
+#define UTMIP_ON_SINK_ENG (1 << 2)
+#define UTMIP_OP_SINK_ENG (1 << 1)
+#define UTMIP_PD_CHRG (1 << 0)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_HS_IREF_CAP_CFG (1 << 7)
+#define FUSE_HS_SQUELCH_LEVEL (1 << 6)
+#define FUSE_SPARE (1 << 5)
+#define FUSE_TERM_RANGE_ADJ_SEL (1 << 4)
+#define FUSE_SETUP_SEL (1 << 3)
+#define HS_RX_LATE_SQUELCH (1 << 2)
+#define HS_RX_FLUSH_ALAP (1 << 1)
+#define HS_RX_IPG_ERROR_ENABLE (1 << 0)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_XCVR_RPU_RANGE_ADJ(x) (((x) & 0x3) << 26)
+#define UTMIP_XCVR_HS_IREF_CAP(x) (((x) & 0x3) << 24)
+#define UTMIP_XCVR_SPARE(x) (((x) & 0x3) << 22)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+#define UTMIP_RCTRL_SW_SET (1 << 17)
+#define UTMIP_RCTRL_SW_VAL(x) (((x) & 0x1f) << 12)
+#define UTMIP_TCTRL_SW_SET (1 << 11)
+#define UTMIP_TCTRL_SW_VAL(x) (((x) & 0x1f) << 6)
+#define UTMIP_FORCE_PDDR_POWERUP (1 << 5)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_FORCE_PDCHRP_POWERUP (1 << 3)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDISC_POWERUP (1 << 1)
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_DEBOUNCE_TIMESCALE(x) (((x) & 0x3f) << 8)
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+#define UTMIP_VBUS_WAKEUP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDTRK_POWERUP (1 << 1)
+#define UTMIP_FORCE_PDTRK_POWERDOWN (1 << 0)
+
+static int usbpby_enable_cnt;
+
+enum usb_ifc_type {
+ USB_IFC_TYPE_UNKNOWN = 0,
+ USB_IFC_TYPE_UTMI,
+ USB_IFC_TYPE_ULPI
+};
+
+enum usb_dr_mode {
+ USB_DR_MODE_UNKNOWN = 0,
+ USB_DR_MODE_DEVICE,
+ USB_DR_MODE_HOST,
+ USB_DR_MODE_OTG
+};
+
+struct usbphy_softc {
+ device_t dev;
+ struct resource *mem_res;
+ struct resource *pads_res;
+ clk_t clk_reg;
+ clk_t clk_pads;
+ clk_t clk_pllu;
+ regulator_t supply_vbus;
+ hwreset_t reset_usb;
+ hwreset_t reset_pads;
+ enum usb_ifc_type ifc_type;
+ enum usb_dr_mode dr_mode;
+ bool have_utmi_regs;
+
+ /* UTMI params */
+ int hssync_start_delay;
+ int elastic_limit;
+ int idle_wait_delay;
+ int term_range_adj;
+ int xcvr_lsfslew;
+ int xcvr_lsrslew;
+ int xcvr_hsslew;
+ int hssquelch_level;
+ int hsdiscon_level;
+ int xcvr_setup;
+ int xcvr_setup_use_fuses;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"nvidia,tegra30-usb-phy", 1},
+ {NULL, 0},
+};
+
+#define RD4(sc, offs) \
+ bus_read_4(sc->mem_res, offs)
+
+#define WR4(sc, offs, val) \
+ bus_write_4(sc->mem_res, offs, val)
+
+static int
+reg_wait(struct usbphy_softc *sc, uint32_t reg, uint32_t mask, uint32_t val)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ if ((RD4(sc, reg) & mask) == val)
+ return (0);
+ DELAY(10);
+ }
+ return (ETIMEDOUT);
+}
+
+static int
+usbphy_utmi_phy_clk(struct usbphy_softc *sc, bool enable)
+{
+ uint32_t val;
+ int rv;
+
+ val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC);
+ if (enable)
+ val &= ~USB_HOSTPC1_DEVLC_PHCD;
+ else
+ val |= USB_HOSTPC1_DEVLC_PHCD;
+ WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val);
+
+ rv = reg_wait(sc, IF_USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ enable ? USB_PHY_CLK_VALID: 0);
+ if (rv != 0) {
+ device_printf(sc->dev, "USB phy clock timeout.\n");
+ return (ETIMEDOUT);
+ }
+ return (0);
+}
+
+static int
+usbphy_utmi_enable(struct usbphy_softc *sc)
+{
+ int rv;
+ uint32_t val;
+
+ /* Reset phy */
+ val = RD4(sc, IF_USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+
+
+ val = RD4(sc, UTMIP_TX_CFG0);
+ val |= UTMIP_FS_PREAMBLE_J;
+ WR4(sc, UTMIP_TX_CFG0, val);
+
+ val = RD4(sc, UTMIP_HSRX_CFG0);
+ val &= ~UTMIP_IDLE_WAIT(~0);
+ val &= ~UTMIP_ELASTIC_LIMIT(~0);
+ val |= UTMIP_IDLE_WAIT(sc->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(sc->elastic_limit);
+ WR4(sc, UTMIP_HSRX_CFG0, val);
+
+ val = RD4(sc, UTMIP_HSRX_CFG1);
+ val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+ val |= UTMIP_HS_SYNC_START_DLY(sc->hssync_start_delay);
+ WR4(sc, UTMIP_HSRX_CFG1, val);
+
+ val = RD4(sc, UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(0x7530); /* For 12MHz */
+ WR4(sc, UTMIP_DEBOUNCE_CFG0, val);
+
+ val = RD4(sc, UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ WR4(sc, UTMIP_MISC_CFG0, val);
+
+ if (sc->dr_mode == USB_DR_MODE_DEVICE) {
+ val = RD4(sc,IF_USB_SUSP_CTRL);
+ val &= ~USB_WAKE_ON_CNNT_EN_DEV;
+ val &= ~USB_WAKE_ON_DISCON_EN_DEV;
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+
+ val = RD4(sc, UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ WR4(sc, UTMIP_BAT_CHRG_CFG0, val);
+ } else {
+ val = RD4(sc, UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ WR4(sc, UTMIP_BAT_CHRG_CFG0, val);
+ }
+
+ usbpby_enable_cnt++;
+ if (usbpby_enable_cnt == 1) {
+ rv = hwreset_deassert(sc->reset_pads);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot unreset 'utmi-pads' reset\n");
+ return (rv);
+ }
+ rv = clk_enable(sc->clk_pads);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'utmi-pads' clock\n");
+ return (rv);
+ }
+
+ val = bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0);
+ val &= ~UTMIP_OTGPD;
+ val &= ~UTMIP_BIASPD;
+ val &= ~UTMIP_HSSQUELCH_LEVEL(~0);
+ val &= ~UTMIP_HSDISCON_LEVEL(~0);
+ val &= ~UTMIP_HSDISCON_LEVEL_MSB(~0);
+ val |= UTMIP_HSSQUELCH_LEVEL(sc->hssquelch_level);
+ val |= UTMIP_HSDISCON_LEVEL(sc->hsdiscon_level);
+ val |= UTMIP_HSDISCON_LEVEL_MSB(sc->hsdiscon_level);
+ bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val);
+
+ rv = clk_disable(sc->clk_pads);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot disable 'utmi-pads' clock\n");
+ return (rv);
+ }
+ }
+
+ val = RD4(sc, UTMIP_XCVR_CFG0);
+ val &= ~UTMIP_FORCE_PD_POWERDOWN;
+ val &= ~UTMIP_FORCE_PD2_POWERDOWN ;
+ val &= ~UTMIP_FORCE_PDZI_POWERDOWN;
+ val &= ~UTMIP_XCVR_LSBIAS_SEL;
+ val &= ~UTMIP_XCVR_LSFSLEW(~0);
+ val &= ~UTMIP_XCVR_LSRSLEW(~0);
+ val &= ~UTMIP_XCVR_HSSLEW(~0);
+ val &= ~UTMIP_XCVR_HSSLEW_MSB(~0);
+ val |= UTMIP_XCVR_LSFSLEW(sc->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(sc->xcvr_lsrslew);
+ val |= UTMIP_XCVR_HSSLEW(sc->xcvr_hsslew);
+ val |= UTMIP_XCVR_HSSLEW_MSB(sc->xcvr_hsslew);
+ if (!sc->xcvr_setup_use_fuses) {
+ val &= ~UTMIP_XCVR_SETUP(~0);
+ val &= ~UTMIP_XCVR_SETUP_MSB(~0);
+ val |= UTMIP_XCVR_SETUP(sc->xcvr_setup);
+ val |= UTMIP_XCVR_SETUP_MSB(sc->xcvr_setup);
+ }
+ WR4(sc, UTMIP_XCVR_CFG0, val);
+
+ val = RD4(sc, UTMIP_XCVR_CFG1);
+ val &= ~UTMIP_FORCE_PDDISC_POWERDOWN;
+ val &= ~UTMIP_FORCE_PDCHRP_POWERDOWN;
+ val &= ~UTMIP_FORCE_PDDR_POWERDOWN;
+ val &= ~UTMIP_XCVR_TERM_RANGE_ADJ(~0);
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(sc->term_range_adj);
+ WR4(sc, UTMIP_XCVR_CFG1, val);
+
+
+ val = RD4(sc, UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+ WR4(sc, UTMIP_BIAS_CFG1, val);
+
+ val = RD4(sc, UTMIP_SPARE_CFG0);
+ if (sc->xcvr_setup_use_fuses)
+ val |= FUSE_SETUP_SEL;
+ else
+ val &= ~FUSE_SETUP_SEL;
+ WR4(sc, UTMIP_SPARE_CFG0, val);
+
+ val = RD4(sc, IF_USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENB;
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+
+ val = RD4(sc, IF_USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+
+ usbphy_utmi_phy_clk(sc, true);
+
+ val = RD4(sc, CTRL_USB_USBMODE);
+ val &= ~USB_USBMODE_MASK;
+ if (sc->dr_mode == USB_DR_MODE_HOST)
+ val |= USB_USBMODE_HOST;
+ else
+ val |= USB_USBMODE_DEVICE;
+ WR4(sc, CTRL_USB_USBMODE, val);
+
+ val = RD4(sc, CTRL_USB_HOSTPC1_DEVLC);
+ val &= ~USB_HOSTPC1_DEVLC_PTS(~0);
+ val |= USB_HOSTPC1_DEVLC_PTS(0);
+ WR4(sc, CTRL_USB_HOSTPC1_DEVLC, val);
+
+ return (0);
+}
+
+static int
+usbphy_utmi_disable(struct usbphy_softc *sc)
+{
+ int rv;
+ uint32_t val;
+
+ usbphy_utmi_phy_clk(sc, false);
+
+ if (sc->dr_mode == USB_DR_MODE_DEVICE) {
+ val = RD4(sc, IF_USB_SUSP_CTRL);
+ val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+ val |= USB_WAKE_ON_CNNT_EN_DEV;
+ val |= USB_WAKEUP_DEBOUNCE_COUNT(5);
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+ }
+
+ val = RD4(sc, IF_USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ WR4(sc, IF_USB_SUSP_CTRL, val);
+
+ val = RD4(sc, UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ WR4(sc, UTMIP_BAT_CHRG_CFG0, val);
+
+ val = RD4(sc, UTMIP_XCVR_CFG0);
+ val |= UTMIP_FORCE_PD_POWERDOWN;
+ val |= UTMIP_FORCE_PD2_POWERDOWN;
+ val |= UTMIP_FORCE_PDZI_POWERDOWN;
+ WR4(sc, UTMIP_XCVR_CFG0, val);
+
+ val = RD4(sc, UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN;
+ val |= UTMIP_FORCE_PDCHRP_POWERDOWN;
+ val |= UTMIP_FORCE_PDDR_POWERDOWN;
+ WR4(sc, UTMIP_XCVR_CFG1, val);
+
+ usbpby_enable_cnt--;
+ if (usbpby_enable_cnt <= 0) {
+ rv = clk_enable(sc->clk_pads);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable 'utmi-pads' clock\n");
+ return (rv);
+ }
+ val =bus_read_4(sc->pads_res, UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD;
+ val |= UTMIP_BIASPD;
+ bus_write_4(sc->pads_res, UTMIP_BIAS_CFG0, val);
+
+ rv = clk_disable(sc->clk_pads);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot disable 'utmi-pads' clock\n");
+ return (rv);
+ }
+ }
+ return (0);
+}
+
+static int
+usbphy_phy_enable(device_t dev, int id, bool enable)
+{
+ struct usbphy_softc *sc;
+ int rv = 0;
+
+ sc = device_get_softc(dev);
+
+ if (sc->ifc_type != USB_IFC_TYPE_UTMI) {
+ device_printf(sc->dev,
+ "Only UTMI interface is supported.\n");
+ return (ENXIO);
+ }
+ if (enable)
+ rv = usbphy_utmi_enable(sc);
+ else
+ rv = usbphy_utmi_disable(sc);
+
+ return (rv);
+}
+
+static enum usb_ifc_type
+usb_get_ifc_mode(device_t dev, phandle_t node, char *name)
+{
+ char *tmpstr;
+ int rv;
+ enum usb_ifc_type ret;
+
+ rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr);
+ if (rv <= 0)
+ return (USB_IFC_TYPE_UNKNOWN);
+
+ ret = USB_IFC_TYPE_UNKNOWN;
+ if (strcmp(tmpstr, "utmi") == 0)
+ ret = USB_IFC_TYPE_UTMI;
+ else if (strcmp(tmpstr, "ulpi") == 0)
+ ret = USB_IFC_TYPE_ULPI;
+ else
+ device_printf(dev, "Unsupported phy type: %s\n", tmpstr);
+ free(tmpstr, M_OFWPROP);
+ return (ret);
+}
+
+static enum usb_dr_mode
+usb_get_dr_mode(device_t dev, phandle_t node, char *name)
+{
+ char *tmpstr;
+ int rv;
+ enum usb_dr_mode ret;
+
+ rv = OF_getprop_alloc(node, name, 1, (void **)&tmpstr);
+ if (rv <= 0)
+ return (USB_DR_MODE_UNKNOWN);
+
+ ret = USB_DR_MODE_UNKNOWN;
+ if (strcmp(tmpstr, "device") == 0)
+ ret = USB_DR_MODE_DEVICE;
+ else if (strcmp(tmpstr, "host") == 0)
+ ret = USB_DR_MODE_HOST;
+ else if (strcmp(tmpstr, "otg") == 0)
+ ret = USB_DR_MODE_OTG;
+ else
+ device_printf(dev, "Unknown dr mode: %s\n", tmpstr);
+ free(tmpstr, M_OFWPROP);
+ return (ret);
+}
+
+static int
+usbphy_utmi_read_params(struct usbphy_softc *sc, phandle_t node)
+{
+ int rv;
+
+ rv = OF_getencprop(node, "nvidia,hssync-start-delay",
+ &sc->hssync_start_delay, sizeof (sc->hssync_start_delay));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,elastic-limit",
+ &sc->elastic_limit, sizeof (sc->elastic_limit));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,idle-wait-delay",
+ &sc->idle_wait_delay, sizeof (sc->idle_wait_delay));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,term-range-adj",
+ &sc->term_range_adj, sizeof (sc->term_range_adj));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,xcvr-lsfslew",
+ &sc->xcvr_lsfslew, sizeof (sc->xcvr_lsfslew));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,xcvr-lsrslew",
+ &sc->xcvr_lsrslew, sizeof (sc->xcvr_lsrslew));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,xcvr-hsslew",
+ &sc->xcvr_hsslew, sizeof (sc->xcvr_hsslew));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,hssquelch-level",
+ &sc->hssquelch_level, sizeof (sc->hssquelch_level));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getencprop(node, "nvidia,hsdiscon-level",
+ &sc->hsdiscon_level, sizeof (sc->hsdiscon_level));
+ if (rv <= 0)
+ return (ENXIO);
+
+ rv = OF_getproplen(node, "nvidia,xcvr-setup-use-fuses");
+ if (rv >= 1) {
+ sc->xcvr_setup_use_fuses = 1;
+ } else {
+ rv = OF_getencprop(node, "nvidia,xcvr-setup",
+ &sc->xcvr_setup, sizeof (sc->xcvr_setup));
+ if (rv <= 0)
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+usbphy_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Tegra USB phy");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+usbphy_attach(device_t dev)
+{
+ struct usbphy_softc * sc;
+ int rid, rv;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ rid = 1;
+ sc->pads_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ return (ENXIO);
+ }
+
+ node = ofw_bus_get_node(dev);
+
+ rv = hwreset_get_by_ofw_name(sc->dev, "usb", &sc->reset_usb);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'usb' reset\n");
+ return (ENXIO);
+ }
+ rv = hwreset_get_by_ofw_name(sc->dev, "utmi-pads", &sc->reset_pads);
+ if (rv != 0) {
+ device_printf(dev, "Cannot get 'utmi-pads' reset\n");
+ return (ENXIO);
+ }
+
+ rv = clk_get_by_ofw_name(sc->dev, "reg", &sc->clk_reg);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'reg' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "pll_u", &sc->clk_pllu);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'pll_u' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_get_by_ofw_name(sc->dev, "utmi-pads", &sc->clk_pads);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'utmi-pads' clock\n");
+ return (ENXIO);
+ }
+
+ rv = hwreset_deassert(sc->reset_usb);
+ if (rv != 0) {
+ device_printf(dev, "Cannot unreset 'usb' reset\n");
+ return (ENXIO);
+ }
+
+ rv = clk_enable(sc->clk_pllu);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'pllu' clock\n");
+ return (ENXIO);
+ }
+ rv = clk_enable(sc->clk_reg);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'reg' clock\n");
+ return (ENXIO);
+ }
+ if (OF_hasprop(node, "nvidia,has-utmi-pad-registers"))
+ sc->have_utmi_regs = true;
+
+ sc->dr_mode = usb_get_dr_mode(dev, node, "dr_mode");
+ if (sc->dr_mode == USB_DR_MODE_UNKNOWN)
+ sc->dr_mode = USB_DR_MODE_HOST;
+
+ sc->ifc_type = usb_get_ifc_mode(dev, node, "phy_type");
+
+ /* We supports only utmi phy mode for now .... */
+ if (sc->ifc_type != USB_IFC_TYPE_UTMI) {
+ device_printf(dev, "Unsupported phy type\n");
+ return (ENXIO);
+ }
+ rv = usbphy_utmi_read_params(sc, node);
+ if (rv < 0)
+ return rv;
+
+ if (OF_hasprop(node, "vbus-supply")) {
+ rv = regulator_get_by_ofw_property(sc->dev, "vbus-supply",
+ &sc->supply_vbus);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get \"vbus\" regulator\n");
+ return (ENXIO);
+ }
+ rv = regulator_enable(sc->supply_vbus);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable \"vbus\" regulator\n");
+ return (rv);
+ }
+ }
+
+ phy_register_provider(dev);
+ return (0);
+}
+
+static int
+usbphy_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static device_method_t tegra_usbphy_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, usbphy_probe),
+ DEVMETHOD(device_attach, usbphy_attach),
+ DEVMETHOD(device_detach, usbphy_detach),
+
+ /* phy interface */
+ DEVMETHOD(phy_enable, usbphy_phy_enable),
+
+ DEVMETHOD_END
+};
+
+static driver_t tegra_usbphy_driver = {
+ "tegra_usbphy",
+ tegra_usbphy_methods,
+ sizeof(struct usbphy_softc),
+};
+
+static devclass_t tegra_usbphy_devclass;
+
+EARLY_DRIVER_MODULE(tegra_usbphy, simplebus, tegra_usbphy_driver,
+ tegra_usbphy_devclass, 0, 0, 79);
diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c
index 19f4544..9a0a313 100644
--- a/sys/arm/ti/aintc.c
+++ b/sys/arm/ti/aintc.c
@@ -30,12 +30,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/module.h>
+#include <sys/proc.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -45,6 +48,10 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#endif
+
#define INTC_REVISION 0x00
#define INTC_SYSCONFIG 0x10
#define INTC_SYSSTATUS 0x14
@@ -56,12 +63,27 @@ __FBSDID("$FreeBSD$");
#define INTC_ISR_SET(x) (0x90 + ((x) * 0x20))
#define INTC_ISR_CLEAR(x) (0x94 + ((x) * 0x20))
+#define INTC_SIR_SPURIOUS_MASK 0xffffff80
+#define INTS_SIR_ACTIVE_MASK 0x7f
+
+#define INTC_NIRQS 128
+
+#ifdef ARM_INTRNG
+struct ti_aintc_irqsrc {
+ struct intr_irqsrc tai_isrc;
+ u_int tai_irq;
+};
+#endif
+
struct ti_aintc_softc {
device_t sc_dev;
struct resource * aintc_res[3];
bus_space_tag_t aintc_bst;
bus_space_handle_t aintc_bsh;
uint8_t ver;
+#ifdef ARM_INTRNG
+ struct ti_aintc_irqsrc aintc_isrcs[INTC_NIRQS];
+#endif
};
static struct resource_spec ti_aintc_spec[] = {
@@ -83,6 +105,141 @@ static struct ofw_compat_data compat_data[] = {
{NULL, 0},
};
+#ifdef ARM_INTRNG
+static inline void
+ti_aintc_irq_eoi(struct ti_aintc_softc *sc)
+{
+
+ aintc_write_4(sc, INTC_CONTROL, 1);
+}
+
+static inline void
+ti_aintc_irq_mask(struct ti_aintc_softc *sc, u_int irq)
+{
+
+ aintc_write_4(sc, INTC_MIR_SET(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static inline void
+ti_aintc_irq_unmask(struct ti_aintc_softc *sc, u_int irq)
+{
+
+ aintc_write_4(sc, INTC_MIR_CLEAR(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static int
+ti_aintc_intr(void *arg)
+{
+ uint32_t irq;
+ struct ti_aintc_softc *sc = arg;
+
+ /* Get active interrupt */
+ irq = aintc_read_4(sc, INTC_SIR_IRQ);
+ if ((irq & INTC_SIR_SPURIOUS_MASK) != 0) {
+ device_printf(sc->sc_dev,
+ "Spurious interrupt detected (0x%08x)\n", irq);
+ ti_aintc_irq_eoi(sc);
+ return (FILTER_HANDLED);
+ }
+
+ /* Only level-sensitive interrupts detection is supported. */
+ irq &= INTS_SIR_ACTIVE_MASK;
+ if (intr_isrc_dispatch(&sc->aintc_isrcs[irq].tai_isrc,
+ curthread->td_intr_frame) != 0) {
+ ti_aintc_irq_mask(sc, irq);
+ ti_aintc_irq_eoi(sc);
+ device_printf(sc->sc_dev, "Stray irq %u disabled\n", irq);
+ }
+
+ arm_irq_memory_barrier(irq); /* XXX */
+ return (FILTER_HANDLED);
+}
+
+static void
+ti_aintc_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ arm_irq_memory_barrier(irq);
+ ti_aintc_irq_unmask(sc, irq);
+}
+
+static void
+ti_aintc_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ ti_aintc_irq_mask(sc, irq);
+}
+
+static int
+ti_aintc_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ struct ti_aintc_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells != 1 ||
+ data->fdt.cells[0] >= INTC_NIRQS)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ *isrcp = &sc->aintc_isrcs[data->fdt.cells[0]].tai_isrc;
+ return (0);
+}
+
+static void
+ti_aintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ u_int irq = ((struct ti_aintc_irqsrc *)isrc)->tai_irq;
+ struct ti_aintc_softc *sc = device_get_softc(dev);
+
+ ti_aintc_irq_mask(sc, irq);
+ ti_aintc_irq_eoi(sc);
+}
+
+static void
+ti_aintc_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ ti_aintc_enable_intr(dev, isrc);
+}
+
+static void
+ti_aintc_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ ti_aintc_irq_eoi(device_get_softc(dev));
+}
+
+static int
+ti_aintc_pic_attach(struct ti_aintc_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ const char *name;
+ intptr_t xref;
+
+ name = device_get_nameunit(sc->sc_dev);
+ for (irq = 0; irq < INTC_NIRQS; irq++) {
+ sc->aintc_isrcs[irq].tai_irq = irq;
+
+ error = intr_isrc_register(&sc->aintc_isrcs[irq].tai_isrc,
+ sc->sc_dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error);
+ }
+
+ xref = OF_xref_from_node(ofw_bus_get_node(sc->sc_dev));
+ error = intr_pic_register(sc->sc_dev, xref);
+ if (error != 0)
+ return (error);
+
+ return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc, 0));
+}
+
+#else
static void
aintc_post_filter(void *arg)
{
@@ -90,6 +247,7 @@ aintc_post_filter(void *arg)
arm_irq_memory_barrier(0);
aintc_write_4(ti_aintc_sc, INTC_CONTROL, 1); /* EOI */
}
+#endif
static int
ti_aintc_probe(device_t dev)
@@ -137,14 +295,30 @@ ti_aintc_attach(device_t dev)
/*Set Priority Threshold */
aintc_write_4(sc, INTC_THRESHOLD, 0xFF);
+#ifndef ARM_INTRNG
arm_post_filter = aintc_post_filter;
-
+#else
+ if (ti_aintc_pic_attach(sc) != 0) {
+ device_printf(dev, "could not attach PIC\n");
+ return (ENXIO);
+ }
+#endif
return (0);
}
static device_method_t ti_aintc_methods[] = {
DEVMETHOD(device_probe, ti_aintc_probe),
DEVMETHOD(device_attach, ti_aintc_attach),
+
+#ifdef ARM_INTRNG
+ DEVMETHOD(pic_disable_intr, ti_aintc_disable_intr),
+ DEVMETHOD(pic_enable_intr, ti_aintc_enable_intr),
+ DEVMETHOD(pic_map_intr, ti_aintc_map_intr),
+ DEVMETHOD(pic_post_filter, ti_aintc_post_filter),
+ DEVMETHOD(pic_post_ithread, ti_aintc_post_ithread),
+ DEVMETHOD(pic_pre_ithread, ti_aintc_pre_ithread),
+#endif
+
{ 0, 0 }
};
@@ -160,6 +334,7 @@ EARLY_DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass,
0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
SIMPLEBUS_PNP_INFO(compat_data);
+#ifndef ARM_INTRNG
int
arm_get_next_irq(int last_irq)
{
@@ -200,3 +375,4 @@ arm_unmask_irq(uintptr_t nb)
arm_irq_memory_barrier(nb);
aintc_write_4(sc, INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
}
+#endif
diff --git a/sys/arm/ti/am335x/am335x_prcm.c b/sys/arm/ti/am335x/am335x_prcm.c
index 8a6476d..f72bb54 100644
--- a/sys/arm/ti/am335x/am335x_prcm.c
+++ b/sys/arm/ti/am335x/am335x_prcm.c
@@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$");
#define CM_PER_MMC0_CLKCTRL (CM_PER + 0x03C)
#define CM_PER_I2C2_CLKCTRL (CM_PER + 0x044)
#define CM_PER_I2C1_CLKCTRL (CM_PER + 0x048)
+#define CM_PER_SPI0_CLKCTRL (CM_PER + 0x04C)
+#define CM_PER_SPI1_CLKCTRL (CM_PER + 0x050)
#define CM_PER_UART1_CLKCTRL (CM_PER + 0x06C)
#define CM_PER_UART2_CLKCTRL (CM_PER + 0x070)
#define CM_PER_UART3_CLKCTRL (CM_PER + 0x074)
@@ -274,6 +276,10 @@ struct ti_clock_dev ti_am335x_clk_devmap[] = {
AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
AM335X_GENERIC_CLOCK_DEV(I2C3_CLK),
+ /* McSPI we use hwmods as reference, not units in spec */
+ AM335X_GENERIC_CLOCK_DEV(SPI0_CLK),
+ AM335X_GENERIC_CLOCK_DEV(SPI1_CLK),
+
/* TSC_ADC */
AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK),
@@ -356,6 +362,10 @@ static struct am335x_clk_details g_am335x_clk_details[] = {
_CLK_DETAIL(I2C2_CLK, CM_PER_I2C1_CLKCTRL, 0),
_CLK_DETAIL(I2C3_CLK, CM_PER_I2C2_CLKCTRL, 0),
+ /* McSPI modules, hwmods start with spi0 */
+ _CLK_DETAIL(SPI0_CLK, CM_PER_SPI0_CLKCTRL, 0),
+ _CLK_DETAIL(SPI1_CLK, CM_PER_SPI1_CLKCTRL, 0),
+
/* TSC_ADC module */
_CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0),
diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c
index a27393d..4486e0f 100644
--- a/sys/arm/ti/cpsw/if_cpsw.c
+++ b/sys/arm/ti/cpsw/if_cpsw.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ * Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -93,50 +94,55 @@ __FBSDID("$FreeBSD$");
/* Device probe/attach/detach. */
static int cpsw_probe(device_t);
-static void cpsw_init_slots(struct cpsw_softc *);
static int cpsw_attach(device_t);
-static void cpsw_free_slot(struct cpsw_softc *, struct cpsw_slot *);
static int cpsw_detach(device_t);
+static int cpswp_probe(device_t);
+static int cpswp_attach(device_t);
+static int cpswp_detach(device_t);
+
+static phandle_t cpsw_get_node(device_t, device_t);
/* Device Init/shutdown. */
-static void cpsw_init(void *);
-static void cpsw_init_locked(void *);
static int cpsw_shutdown(device_t);
-static void cpsw_shutdown_locked(struct cpsw_softc *);
+static void cpswp_init(void *);
+static void cpswp_init_locked(void *);
+static void cpswp_stop_locked(struct cpswp_softc *);
/* Device Suspend/Resume. */
static int cpsw_suspend(device_t);
static int cpsw_resume(device_t);
/* Ioctl. */
-static int cpsw_ioctl(struct ifnet *, u_long command, caddr_t data);
+static int cpswp_ioctl(struct ifnet *, u_long command, caddr_t data);
-static int cpsw_miibus_readreg(device_t, int phy, int reg);
-static int cpsw_miibus_writereg(device_t, int phy, int reg, int value);
-static void cpsw_miibus_statchg(device_t);
+static int cpswp_miibus_readreg(device_t, int phy, int reg);
+static int cpswp_miibus_writereg(device_t, int phy, int reg, int value);
+static void cpswp_miibus_statchg(device_t);
/* Send/Receive packets. */
static void cpsw_intr_rx(void *arg);
static struct mbuf *cpsw_rx_dequeue(struct cpsw_softc *);
static void cpsw_rx_enqueue(struct cpsw_softc *);
-static void cpsw_start(struct ifnet *);
-static void cpsw_tx_enqueue(struct cpsw_softc *);
+static void cpswp_start(struct ifnet *);
+static void cpswp_tx_enqueue(struct cpswp_softc *);
static int cpsw_tx_dequeue(struct cpsw_softc *);
/* Misc interrupts and watchdog. */
static void cpsw_intr_rx_thresh(void *);
static void cpsw_intr_misc(void *);
-static void cpsw_tick(void *);
-static void cpsw_ifmedia_sts(struct ifnet *, struct ifmediareq *);
-static int cpsw_ifmedia_upd(struct ifnet *);
-static void cpsw_tx_watchdog(struct cpsw_softc *);
+static void cpswp_tick(void *);
+static void cpswp_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int cpswp_ifmedia_upd(struct ifnet *);
+static void cpsw_tx_watchdog(void *);
/* ALE support */
-static void cpsw_ale_read_entry(struct cpsw_softc *, uint16_t idx, uint32_t *ale_entry);
-static void cpsw_ale_write_entry(struct cpsw_softc *, uint16_t idx, uint32_t *ale_entry);
-static int cpsw_ale_mc_entry_set(struct cpsw_softc *, uint8_t portmap, uint8_t *mac);
-static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge);
+static void cpsw_ale_read_entry(struct cpsw_softc *, uint16_t, uint32_t *);
+static void cpsw_ale_write_entry(struct cpsw_softc *, uint16_t, uint32_t *);
+static int cpsw_ale_mc_entry_set(struct cpsw_softc *, uint8_t, int, uint8_t *);
static void cpsw_ale_dump_table(struct cpsw_softc *);
+static int cpsw_ale_update_vlan_table(struct cpsw_softc *, int, int, int, int,
+ int);
+static int cpswp_ale_update_addresses(struct cpswp_softc *, int);
/* Statistics and sysctls. */
static void cpsw_add_sysctls(struct cpsw_softc *);
@@ -148,27 +154,9 @@ static int cpsw_stats_sysctl(SYSCTL_HANDLER_ARGS);
* Packets with more segments than this will be defragmented before
* they are queued.
*/
-#define CPSW_TXFRAGS 8
-
-
-/*
- * TODO: The CPSW subsystem (CPSW_SS) can drive two independent PHYs
- * as separate Ethernet ports. To properly support this, we should
- * break this into two separate devices: a CPSW_SS device that owns
- * the interrupts and actually talks to the CPSW hardware, and a
- * separate CPSW Ethernet child device for each Ethernet port. The RX
- * interrupt, for example, would be part of CPSW_SS; it would receive
- * a packet, note the input port, and then dispatch it to the child
- * device's interface queue. Similarly for transmit.
- *
- * It's not clear to me whether the device tree should be restructured
- * with a cpsw_ss node and two child nodes. That would allow specifying
- * MAC addresses for each port, for example, but might be overkill.
- *
- * Unfortunately, I don't have hardware right now that supports two
- * Ethernet ports via CPSW.
- */
+#define CPSW_TXFRAGS 16
+/* Shared resources. */
static device_method_t cpsw_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, cpsw_probe),
@@ -177,26 +165,49 @@ static device_method_t cpsw_methods[] = {
DEVMETHOD(device_shutdown, cpsw_shutdown),
DEVMETHOD(device_suspend, cpsw_suspend),
DEVMETHOD(device_resume, cpsw_resume),
- /* MII interface */
- DEVMETHOD(miibus_readreg, cpsw_miibus_readreg),
- DEVMETHOD(miibus_writereg, cpsw_miibus_writereg),
- DEVMETHOD(miibus_statchg, cpsw_miibus_statchg),
- { 0, 0 }
+ /* OFW methods */
+ DEVMETHOD(ofw_bus_get_node, cpsw_get_node),
+ DEVMETHOD_END
};
static driver_t cpsw_driver = {
- "cpsw",
+ "cpswss",
cpsw_methods,
sizeof(struct cpsw_softc),
};
static devclass_t cpsw_devclass;
-DRIVER_MODULE(cpsw, simplebus, cpsw_driver, cpsw_devclass, 0, 0);
+DRIVER_MODULE(cpswss, simplebus, cpsw_driver, cpsw_devclass, 0, 0);
+
+/* Port/Slave resources. */
+static device_method_t cpswp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cpswp_probe),
+ DEVMETHOD(device_attach, cpswp_attach),
+ DEVMETHOD(device_detach, cpswp_detach),
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, cpswp_miibus_readreg),
+ DEVMETHOD(miibus_writereg, cpswp_miibus_writereg),
+ DEVMETHOD(miibus_statchg, cpswp_miibus_statchg),
+ DEVMETHOD_END
+};
+
+static driver_t cpswp_driver = {
+ "cpsw",
+ cpswp_methods,
+ sizeof(struct cpswp_softc),
+};
+
+static devclass_t cpswp_devclass;
+
+DRIVER_MODULE(cpsw, cpswss, cpswp_driver, cpswp_devclass, 0, 0);
DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0);
MODULE_DEPEND(cpsw, ether, 1, 1, 1);
MODULE_DEPEND(cpsw, miibus, 1, 1, 1);
+static uint32_t slave_mdio_addr[] = { 0x4a100200, 0x4a100300 };
+
static struct resource_spec irq_res_spec[] = {
{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
@@ -206,7 +217,7 @@ static struct resource_spec irq_res_spec[] = {
};
/* Number of entries here must match size of stats
- * array in struct cpsw_softc. */
+ * array in struct cpswp_softc. */
static struct cpsw_stat {
int reg;
char *oid;
@@ -251,7 +262,7 @@ static struct cpsw_stat {
* Basic debug support.
*/
-#define IF_DEBUG(sc) if (sc->cpsw_if_flags & IFF_DEBUG)
+#define IF_DEBUG(_sc) if ((_sc)->if_flags & IFF_DEBUG)
static void
cpsw_debugf_head(const char *funcname)
@@ -274,35 +285,42 @@ cpsw_debugf(const char *fmt, ...)
}
-#define CPSW_DEBUGF(a) do { \
- IF_DEBUG(sc) { \
- cpsw_debugf_head(__func__); \
- cpsw_debugf a; \
- } \
+#define CPSW_DEBUGF(_sc, a) do { \
+ if (sc->debug) { \
+ cpsw_debugf_head(__func__); \
+ cpsw_debugf a; \
+ } \
+} while (0)
+
+#define CPSWP_DEBUGF(_sc, a) do { \
+ IF_DEBUG((_sc)) { \
+ cpsw_debugf_head(__func__); \
+ cpsw_debugf a; \
+ } \
} while (0)
/*
* Locking macros
*/
-#define CPSW_TX_LOCK(sc) do { \
+#define CPSW_TX_LOCK(sc) do { \
mtx_assert(&(sc)->rx.lock, MA_NOTOWNED); \
mtx_lock(&(sc)->tx.lock); \
} while (0)
-#define CPSW_TX_UNLOCK(sc) mtx_unlock(&(sc)->tx.lock)
-#define CPSW_TX_LOCK_ASSERT(sc) mtx_assert(&(sc)->tx.lock, MA_OWNED)
+#define CPSW_TX_UNLOCK(sc) mtx_unlock(&(sc)->tx.lock)
+#define CPSW_TX_LOCK_ASSERT(sc) mtx_assert(&(sc)->tx.lock, MA_OWNED)
-#define CPSW_RX_LOCK(sc) do { \
+#define CPSW_RX_LOCK(sc) do { \
mtx_assert(&(sc)->tx.lock, MA_NOTOWNED); \
mtx_lock(&(sc)->rx.lock); \
} while (0)
-#define CPSW_RX_UNLOCK(sc) mtx_unlock(&(sc)->rx.lock)
-#define CPSW_RX_LOCK_ASSERT(sc) mtx_assert(&(sc)->rx.lock, MA_OWNED)
+#define CPSW_RX_UNLOCK(sc) mtx_unlock(&(sc)->rx.lock)
+#define CPSW_RX_LOCK_ASSERT(sc) mtx_assert(&(sc)->rx.lock, MA_OWNED)
-#define CPSW_GLOBAL_LOCK(sc) do { \
- if ((mtx_owned(&(sc)->tx.lock) ? 1 : 0) != \
+#define CPSW_GLOBAL_LOCK(sc) do { \
+ if ((mtx_owned(&(sc)->tx.lock) ? 1 : 0) != \
(mtx_owned(&(sc)->rx.lock) ? 1 : 0)) { \
panic("cpsw deadlock possibility detection!"); \
} \
@@ -310,25 +328,34 @@ cpsw_debugf(const char *fmt, ...)
mtx_lock(&(sc)->rx.lock); \
} while (0)
-#define CPSW_GLOBAL_UNLOCK(sc) do { \
- CPSW_RX_UNLOCK(sc); \
- CPSW_TX_UNLOCK(sc); \
+#define CPSW_GLOBAL_UNLOCK(sc) do { \
+ CPSW_RX_UNLOCK(sc); \
+ CPSW_TX_UNLOCK(sc); \
} while (0)
-#define CPSW_GLOBAL_LOCK_ASSERT(sc) do { \
+#define CPSW_GLOBAL_LOCK_ASSERT(sc) do { \
CPSW_TX_LOCK_ASSERT(sc); \
CPSW_RX_LOCK_ASSERT(sc); \
} while (0)
+#define CPSW_PORT_LOCK(_sc) do { \
+ mtx_assert(&(_sc)->lock, MA_NOTOWNED); \
+ mtx_lock(&(_sc)->lock); \
+} while (0)
+
+#define CPSW_PORT_UNLOCK(_sc) mtx_unlock(&(_sc)->lock)
+#define CPSW_PORT_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->lock, MA_OWNED)
+
/*
* Read/Write macros
*/
-#define cpsw_read_4(sc, reg) bus_read_4(sc->mem_res, reg)
-#define cpsw_write_4(sc, reg, val) bus_write_4(sc->mem_res, reg, val)
+#define cpsw_read_4(_sc, _reg) bus_read_4((_sc)->mem_res, (_reg))
+#define cpsw_write_4(_sc, _reg, _val) \
+ bus_write_4((_sc)->mem_res, (_reg), (_val))
#define cpsw_cpdma_bd_offset(i) (CPSW_CPPI_RAM_OFFSET + ((i)*16))
-#define cpsw_cpdma_bd_paddr(sc, slot) \
+#define cpsw_cpdma_bd_paddr(sc, slot) \
BUS_SPACE_PHYSADDR(sc->mem_res, slot->bd_offset)
#define cpsw_cpdma_read_bd(sc, slot, val) \
bus_read_region_4(sc->mem_res, slot->bd_offset, (uint32_t *) val, 4)
@@ -336,16 +363,16 @@ cpsw_debugf(const char *fmt, ...)
bus_write_region_4(sc->mem_res, slot->bd_offset, (uint32_t *) val, 4)
#define cpsw_cpdma_write_bd_next(sc, slot, next_slot) \
cpsw_write_4(sc, slot->bd_offset, cpsw_cpdma_bd_paddr(sc, next_slot))
-#define cpsw_cpdma_read_bd_flags(sc, slot) \
+#define cpsw_cpdma_read_bd_flags(sc, slot) \
bus_read_2(sc->mem_res, slot->bd_offset + 14)
#define cpsw_write_hdp_slot(sc, queue, slot) \
cpsw_write_4(sc, (queue)->hdp_offset, cpsw_cpdma_bd_paddr(sc, slot))
#define CP_OFFSET (CPSW_CPDMA_TX_CP(0) - CPSW_CPDMA_TX_HDP(0))
-#define cpsw_read_cp(sc, queue) \
+#define cpsw_read_cp(sc, queue) \
cpsw_read_4(sc, (queue)->hdp_offset + CP_OFFSET)
-#define cpsw_write_cp(sc, queue, val) \
+#define cpsw_write_cp(sc, queue, val) \
cpsw_write_4(sc, (queue)->hdp_offset + CP_OFFSET, (val))
-#define cpsw_write_cp_slot(sc, queue, slot) \
+#define cpsw_write_cp_slot(sc, queue, slot) \
cpsw_write_cp(sc, queue, cpsw_cpdma_bd_paddr(sc, slot))
#if 0
@@ -403,13 +430,12 @@ cpsw_dump_slot(struct cpsw_softc *sc, struct cpsw_slot *slot)
}
}
-#define CPSW_DUMP_SLOT(cs, slot) do { \
+#define CPSW_DUMP_SLOT(cs, slot) do { \
IF_DEBUG(sc) { \
cpsw_dump_slot(sc, slot); \
} \
} while (0)
-
static void
cpsw_dump_queue(struct cpsw_softc *sc, struct cpsw_slots *q)
{
@@ -435,28 +461,6 @@ cpsw_dump_queue(struct cpsw_softc *sc, struct cpsw_slots *q)
} \
} while (0)
-
-/*
- *
- * Device Probe, Attach, Detach.
- *
- */
-
-static int
-cpsw_probe(device_t dev)
-{
-
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
-
- if (!ofw_bus_is_compatible(dev, "ti,cpsw"))
- return (ENXIO);
-
- device_set_desc(dev, "3-port Switch Ethernet Subsystem");
- return (BUS_PROBE_DEFAULT);
-}
-
-
static void
cpsw_init_slots(struct cpsw_softc *sc)
{
@@ -473,50 +477,6 @@ cpsw_init_slots(struct cpsw_softc *sc)
}
}
-/*
- * bind an interrupt, add the relevant info to sc->interrupts
- */
-static int
-cpsw_attach_interrupt(struct cpsw_softc *sc, struct resource *res, driver_intr_t *handler, const char *description)
-{
- void **pcookie;
- int error;
-
- sc->interrupts[sc->interrupt_count].res = res;
- sc->interrupts[sc->interrupt_count].description = description;
- pcookie = &sc->interrupts[sc->interrupt_count].ih_cookie;
-
- error = bus_setup_intr(sc->dev, res, INTR_TYPE_NET | INTR_MPSAFE,
- NULL, *handler, sc, pcookie);
- if (error)
- device_printf(sc->dev,
- "could not setup %s\n", description);
- else
- ++sc->interrupt_count;
- return (error);
-}
-
-/*
- * teardown everything in sc->interrupts.
- */
-static void
-cpsw_detach_interrupts(struct cpsw_softc *sc)
-{
- int error;
- int i;
-
- for (i = 0; i < sizeof(sc->interrupts) / sizeof(sc->interrupts[0]); ++i) {
- if (!sc->interrupts[i].ih_cookie)
- continue;
- error = bus_teardown_intr(sc->dev,
- sc->interrupts[i].res, sc->interrupts[i].ih_cookie);
- if (error)
- device_printf(sc->dev, "could not release %s\n",
- sc->interrupts[i].description);
- sc->interrupts[i].ih_cookie = NULL;
- }
-}
-
static int
cpsw_add_slots(struct cpsw_softc *sc, struct cpsw_queue *queue, int requested)
{
@@ -532,7 +492,7 @@ cpsw_add_slots(struct cpsw_softc *sc, struct cpsw_queue *queue, int requested)
if (slot == NULL)
return (0);
if (bus_dmamap_create(sc->mbuf_dtag, 0, &slot->dmamap)) {
- if_printf(sc->ifp, "failed to create dmamap\n");
+ device_printf(sc->dev, "failed to create dmamap\n");
return (ENOMEM);
}
STAILQ_REMOVE_HEAD(&sc->avail, next);
@@ -543,56 +503,294 @@ cpsw_add_slots(struct cpsw_softc *sc, struct cpsw_queue *queue, int requested)
return (0);
}
-static int
-cpsw_attach(device_t dev)
+static void
+cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot)
{
- bus_dma_segment_t segs[1];
- struct cpsw_softc *sc = device_get_softc(dev);
- struct mii_softc *miisc;
- struct ifnet *ifp;
- int phy, nsegs, error;
+ int error;
+
+ if (slot->dmamap) {
+ if (slot->mbuf)
+ bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
+ error = bus_dmamap_destroy(sc->mbuf_dtag, slot->dmamap);
+ KASSERT(error == 0, ("Mapping still active"));
+ slot->dmamap = NULL;
+ }
+ if (slot->mbuf) {
+ m_freem(slot->mbuf);
+ slot->mbuf = NULL;
+ }
+}
+
+static void
+cpsw_reset(struct cpsw_softc *sc)
+{
+ int i;
+
+ callout_stop(&sc->watchdog.callout);
+
+ /* Reset RMII/RGMII wrapper. */
+ cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1);
+ while (cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1)
+ ;
+
+ /* Disable TX and RX interrupts for all cores. */
+ for (i = 0; i < 3; ++i) {
+ cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(i), 0x00);
+ cpsw_write_4(sc, CPSW_WR_C_TX_EN(i), 0x00);
+ cpsw_write_4(sc, CPSW_WR_C_RX_EN(i), 0x00);
+ cpsw_write_4(sc, CPSW_WR_C_MISC_EN(i), 0x00);
+ }
+
+ /* Reset CPSW subsystem. */
+ cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1);
+ while (cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1)
+ ;
+
+ /* Reset Sliver port 1 and 2 */
+ for (i = 0; i < 2; i++) {
+ /* Reset */
+ cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
+ while (cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1)
+ ;
+ }
+
+ /* Reset DMA controller. */
+ cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1);
+ while (cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1)
+ ;
+
+ /* Disable TX & RX DMA */
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 0);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 0);
+
+ /* Clear all queues. */
+ for (i = 0; i < 8; i++) {
+ cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0);
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_CP(i), 0);
+ }
+
+ /* Clear all interrupt Masks */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+ cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+}
+
+static void
+cpsw_init(struct cpsw_softc *sc)
+{
+ struct cpsw_slot *slot;
uint32_t reg;
- pcell_t phy_id[3];
- u_long mem_base, mem_size;
- phandle_t child;
- int len;
- CPSW_DEBUGF((""));
+ /* Clear ALE */
+ cpsw_write_4(sc, CPSW_ALE_CONTROL, CPSW_ALE_CTL_CLEAR_TBL);
- getbinuptime(&sc->attach_uptime);
- sc->dev = dev;
- sc->node = ofw_bus_get_node(dev);
+ /* Enable ALE */
+ reg = CPSW_ALE_CTL_ENABLE;
+ if (sc->dualemac)
+ reg |= CPSW_ALE_CTL_VLAN_AWARE;
+ cpsw_write_4(sc, CPSW_ALE_CONTROL, reg);
- /* TODO: handle multiple slaves */
- phy = -1;
+ /* Set Host Port Mapping. */
+ cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
+ cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+
+ /* Initialize ALE: set host port to forwarding(3). */
+ cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3);
+
+ cpsw_write_4(sc, CPSW_SS_PTYPE, 0);
+
+ /* Enable statistics for ports 0, 1 and 2 */
+ cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7);
+
+ /* Experiment: Turn off flow control */
+ /* This seems to fix the watchdog resets that have plagued
+ earlier versions of this driver; I'm not yet sure if there
+ are negative effects yet. */
+ cpsw_write_4(sc, CPSW_SS_FLOW_CONTROL, 0);
+
+ /* Make IP hdr aligned with 4 */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, 2);
+
+ /* Initialize RX Buffer Descriptors */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_FREEBUFFER(0), 0);
+
+ /* Enable TX & RX DMA */
+ cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1);
+ cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1);
+
+ /* Enable Interrupts for core 0 */
+ cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(0), 0xFF);
+ cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0xFF);
+ cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F);
+
+ /* Enable host Error Interrupt */
+ cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 3);
+
+ /* Enable interrupts for RX Channel 0 */
+ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1);
+
+ /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+ cpsw_write_4(sc, MDIOCONTROL, MDIOCTL_ENABLE | MDIOCTL_FAULTENB | 0xff);
+
+ /* Select MII in GMII_SEL, Internal Delay mode */
+ //ti_scm_reg_write_4(0x650, 0);
+
+ /* Initialize active queues. */
+ slot = STAILQ_FIRST(&sc->tx.active);
+ if (slot != NULL)
+ cpsw_write_hdp_slot(sc, &sc->tx, slot);
+ slot = STAILQ_FIRST(&sc->rx.active);
+ if (slot != NULL)
+ cpsw_write_hdp_slot(sc, &sc->rx, slot);
+ cpsw_rx_enqueue(sc);
+
+ /* Activate network interface. */
+ sc->rx.running = 1;
+ sc->tx.running = 1;
+ sc->watchdog.timer = 0;
+ callout_init(&sc->watchdog.callout, 0);
+ callout_reset(&sc->watchdog.callout, hz, cpsw_tx_watchdog, sc);
+}
+
+/*
+ *
+ * Device Probe, Attach, Detach.
+ *
+ */
+
+static int
+cpsw_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "ti,cpsw"))
+ return (ENXIO);
+
+ device_set_desc(dev, "3-port Switch Ethernet Subsystem");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+cpsw_intr_attach(struct cpsw_softc *sc)
+{
+
+ /* Note: We don't use sc->irq_res[2] (TX interrupt) */
+ if (bus_setup_intr(sc->dev, sc->irq_res[0],
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, cpsw_intr_rx_thresh,
+ sc, &sc->ih_cookie[0]) != 0) {
+ return (-1);
+ }
+ if (bus_setup_intr(sc->dev, sc->irq_res[1],
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, cpsw_intr_rx,
+ sc, &sc->ih_cookie[1]) != 0) {
+ return (-1);
+ }
+ if (bus_setup_intr(sc->dev, sc->irq_res[3],
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, cpsw_intr_misc,
+ sc, &sc->ih_cookie[3]) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+cpsw_intr_detach(struct cpsw_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < CPSW_INTR_COUNT; i++) {
+ if (sc->ih_cookie[i]) {
+ bus_teardown_intr(sc->dev, sc->irq_res[i],
+ sc->ih_cookie[i]);
+ }
+ }
+}
+
+static int
+cpsw_get_fdt_data(struct cpsw_softc *sc, int port)
+{
+ char *name;
+ int len, phy, vlan;
+ pcell_t phy_id[3], vlan_id;
+ phandle_t child;
+ unsigned long mdio_child_addr;
/* Find any slave with phy_id */
+ phy = -1;
+ vlan = -1;
for (child = OF_child(sc->node); child != 0; child = OF_peer(child)) {
- len = OF_getproplen(child, "phy_id");
- if (len <= 0)
+ if (OF_getprop_alloc(child, "name", 1, (void **)&name) < 0)
continue;
-
- /* Get phy address from fdt */
- if (OF_getencprop(child, "phy_id", phy_id, len) <= 0)
+ if (sscanf(name, "slave@%x", &mdio_child_addr) != 1) {
+ free(name, M_OFWPROP);
continue;
+ }
+ free(name, M_OFWPROP);
+ if (mdio_child_addr != slave_mdio_addr[port])
+ continue;
+
+ len = OF_getproplen(child, "phy_id");
+ if (len / sizeof(pcell_t) == 2) {
+ /* Get phy address from fdt */
+ if (OF_getencprop(child, "phy_id", phy_id, len) > 0)
+ phy = phy_id[1];
+ }
- phy = phy_id[1];
- /* TODO: get memory window for MDIO */
+ len = OF_getproplen(child, "dual_emac_res_vlan");
+ if (len / sizeof(pcell_t) == 1) {
+ /* Get phy address from fdt */
+ if (OF_getencprop(child, "dual_emac_res_vlan",
+ &vlan_id, len) > 0) {
+ vlan = vlan_id;
+ }
+ }
break;
}
-
- if (phy == -1) {
- device_printf(dev, "failed to get PHY address from FDT\n");
+ if (phy == -1)
return (ENXIO);
+ sc->port[port].phy = phy;
+ sc->port[port].vlan = vlan;
+
+ return (0);
+}
+
+static int
+cpsw_attach(device_t dev)
+{
+ bus_dma_segment_t segs[1];
+ int error, i, nsegs;
+ struct cpsw_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->node = ofw_bus_get_node(dev);
+ getbinuptime(&sc->attach_uptime);
+
+ if (OF_getencprop(sc->node, "active_slave", &sc->active_slave,
+ sizeof(sc->active_slave)) <= 0) {
+ sc->active_slave = 0;
}
+ if (sc->active_slave > 1)
+ sc->active_slave = 1;
- mem_base = 0;
- mem_size = 0;
+ if (OF_hasprop(sc->node, "dual_emac"))
+ sc->dualemac = 1;
- if (fdt_regsize(sc->node, &mem_base, &mem_size) != 0) {
- device_printf(sc->dev, "no regs property in cpsw node\n");
- return (ENXIO);
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ if (cpsw_get_fdt_data(sc, i) != 0) {
+ device_printf(dev,
+ "failed to get PHY address from FDT\n");
+ return (ENXIO);
+ }
}
/* Initialize mutexes */
@@ -610,9 +808,8 @@ cpsw_attach(device_t dev)
}
sc->mem_rid = 0;
- sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
- &sc->mem_rid, mem_base, mem_base + CPSW_MEMWINDOW_SIZE -1,
- CPSW_MEMWINDOW_SIZE, RF_ACTIVE);
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->mem_rid, RF_ACTIVE);
if (sc->mem_res == NULL) {
device_printf(sc->dev, "failed to allocate memory resource\n");
cpsw_detach(dev);
@@ -642,14 +839,6 @@ cpsw_attach(device_t dev)
return (error);
}
- /* Allocate network interface */
- ifp = sc->ifp = if_alloc(IFT_ETHER);
- if (ifp == NULL) {
- device_printf(dev, "if_alloc() failed\n");
- cpsw_detach(dev);
- return (ENOMEM);
- }
-
/* Allocate the null mbuf and pre-sync it. */
sc->null_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
memset(sc->null_mbuf->m_data, 0, sc->null_mbuf->m_ext.ext_size);
@@ -660,16 +849,6 @@ cpsw_attach(device_t dev)
BUS_DMASYNC_PREWRITE);
sc->null_mbuf_paddr = segs[0].ds_addr;
- if_initname(ifp, device_get_name(dev), device_get_unit(dev));
- ifp->if_softc = sc;
- ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
- ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN?
- ifp->if_capenable = ifp->if_capabilities;
-
- ifp->if_init = cpsw_init;
- ifp->if_start = cpsw_start;
- ifp->if_ioctl = cpsw_ioctl;
-
cpsw_init_slots(sc);
/* Allocate slots to TX and RX queues. */
@@ -679,7 +858,8 @@ cpsw_attach(device_t dev)
STAILQ_INIT(&sc->tx.active);
// For now: 128 slots to TX, rest to RX.
// XXX TODO: start with 32/64 and grow dynamically based on demand.
- if (cpsw_add_slots(sc, &sc->tx, 128) || cpsw_add_slots(sc, &sc->rx, -1)) {
+ if (cpsw_add_slots(sc, &sc->tx, 128) ||
+ cpsw_add_slots(sc, &sc->rx, -1)) {
device_printf(dev, "failed to allocate dmamaps\n");
cpsw_detach(dev);
return (ENOMEM);
@@ -687,127 +867,78 @@ cpsw_attach(device_t dev)
device_printf(dev, "Initial queue size TX=%d RX=%d\n",
sc->tx.queue_slots, sc->rx.queue_slots);
- ifp->if_snd.ifq_drv_maxlen = sc->tx.queue_slots;
- IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
- IFQ_SET_READY(&ifp->if_snd);
-
sc->tx.hdp_offset = CPSW_CPDMA_TX_HDP(0);
sc->rx.hdp_offset = CPSW_CPDMA_RX_HDP(0);
- /* Get high part of MAC address from control module (mac_id0_hi) */
- /* TODO: Get MAC ID1 as well as MAC ID0. */
- ti_scm_reg_read_4(0x634, &reg);
- sc->mac_addr[0] = reg & 0xFF;
- sc->mac_addr[1] = (reg >> 8) & 0xFF;
- sc->mac_addr[2] = (reg >> 16) & 0xFF;
- sc->mac_addr[3] = (reg >> 24) & 0xFF;
-
- /* Get low part of MAC address from control module (mac_id0_lo) */
- ti_scm_reg_read_4(0x630, &reg);
- sc->mac_addr[4] = reg & 0xFF;
- sc->mac_addr[5] = (reg >> 8) & 0xFF;
-
- /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
- /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
- cpsw_write_4(sc, MDIOCONTROL, 1 << 30 | 1 << 18 | 0xFF);
-
- /* Clear ALE */
- cpsw_write_4(sc, CPSW_ALE_CONTROL, 1 << 30);
-
- /* Attach PHY(s) */
- error = mii_attach(dev, &sc->miibus, ifp, cpsw_ifmedia_upd,
- cpsw_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
- if (error) {
- device_printf(dev, "attaching PHYs failed\n");
+ if (cpsw_intr_attach(sc) == -1) {
+ device_printf(dev, "failed to setup interrupts\n");
cpsw_detach(dev);
- return (error);
+ return (ENXIO);
}
- sc->mii = device_get_softc(sc->miibus);
- /* Tell the MAC where to find the PHY so autoneg works */
- miisc = LIST_FIRST(&sc->mii->mii_phys);
+ /* Reset the controller. */
+ cpsw_reset(sc);
+ cpsw_init(sc);
- /* Select PHY and enable interrupts */
- cpsw_write_4(sc, MDIOUSERPHYSEL0, 1 << 6 | (miisc->mii_phy & 0x1F));
-
- /* Note: We don't use sc->res[3] (TX interrupt) */
- if (cpsw_attach_interrupt(sc, sc->irq_res[0],
- cpsw_intr_rx_thresh, "CPSW RX threshold interrupt") ||
- cpsw_attach_interrupt(sc, sc->irq_res[1],
- cpsw_intr_rx, "CPSW RX interrupt") ||
- cpsw_attach_interrupt(sc, sc->irq_res[3],
- cpsw_intr_misc, "CPSW misc interrupt")) {
- cpsw_detach(dev);
- return (ENXIO);
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ sc->port[i].dev = device_add_child(dev, "cpsw", i);
+ if (sc->port[i].dev == NULL) {
+ cpsw_detach(dev);
+ return (ENXIO);
+ }
}
-
- ether_ifattach(ifp, sc->mac_addr);
- callout_init(&sc->watchdog.callout, 0);
+ bus_generic_attach(dev);
return (0);
}
-static void
-cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot)
-{
- int error;
-
- if (slot->dmamap) {
- error = bus_dmamap_destroy(sc->mbuf_dtag, slot->dmamap);
- KASSERT(error == 0, ("Mapping still active"));
- slot->dmamap = NULL;
- }
- if (slot->mbuf) {
- m_freem(slot->mbuf);
- slot->mbuf = NULL;
- }
-}
-
static int
cpsw_detach(device_t dev)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpsw_softc *sc;
int error, i;
- CPSW_DEBUGF((""));
+ bus_generic_detach(dev);
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (sc->port[i].dev)
+ device_delete_child(dev, sc->port[i].dev);
+ }
- /* Stop controller and free TX queue */
if (device_is_attached(dev)) {
- ether_ifdetach(sc->ifp);
- CPSW_GLOBAL_LOCK(sc);
- cpsw_shutdown_locked(sc);
- CPSW_GLOBAL_UNLOCK(sc);
+ callout_stop(&sc->watchdog.callout);
callout_drain(&sc->watchdog.callout);
}
- bus_generic_detach(dev);
- if (sc->miibus)
- device_delete_child(dev, sc->miibus);
-
/* Stop and release all interrupts */
- cpsw_detach_interrupts(sc);
+ cpsw_intr_detach(sc);
/* Free dmamaps and mbufs */
for (i = 0; i < sizeof(sc->_slots) / sizeof(sc->_slots[0]); ++i)
cpsw_free_slot(sc, &sc->_slots[i]);
+
+ /* Free null mbuf. */
if (sc->null_mbuf_dmamap) {
+ bus_dmamap_unload(sc->mbuf_dtag, sc->null_mbuf_dmamap);
error = bus_dmamap_destroy(sc->mbuf_dtag, sc->null_mbuf_dmamap);
KASSERT(error == 0, ("Mapping still active"));
- }
- if (sc->null_mbuf)
m_freem(sc->null_mbuf);
+ }
/* Free DMA tag */
- error = bus_dma_tag_destroy(sc->mbuf_dtag);
- KASSERT(error == 0, ("Unable to destroy DMA tag"));
+ if (sc->mbuf_dtag) {
+ error = bus_dma_tag_destroy(sc->mbuf_dtag);
+ KASSERT(error == 0, ("Unable to destroy DMA tag"));
+ }
/* Free IO memory handler */
- bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
bus_release_resources(dev, irq_res_spec, sc->irq_res);
- if (sc->ifp != NULL)
- if_free(sc->ifp);
-
/* Destroy mutexes */
mtx_destroy(&sc->rx.lock);
mtx_destroy(&sc->tx.lock);
@@ -815,196 +946,249 @@ cpsw_detach(device_t dev)
return (0);
}
-/*
- *
- * Init/Shutdown.
- *
- */
-
-static void
-cpsw_reset(struct cpsw_softc *sc)
+static phandle_t
+cpsw_get_node(device_t bus, device_t dev)
{
- int i;
-
- /* Reset RMII/RGMII wrapper. */
- cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1);
- while (cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1)
- ;
- /* Disable TX and RX interrupts for all cores. */
- for (i = 0; i < 3; ++i) {
- cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(i), 0x00);
- cpsw_write_4(sc, CPSW_WR_C_TX_EN(i), 0x00);
- cpsw_write_4(sc, CPSW_WR_C_RX_EN(i), 0x00);
- cpsw_write_4(sc, CPSW_WR_C_MISC_EN(i), 0x00);
- }
+ /* Share controller node with port device. */
+ return (ofw_bus_get_node(bus));
+}
- /* Reset CPSW subsystem. */
- cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1);
- while (cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1)
- ;
+static int
+cpswp_probe(device_t dev)
+{
- /* Reset Sliver port 1 and 2 */
- for (i = 0; i < 2; i++) {
- /* Reset */
- cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1);
- while (cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1)
- ;
+ if (device_get_unit(dev) > 1) {
+ device_printf(dev, "Only two ports are supported.\n");
+ return (ENXIO);
}
+ device_set_desc(dev, "Ethernet Switch Port");
- /* Reset DMA controller. */
- cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1);
- while (cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1)
- ;
+ return (BUS_PROBE_DEFAULT);
+}
- /* Disable TX & RX DMA */
- cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 0);
- cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 0);
+static int
+cpswp_attach(device_t dev)
+{
+ int error;
+ struct ifnet *ifp;
+ struct cpswp_softc *sc;
+ uint32_t reg;
+ uint8_t mac_addr[ETHER_ADDR_LEN];
- /* Clear all queues. */
- for (i = 0; i < 8; i++) {
- cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0);
- cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0);
- cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0);
- cpsw_write_4(sc, CPSW_CPDMA_RX_CP(i), 0);
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->pdev = device_get_parent(dev);
+ sc->swsc = device_get_softc(sc->pdev);
+ sc->unit = device_get_unit(dev);
+ sc->phy = sc->swsc->port[sc->unit].phy;
+ sc->vlan = sc->swsc->port[sc->unit].vlan;
+ if (sc->swsc->dualemac && sc->vlan == -1)
+ sc->vlan = sc->unit + 1;
+
+ if (sc->unit == 0) {
+ sc->physel = MDIOUSERPHYSEL0;
+ sc->phyaccess = MDIOUSERACCESS0;
+ } else {
+ sc->physel = MDIOUSERPHYSEL1;
+ sc->phyaccess = MDIOUSERACCESS1;
}
- /* Clear all interrupt Masks */
- cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
- cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
-}
+ mtx_init(&sc->lock, device_get_nameunit(dev), "cpsw port lock",
+ MTX_DEF);
-static void
-cpsw_init(void *arg)
-{
- struct cpsw_softc *sc = arg;
+ /* Allocate network interface */
+ ifp = sc->ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ cpswp_detach(dev);
+ return (ENXIO);
+ }
- CPSW_DEBUGF((""));
- CPSW_GLOBAL_LOCK(sc);
- cpsw_init_locked(arg);
- CPSW_GLOBAL_UNLOCK(sc);
-}
+ if_initname(ifp, device_get_name(sc->dev), sc->unit);
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
+ ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN?
+ ifp->if_capenable = ifp->if_capabilities;
-static void
-cpsw_init_locked(void *arg)
-{
- struct ifnet *ifp;
- struct cpsw_softc *sc = arg;
- struct cpsw_slot *slot;
- uint32_t i;
+ ifp->if_init = cpswp_init;
+ ifp->if_start = cpswp_start;
+ ifp->if_ioctl = cpswp_ioctl;
- CPSW_DEBUGF((""));
- ifp = sc->ifp;
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
- return;
+ ifp->if_snd.ifq_drv_maxlen = sc->swsc->tx.queue_slots;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+ IFQ_SET_READY(&ifp->if_snd);
- getbinuptime(&sc->init_uptime);
+ /* Get high part of MAC address from control module (mac_id[0|1]_hi) */
+ ti_scm_reg_read_4(0x634 + sc->unit * 8, &reg);
+ mac_addr[0] = reg & 0xFF;
+ mac_addr[1] = (reg >> 8) & 0xFF;
+ mac_addr[2] = (reg >> 16) & 0xFF;
+ mac_addr[3] = (reg >> 24) & 0xFF;
- /* Reset the controller. */
- cpsw_reset(sc);
+ /* Get low part of MAC address from control module (mac_id[0|1]_lo) */
+ ti_scm_reg_read_4(0x630 + sc->unit * 8, &reg);
+ mac_addr[4] = reg & 0xFF;
+ mac_addr[5] = (reg >> 8) & 0xFF;
- /* Enable ALE */
- cpsw_write_4(sc, CPSW_ALE_CONTROL, 1 << 31 | 1 << 4);
+ error = mii_attach(dev, &sc->miibus, ifp, cpswp_ifmedia_upd,
+ cpswp_ifmedia_sts, BMSR_DEFCAPMASK, sc->phy, MII_OFFSET_ANY, 0);
+ if (error) {
+ device_printf(dev, "attaching PHYs failed\n");
+ cpswp_detach(dev);
+ return (error);
+ }
+ sc->mii = device_get_softc(sc->miibus);
- /* Init Sliver port 1 and 2 */
- for (i = 0; i < 2; i++) {
- /* Set Slave Mapping */
- cpsw_write_4(sc, CPSW_SL_RX_PRI_MAP(i), 0x76543210);
- cpsw_write_4(sc, CPSW_PORT_P_TX_PRI_MAP(i + 1), 0x33221100);
- cpsw_write_4(sc, CPSW_SL_RX_MAXLEN(i), 0x5f2);
- /* Set MACCONTROL for ports 0,1: IFCTL_B(16), IFCTL_A(15),
- GMII_EN(5), FULLDUPLEX(1) */
- /* TODO: Docs claim that IFCTL_B and IFCTL_A do the same thing? */
- /* Huh? Docs call bit 0 "Loopback" some places, "FullDuplex" others. */
- cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), 1 << 15 | 1 << 5 | 1);
- }
-
- /* Set Host Port Mapping */
- cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
- cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+ /* Select PHY and enable interrupts */
+ cpsw_write_4(sc->swsc, sc->physel,
+ MDIO_PHYSEL_LINKINTENB | (sc->phy & 0x1F));
- /* Initialize ALE: all ports set to forwarding(3), initialize addrs */
- for (i = 0; i < 3; i++)
- cpsw_write_4(sc, CPSW_ALE_PORTCTL(i), 3);
- cpsw_ale_update_addresses(sc, 1);
+ ether_ifattach(sc->ifp, mac_addr);
+ callout_init(&sc->mii_callout, 0);
- cpsw_write_4(sc, CPSW_SS_PTYPE, 0);
+ return (0);
+}
- /* Enable statistics for ports 0, 1 and 2 */
- cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7);
+static int
+cpswp_detach(device_t dev)
+{
+ struct cpswp_softc *sc;
- /* Experiment: Turn off flow control */
- /* This seems to fix the watchdog resets that have plagued
- earlier versions of this driver; I'm not yet sure if there
- are negative effects yet. */
- cpsw_write_4(sc, CPSW_SS_FLOW_CONTROL, 0);
+ sc = device_get_softc(dev);
+ CPSWP_DEBUGF(sc, (""));
+ if (device_is_attached(dev)) {
+ ether_ifdetach(sc->ifp);
+ CPSW_PORT_LOCK(sc);
+ cpswp_stop_locked(sc);
+ CPSW_PORT_UNLOCK(sc);
+ callout_drain(&sc->mii_callout);
+ }
- /* Make IP hdr aligned with 4 */
- cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, 2);
+ bus_generic_detach(dev);
- /* Initialize RX Buffer Descriptors */
- cpsw_write_4(sc, CPSW_CPDMA_RX_FREEBUFFER(0), 0);
+ if_free(sc->ifp);
+ mtx_destroy(&sc->lock);
- /* Enable TX & RX DMA */
- cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1);
- cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1);
+ return (0);
+}
- /* Enable Interrupts for core 0 */
- cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(0), 0xFF);
- cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0xFF);
- cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x3F);
+/*
+ *
+ * Init/Shutdown.
+ *
+ */
- /* Enable host Error Interrupt */
- cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 3);
+static int
+cpsw_ports_down(struct cpsw_softc *sc)
+{
+ struct cpswp_softc *psc;
+ struct ifnet *ifp1, *ifp2;
+
+ if (!sc->dualemac)
+ return (1);
+ psc = device_get_softc(sc->port[0].dev);
+ ifp1 = psc->ifp;
+ psc = device_get_softc(sc->port[1].dev);
+ ifp2 = psc->ifp;
+ if ((ifp1->if_flags & IFF_UP) == 0 && (ifp2->if_flags & IFF_UP) == 0)
+ return (1);
- /* Enable interrupts for RX Channel 0 */
- cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1);
+ return (0);
+}
- /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
- /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
- cpsw_write_4(sc, MDIOCONTROL, 1 << 30 | 1 << 18 | 0xFF);
+static void
+cpswp_init(void *arg)
+{
+ struct cpswp_softc *sc = arg;
- /* Select MII in GMII_SEL, Internal Delay mode */
- //ti_scm_reg_write_4(0x650, 0);
+ CPSWP_DEBUGF(sc, (""));
+ CPSW_PORT_LOCK(sc);
+ cpswp_init_locked(arg);
+ CPSW_PORT_UNLOCK(sc);
+}
- /* Initialize active queues. */
- slot = STAILQ_FIRST(&sc->tx.active);
- if (slot != NULL)
- cpsw_write_hdp_slot(sc, &sc->tx, slot);
- slot = STAILQ_FIRST(&sc->rx.active);
- if (slot != NULL)
- cpsw_write_hdp_slot(sc, &sc->rx, slot);
- cpsw_rx_enqueue(sc);
+static void
+cpswp_init_locked(void *arg)
+{
+ struct cpswp_softc *sc = arg;
+ struct ifnet *ifp;
+ uint32_t reg;
- /* Activate network interface */
- sc->rx.running = 1;
- sc->tx.running = 1;
- sc->watchdog.timer = 0;
- callout_reset(&sc->watchdog.callout, hz, cpsw_tick, sc);
- sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
- sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ CPSWP_DEBUGF(sc, (""));
+ CPSW_PORT_LOCK_ASSERT(sc);
+ ifp = sc->ifp;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ return;
+ getbinuptime(&sc->init_uptime);
+
+ if (!sc->swsc->rx.running && !sc->swsc->tx.running) {
+ /* Reset the controller. */
+ cpsw_reset(sc->swsc);
+ cpsw_init(sc->swsc);
+ }
+
+ /* Set Slave Mapping. */
+ cpsw_write_4(sc->swsc, CPSW_SL_RX_PRI_MAP(sc->unit), 0x76543210);
+ cpsw_write_4(sc->swsc, CPSW_PORT_P_TX_PRI_MAP(sc->unit + 1),
+ 0x33221100);
+ cpsw_write_4(sc->swsc, CPSW_SL_RX_MAXLEN(sc->unit), 0x5f2);
+ /* Enable MAC RX/TX modules. */
+ /* TODO: Docs claim that IFCTL_B and IFCTL_A do the same thing? */
+ /* Huh? Docs call bit 0 "Loopback" some places, "FullDuplex" others. */
+ reg = cpsw_read_4(sc->swsc, CPSW_SL_MACCONTROL(sc->unit));
+ reg |= CPSW_SL_MACTL_GMII_ENABLE;
+ cpsw_write_4(sc->swsc, CPSW_SL_MACCONTROL(sc->unit), reg);
+
+ /* Initialize ALE: set port to forwarding(3), initialize addrs */
+ cpsw_write_4(sc->swsc, CPSW_ALE_PORTCTL(sc->unit + 1), 3);
+ cpswp_ale_update_addresses(sc, 1);
+
+ if (sc->swsc->dualemac) {
+ /* Set Port VID. */
+ cpsw_write_4(sc->swsc, CPSW_PORT_P_VLAN(sc->unit + 1),
+ sc->vlan & 0xfff);
+ cpsw_ale_update_vlan_table(sc->swsc, sc->vlan,
+ (1 << (sc->unit + 1)) | (1 << 0), /* Member list */
+ (1 << (sc->unit + 1)) | (1 << 0), /* Untagged egress */
+ (1 << (sc->unit + 1)) | (1 << 0), 0); /* mcast reg flood */
+ }
+
+ mii_mediachg(sc->mii);
+ callout_reset(&sc->mii_callout, hz, cpswp_tick, sc);
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
}
static int
cpsw_shutdown(device_t dev)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpsw_softc *sc;
+ struct cpswp_softc *psc;
+ int i;
+
+ sc = device_get_softc(dev);
+ CPSW_DEBUGF(sc, (""));
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ psc = device_get_softc(sc->port[i].dev);
+ CPSW_PORT_LOCK(psc);
+ cpswp_stop_locked(psc);
+ CPSW_PORT_UNLOCK(psc);
+ }
- CPSW_DEBUGF((""));
- CPSW_GLOBAL_LOCK(sc);
- cpsw_shutdown_locked(sc);
- CPSW_GLOBAL_UNLOCK(sc);
return (0);
}
static void
cpsw_rx_teardown_locked(struct cpsw_softc *sc)
{
+ struct ifnet *ifp;
struct mbuf *received, *next;
int i = 0;
- CPSW_DEBUGF(("starting RX teardown"));
+ CPSW_DEBUGF(sc, ("starting RX teardown"));
cpsw_write_4(sc, CPSW_CPDMA_RX_TEARDOWN, 0);
for (;;) {
received = cpsw_rx_dequeue(sc);
@@ -1012,16 +1196,20 @@ cpsw_rx_teardown_locked(struct cpsw_softc *sc)
while (received != NULL) {
next = received->m_nextpkt;
received->m_nextpkt = NULL;
- (*sc->ifp->if_input)(sc->ifp, received);
+ ifp = received->m_pkthdr.rcvif;
+ (*ifp->if_input)(ifp, received);
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
received = next;
}
CPSW_GLOBAL_LOCK(sc);
if (!sc->rx.running) {
- CPSW_DEBUGF(("finished RX teardown (%d retries)", i));
+ CPSW_DEBUGF(sc,
+ ("finished RX teardown (%d retries)", i));
return;
}
if (++i > 10) {
- if_printf(sc->ifp, "Unable to cleanly shutdown receiver\n");
+ device_printf(sc->dev,
+ "Unable to cleanly shutdown receiver\n");
return;
}
DELAY(10);
@@ -1033,27 +1221,30 @@ cpsw_tx_teardown_locked(struct cpsw_softc *sc)
{
int i = 0;
- CPSW_DEBUGF(("starting TX teardown"));
+ CPSW_DEBUGF(sc, ("starting TX teardown"));
cpsw_write_4(sc, CPSW_CPDMA_TX_TEARDOWN, 0);
cpsw_tx_dequeue(sc);
while (sc->tx.running && ++i < 10) {
DELAY(10);
cpsw_tx_dequeue(sc);
}
- if (sc->tx.running)
- if_printf(sc->ifp, "Unable to cleanly shutdown transmitter\n");
- CPSW_DEBUGF(("finished TX teardown (%d retries, %d idle buffers)",
+ if (sc->tx.running) {
+ device_printf(sc->dev,
+ "Unable to cleanly shutdown transmitter\n");
+ }
+ CPSW_DEBUGF(sc, ("finished TX teardown (%d retries, %d idle buffers)",
i, sc->tx.active_queue_len));
}
static void
-cpsw_shutdown_locked(struct cpsw_softc *sc)
+cpswp_stop_locked(struct cpswp_softc *sc)
{
struct ifnet *ifp;
+ uint32_t reg;
- CPSW_DEBUGF((""));
- CPSW_GLOBAL_LOCK_ASSERT(sc);
ifp = sc->ifp;
+ CPSWP_DEBUGF(sc, (""));
+ CPSW_PORT_LOCK_ASSERT(sc);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
@@ -1063,16 +1254,28 @@ cpsw_shutdown_locked(struct cpsw_softc *sc)
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
/* Stop ticker */
- callout_stop(&sc->watchdog.callout);
+ callout_stop(&sc->mii_callout);
/* Tear down the RX/TX queues. */
- cpsw_rx_teardown_locked(sc);
- cpsw_tx_teardown_locked(sc);
+ if (cpsw_ports_down(sc->swsc)) {
+ CPSW_GLOBAL_LOCK(sc->swsc);
+ cpsw_rx_teardown_locked(sc->swsc);
+ cpsw_tx_teardown_locked(sc->swsc);
+ CPSW_GLOBAL_UNLOCK(sc->swsc);
+ }
- /* Capture stats before we reset controller. */
- cpsw_stats_collect(sc);
+ /* Stop MAC RX/TX modules. */
+ reg = cpsw_read_4(sc->swsc, CPSW_SL_MACCONTROL(sc->unit));
+ reg &= ~CPSW_SL_MACTL_GMII_ENABLE;
+ cpsw_write_4(sc->swsc, CPSW_SL_MACCONTROL(sc->unit), reg);
- cpsw_reset(sc);
+ if (cpsw_ports_down(sc->swsc)) {
+ /* Capture stats before we reset controller. */
+ cpsw_stats_collect(sc->swsc);
+
+ cpsw_reset(sc->swsc);
+ cpsw_init(sc->swsc);
+ }
}
/*
@@ -1082,21 +1285,32 @@ cpsw_shutdown_locked(struct cpsw_softc *sc)
static int
cpsw_suspend(device_t dev)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpsw_softc *sc;
+ struct cpswp_softc *psc;
+ int i;
+
+ sc = device_get_softc(dev);
+ CPSW_DEBUGF(sc, (""));
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ psc = device_get_softc(sc->port[i].dev);
+ CPSW_PORT_LOCK(psc);
+ cpswp_stop_locked(psc);
+ CPSW_PORT_UNLOCK(psc);
+ }
- CPSW_DEBUGF((""));
- CPSW_GLOBAL_LOCK(sc);
- cpsw_shutdown_locked(sc);
- CPSW_GLOBAL_UNLOCK(sc);
return (0);
}
static int
cpsw_resume(device_t dev)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpsw_softc *sc;
+
+ sc = device_get_softc(dev);
+ CPSW_DEBUGF(sc, ("UNIMPLEMENTED"));
- CPSW_DEBUGF(("UNIMPLEMENTED"));
return (0);
}
@@ -1107,32 +1321,26 @@ cpsw_resume(device_t dev)
*/
static void
-cpsw_set_promisc(struct cpsw_softc *sc, int set)
+cpsw_set_promisc(struct cpswp_softc *sc, int set)
{
+ uint32_t reg;
+
/*
- * Enabling promiscuous mode requires two bits of work: First,
- * ALE_BYPASS needs to be enabled. That disables the ALE
- * forwarding logic and causes every packet to be sent to the
- * host port. That makes us promiscuous wrt received packets.
- *
- * With ALE forwarding disabled, the transmitter needs to set
- * an explicit output port on every packet to route it to the
- * correct egress. This should be doable for systems such as
- * BeagleBone where only one egress port is actually wired to
- * a PHY. If you have both egress ports wired up, life gets a
- * lot more interesting.
- *
- * Hmmm.... NetBSD driver uses ALE_BYPASS always and doesn't
- * seem to set explicit egress ports. Does that mean they
- * are always promiscuous?
+ * Enabling promiscuous mode requires ALE_BYPASS to be enabled.
+ * That disables the ALE forwarding logic and causes every
+ * packet to be sent only to the host port. In bypass mode,
+ * the ALE processes host port transmit packets the same as in
+ * normal mode.
*/
- if (set) {
- printf("Promiscuous mode unimplemented\n");
- }
+ reg = cpsw_read_4(sc->swsc, CPSW_ALE_CONTROL);
+ reg &= ~CPSW_ALE_CTL_BYPASS;
+ if (set)
+ reg |= CPSW_ALE_CTL_BYPASS;
+ cpsw_write_4(sc->swsc, CPSW_ALE_CONTROL, reg);
}
static void
-cpsw_set_allmulti(struct cpsw_softc *sc, int set)
+cpsw_set_allmulti(struct cpswp_softc *sc, int set)
{
if (set) {
printf("All-multicast mode unimplemented\n");
@@ -1140,22 +1348,26 @@ cpsw_set_allmulti(struct cpsw_softc *sc, int set)
}
static int
-cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+cpswp_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
{
- struct cpsw_softc *sc = ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *)data;
+ struct cpswp_softc *sc;
+ struct ifreq *ifr;
int error;
uint32_t changed;
error = 0;
+ sc = ifp->if_softc;
+ ifr = (struct ifreq *)data;
switch (command) {
case SIOCSIFFLAGS:
- CPSW_GLOBAL_LOCK(sc);
+ CPSW_PORT_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- changed = ifp->if_flags ^ sc->cpsw_if_flags;
- CPSW_DEBUGF(("SIOCSIFFLAGS: UP & RUNNING (changed=0x%x)", changed));
+ changed = ifp->if_flags ^ sc->if_flags;
+ CPSWP_DEBUGF(sc,
+ ("SIOCSIFFLAGS: UP & RUNNING (changed=0x%x)",
+ changed));
if (changed & IFF_PROMISC)
cpsw_set_promisc(sc,
ifp->if_flags & IFF_PROMISC);
@@ -1163,25 +1375,27 @@ cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
cpsw_set_allmulti(sc,
ifp->if_flags & IFF_ALLMULTI);
} else {
- CPSW_DEBUGF(("SIOCSIFFLAGS: UP but not RUNNING; starting up"));
- cpsw_init_locked(sc);
+ CPSWP_DEBUGF(sc,
+ ("SIOCSIFFLAGS: UP but not RUNNING; starting up"));
+ cpswp_init_locked(sc);
}
} else if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
- CPSW_DEBUGF(("SIOCSIFFLAGS: not UP but RUNNING; shutting down"));
- cpsw_shutdown_locked(sc);
+ CPSWP_DEBUGF(sc,
+ ("SIOCSIFFLAGS: not UP but RUNNING; shutting down"));
+ cpswp_stop_locked(sc);
}
- sc->cpsw_if_flags = ifp->if_flags;
- CPSW_GLOBAL_UNLOCK(sc);
+ sc->if_flags = ifp->if_flags;
+ CPSW_PORT_UNLOCK(sc);
break;
case SIOCADDMULTI:
- cpsw_ale_update_addresses(sc, 0);
+ cpswp_ale_update_addresses(sc, 0);
break;
case SIOCDELMULTI:
/* Ugh. DELMULTI doesn't provide the specific address
being removed, so the best we can do is remove
everything and rebuild it all. */
- cpsw_ale_update_addresses(sc, 1);
+ cpswp_ale_update_addresses(sc, 1);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
@@ -1199,41 +1413,43 @@ cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
*
*/
static int
-cpsw_miibus_ready(struct cpsw_softc *sc)
+cpswp_miibus_ready(struct cpsw_softc *sc, uint32_t reg)
{
uint32_t r, retries = CPSW_MIIBUS_RETRIES;
while (--retries) {
- r = cpsw_read_4(sc, MDIOUSERACCESS0);
- if ((r & 1 << 31) == 0)
- return 1;
+ r = cpsw_read_4(sc, reg);
+ if ((r & MDIO_PHYACCESS_GO) == 0)
+ return (1);
DELAY(CPSW_MIIBUS_DELAY);
}
- return 0;
+
+ return (0);
}
static int
-cpsw_miibus_readreg(device_t dev, int phy, int reg)
+cpswp_miibus_readreg(device_t dev, int phy, int reg)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpswp_softc *sc;
uint32_t cmd, r;
- if (!cpsw_miibus_ready(sc)) {
+ sc = device_get_softc(dev);
+ if (!cpswp_miibus_ready(sc->swsc, sc->phyaccess)) {
device_printf(dev, "MDIO not ready to read\n");
- return 0;
+ return (0);
}
/* Set GO, reg, phy */
- cmd = 1 << 31 | (reg & 0x1F) << 21 | (phy & 0x1F) << 16;
- cpsw_write_4(sc, MDIOUSERACCESS0, cmd);
+ cmd = MDIO_PHYACCESS_GO | (reg & 0x1F) << 21 | (phy & 0x1F) << 16;
+ cpsw_write_4(sc->swsc, sc->phyaccess, cmd);
- if (!cpsw_miibus_ready(sc)) {
+ if (!cpswp_miibus_ready(sc->swsc, sc->phyaccess)) {
device_printf(dev, "MDIO timed out during read\n");
- return 0;
+ return (0);
}
- r = cpsw_read_4(sc, MDIOUSERACCESS0);
- if((r & 1 << 29) == 0) {
+ r = cpsw_read_4(sc->swsc, sc->phyaccess);
+ if ((r & MDIO_PHYACCESS_ACK) == 0) {
device_printf(dev, "Failed to read from PHY.\n");
r = 0;
}
@@ -1241,60 +1457,63 @@ cpsw_miibus_readreg(device_t dev, int phy, int reg)
}
static int
-cpsw_miibus_writereg(device_t dev, int phy, int reg, int value)
+cpswp_miibus_writereg(device_t dev, int phy, int reg, int value)
{
- struct cpsw_softc *sc = device_get_softc(dev);
+ struct cpswp_softc *sc;
uint32_t cmd;
- if (!cpsw_miibus_ready(sc)) {
+ sc = device_get_softc(dev);
+ if (!cpswp_miibus_ready(sc->swsc, sc->phyaccess)) {
device_printf(dev, "MDIO not ready to write\n");
- return 0;
+ return (0);
}
/* Set GO, WRITE, reg, phy, and value */
- cmd = 3 << 30 | (reg & 0x1F) << 21 | (phy & 0x1F) << 16
- | (value & 0xFFFF);
- cpsw_write_4(sc, MDIOUSERACCESS0, cmd);
+ cmd = MDIO_PHYACCESS_GO | MDIO_PHYACCESS_WRITE |
+ (reg & 0x1F) << 21 | (phy & 0x1F) << 16 | (value & 0xFFFF);
+ cpsw_write_4(sc->swsc, sc->phyaccess, cmd);
- if (!cpsw_miibus_ready(sc)) {
+ if (!cpswp_miibus_ready(sc->swsc, sc->phyaccess)) {
device_printf(dev, "MDIO timed out during write\n");
- return 0;
+ return (0);
}
- if((cpsw_read_4(sc, MDIOUSERACCESS0) & (1 << 29)) == 0)
+ if ((cpsw_read_4(sc->swsc, sc->phyaccess) & MDIO_PHYACCESS_ACK) == 0)
device_printf(dev, "Failed to write to PHY.\n");
- return 0;
+ return (0);
}
static void
-cpsw_miibus_statchg(device_t dev)
+cpswp_miibus_statchg(device_t dev)
{
- struct cpsw_softc *sc = device_get_softc(dev);
- uint32_t mac_control;
- int i;
-
- CPSW_DEBUGF((""));
-
- for (i = 0; i < 2; i++) {
- mac_control = cpsw_read_4(sc, CPSW_SL_MACCONTROL(i));
- mac_control &= ~(1 << 15 | 1 << 7);
-
- switch(IFM_SUBTYPE(sc->mii->mii_media_active)) {
- case IFM_1000_SX:
- case IFM_1000_LX:
- case IFM_1000_CX:
- case IFM_1000_T:
- mac_control |= 1 << 7;
- break;
-
- default:
- mac_control |= 1 << 15;
- break;
- }
+ struct cpswp_softc *sc;
+ uint32_t mac_control, reg;
+
+ sc = device_get_softc(dev);
+ CPSWP_DEBUGF(sc, (""));
+
+ reg = CPSW_SL_MACCONTROL(sc->unit);
+ mac_control = cpsw_read_4(sc->swsc, reg);
+ mac_control &= ~(CPSW_SL_MACTL_GIG | CPSW_SL_MACTL_IFCTL_A |
+ CPSW_SL_MACTL_IFCTL_B | CPSW_SL_MACTL_FULLDUPLEX);
+
+ switch(IFM_SUBTYPE(sc->mii->mii_media_active)) {
+ case IFM_1000_SX:
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+ case IFM_1000_T:
+ mac_control |= CPSW_SL_MACTL_GIG;
+ break;
- cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), mac_control);
+ case IFM_100_TX:
+ mac_control |= CPSW_SL_MACTL_IFCTL_A;
+ break;
}
+ if (sc->mii->mii_media_active & IFM_FDX)
+ mac_control |= CPSW_SL_MACTL_FULLDUPLEX;
+
+ cpsw_write_4(sc->swsc, reg, mac_control);
}
/*
@@ -1302,12 +1521,11 @@ cpsw_miibus_statchg(device_t dev)
* Transmit/Receive Packets.
*
*/
-
-
static void
cpsw_intr_rx(void *arg)
{
struct cpsw_softc *sc = arg;
+ struct ifnet *ifp;
struct mbuf *received, *next;
CPSW_RX_LOCK(sc);
@@ -1319,7 +1537,9 @@ cpsw_intr_rx(void *arg)
while (received != NULL) {
next = received->m_nextpkt;
received->m_nextpkt = NULL;
- (*sc->ifp->if_input)(sc->ifp, received);
+ ifp = received->m_pkthdr.rcvif;
+ (*ifp->if_input)(ifp, received);
+ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
received = next;
}
}
@@ -1329,11 +1549,10 @@ cpsw_rx_dequeue(struct cpsw_softc *sc)
{
struct cpsw_cpdma_bd bd;
struct cpsw_slot *slot;
- struct ifnet *ifp;
+ struct cpswp_softc *psc;
struct mbuf *mb_head, *mb_tail;
- int removed = 0;
+ int port, removed = 0;
- ifp = sc->ifp;
mb_head = mb_tail = NULL;
/* Pull completed packets off hardware RX queue. */
@@ -1342,7 +1561,7 @@ cpsw_rx_dequeue(struct cpsw_softc *sc)
if (bd.flags & CPDMA_BD_OWNER)
break; /* Still in use by hardware */
- CPSW_DEBUGF(("Removing received packet from RX queue"));
+ CPSW_DEBUGF(sc, ("Removing received packet from RX queue"));
++removed;
STAILQ_REMOVE_HEAD(&sc->rx.active, next);
STAILQ_INSERT_TAIL(&sc->rx.avail, slot, next);
@@ -1351,7 +1570,7 @@ cpsw_rx_dequeue(struct cpsw_softc *sc)
bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
if (bd.flags & CPDMA_BD_TDOWNCMPLT) {
- CPSW_DEBUGF(("RX teardown in progress"));
+ CPSW_DEBUGF(sc, ("RX teardown in progress"));
m_freem(slot->mbuf);
slot->mbuf = NULL;
cpsw_write_cp(sc, &sc->rx, 0xfffffffc);
@@ -1361,6 +1580,11 @@ cpsw_rx_dequeue(struct cpsw_softc *sc)
cpsw_write_cp_slot(sc, &sc->rx, slot);
+ port = (bd.flags & CPDMA_BD_PORT_MASK) - 1;
+ KASSERT(port >= 0 && port <= 1,
+ ("patcket received with invalid port: %d", port));
+ psc = device_get_softc(sc->port[port].dev);
+
/* Set up mbuf */
/* TODO: track SOP/EOP bits to assemble a full mbuf
out of received fragments. */
@@ -1368,10 +1592,10 @@ cpsw_rx_dequeue(struct cpsw_softc *sc)
slot->mbuf->m_len = bd.pktlen - 4;
slot->mbuf->m_pkthdr.len = bd.pktlen - 4;
slot->mbuf->m_flags |= M_PKTHDR;
- slot->mbuf->m_pkthdr.rcvif = ifp;
+ slot->mbuf->m_pkthdr.rcvif = psc->ifp;
slot->mbuf->m_nextpkt = NULL;
- if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
+ if ((psc->ifp->if_capenable & IFCAP_RXCSUM) != 0) {
/* check for valid CRC by looking into pkt_err[5:4] */
if ((bd.flags & CPDMA_BD_PKT_ERR_MASK) == 0) {
slot->mbuf->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
@@ -1405,7 +1629,6 @@ cpsw_rx_enqueue(struct cpsw_softc *sc)
{
bus_dma_segment_t seg[1];
struct cpsw_cpdma_bd bd;
- struct ifnet *ifp = sc->ifp;
struct cpsw_slots tmpqueue = STAILQ_HEAD_INITIALIZER(tmpqueue);
struct cpsw_slot *slot, *prev_slot = NULL;
struct cpsw_slot *last_old_slot, *first_new_slot;
@@ -1416,7 +1639,8 @@ cpsw_rx_enqueue(struct cpsw_softc *sc)
if (slot->mbuf == NULL) {
slot->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (slot->mbuf == NULL) {
- if_printf(sc->ifp, "Unable to fill RX queue\n");
+ device_printf(sc->dev,
+ "Unable to fill RX queue\n");
break;
}
slot->mbuf->m_len =
@@ -1430,7 +1654,7 @@ cpsw_rx_enqueue(struct cpsw_softc *sc)
KASSERT(nsegs == 1, ("More than one segment (nsegs=%d)", nsegs));
KASSERT(error == 0, ("DMA error (error=%d)", error));
if (error != 0 || nsegs != 1) {
- if_printf(ifp,
+ device_printf(sc->dev,
"%s: Can't prep RX buf for DMA (nsegs=%d, error=%d)\n",
__func__, nsegs, error);
bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
@@ -1462,7 +1686,7 @@ cpsw_rx_enqueue(struct cpsw_softc *sc)
if (added == 0)
return;
- CPSW_DEBUGF(("Adding %d buffers to RX queue", added));
+ CPSW_DEBUGF(sc, ("Adding %d buffers to RX queue", added));
/* Link new entries to hardware RX queue. */
last_old_slot = STAILQ_LAST(&sc->rx.active, cpsw_slot, next);
@@ -1489,20 +1713,20 @@ cpsw_rx_enqueue(struct cpsw_softc *sc)
}
static void
-cpsw_start(struct ifnet *ifp)
+cpswp_start(struct ifnet *ifp)
{
- struct cpsw_softc *sc = ifp->if_softc;
+ struct cpswp_softc *sc = ifp->if_softc;
- CPSW_TX_LOCK(sc);
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->tx.running) {
- cpsw_tx_enqueue(sc);
- cpsw_tx_dequeue(sc);
+ CPSW_TX_LOCK(sc->swsc);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->swsc->tx.running) {
+ cpswp_tx_enqueue(sc);
+ cpsw_tx_dequeue(sc->swsc);
}
- CPSW_TX_UNLOCK(sc);
+ CPSW_TX_UNLOCK(sc->swsc);
}
static void
-cpsw_tx_enqueue(struct cpsw_softc *sc)
+cpswp_tx_enqueue(struct cpswp_softc *sc)
{
bus_dma_segment_t segs[CPSW_TXFRAGS];
struct cpsw_cpdma_bd bd;
@@ -1510,10 +1734,15 @@ cpsw_tx_enqueue(struct cpsw_softc *sc)
struct cpsw_slot *slot, *prev_slot = NULL;
struct cpsw_slot *last_old_slot, *first_new_slot;
struct mbuf *m0;
- int error, nsegs, seg, added = 0, padlen;
+ int error, flags, nsegs, seg, added = 0, padlen;
+ flags = 0;
+ if (sc->swsc->dualemac) {
+ flags = CPDMA_BD_TO_PORT |
+ ((sc->unit + 1) & CPDMA_BD_PORT_MASK);
+ }
/* Pull pending packets from IF queue and prep them for DMA. */
- while ((slot = STAILQ_FIRST(&sc->tx.avail)) != NULL) {
+ while ((slot = STAILQ_FIRST(&sc->swsc->tx.avail)) != NULL) {
IF_DEQUEUE(&sc->ifp->if_snd, m0);
if (m0 == NULL)
break;
@@ -1524,45 +1753,47 @@ cpsw_tx_enqueue(struct cpsw_softc *sc)
padlen = 0;
/* Create mapping in DMA memory */
- error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, slot->dmamap,
- slot->mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf_sg(sc->swsc->mbuf_dtag,
+ slot->dmamap, slot->mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
/* If the packet is too fragmented, try to simplify. */
if (error == EFBIG ||
(error == 0 &&
- nsegs + (padlen > 0 ? 1 : 0) > sc->tx.avail_queue_len)) {
- bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
+ nsegs + (padlen > 0 ? 1 : 0) > sc->swsc->tx.avail_queue_len)) {
+ bus_dmamap_unload(sc->swsc->mbuf_dtag, slot->dmamap);
if (padlen > 0) /* May as well add padding. */
m_append(slot->mbuf, padlen,
- sc->null_mbuf->m_data);
+ sc->swsc->null_mbuf->m_data);
m0 = m_defrag(slot->mbuf, M_NOWAIT);
if (m0 == NULL) {
- if_printf(sc->ifp,
+ device_printf(sc->dev,
"Can't defragment packet; dropping\n");
m_freem(slot->mbuf);
} else {
- CPSW_DEBUGF(("Requeueing defragmented packet"));
+ CPSWP_DEBUGF(sc,
+ ("Requeueing defragmented packet"));
IF_PREPEND(&sc->ifp->if_snd, m0);
}
slot->mbuf = NULL;
continue;
}
if (error != 0) {
- if_printf(sc->ifp,
+ device_printf(sc->dev,
"%s: Can't setup DMA (error=%d), dropping packet\n",
__func__, error);
- bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
+ bus_dmamap_unload(sc->swsc->mbuf_dtag, slot->dmamap);
m_freem(slot->mbuf);
slot->mbuf = NULL;
break;
}
- bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap,
+ bus_dmamap_sync(sc->swsc->mbuf_dtag, slot->dmamap,
BUS_DMASYNC_PREWRITE);
+ CPSWP_DEBUGF(sc,
+ ("Queueing TX packet: %d segments + %d pad bytes",
+ nsegs, padlen));
- CPSW_DEBUGF(("Queueing TX packet: %d segments + %d pad bytes",
- nsegs, padlen));
-
+ slot->ifp = sc->ifp;
/* If there is only one segment, the for() loop
* gets skipped and the single buffer gets set up
* as both SOP and EOP. */
@@ -1572,18 +1803,20 @@ cpsw_tx_enqueue(struct cpsw_softc *sc)
bd.bufoff = 0;
bd.buflen = segs[0].ds_len;
bd.pktlen = m_length(slot->mbuf, NULL) + padlen;
- bd.flags = CPDMA_BD_SOP | CPDMA_BD_OWNER;
+ bd.flags = CPDMA_BD_SOP | CPDMA_BD_OWNER | flags;
for (seg = 1; seg < nsegs; ++seg) {
/* Save the previous buffer (which isn't EOP) */
- cpsw_cpdma_write_bd(sc, slot, &bd);
- if (prev_slot != NULL)
- cpsw_cpdma_write_bd_next(sc, prev_slot, slot);
+ cpsw_cpdma_write_bd(sc->swsc, slot, &bd);
+ if (prev_slot != NULL) {
+ cpsw_cpdma_write_bd_next(sc->swsc, prev_slot,
+ slot);
+ }
prev_slot = slot;
- STAILQ_REMOVE_HEAD(&sc->tx.avail, next);
- sc->tx.avail_queue_len--;
+ STAILQ_REMOVE_HEAD(&sc->swsc->tx.avail, next);
+ sc->swsc->tx.avail_queue_len--;
STAILQ_INSERT_TAIL(&tmpqueue, slot, next);
++added;
- slot = STAILQ_FIRST(&sc->tx.avail);
+ slot = STAILQ_FIRST(&sc->swsc->tx.avail);
/* Setup next buffer (which isn't SOP) */
bd.next = 0;
@@ -1591,42 +1824,42 @@ cpsw_tx_enqueue(struct cpsw_softc *sc)
bd.bufoff = 0;
bd.buflen = segs[seg].ds_len;
bd.pktlen = 0;
- bd.flags = CPDMA_BD_OWNER;
+ bd.flags = CPDMA_BD_OWNER | flags;
}
/* Save the final buffer. */
if (padlen <= 0)
bd.flags |= CPDMA_BD_EOP;
- cpsw_cpdma_write_bd(sc, slot, &bd);
+ cpsw_cpdma_write_bd(sc->swsc, slot, &bd);
if (prev_slot != NULL)
- cpsw_cpdma_write_bd_next(sc, prev_slot, slot);
+ cpsw_cpdma_write_bd_next(sc->swsc, prev_slot, slot);
prev_slot = slot;
- STAILQ_REMOVE_HEAD(&sc->tx.avail, next);
- sc->tx.avail_queue_len--;
+ STAILQ_REMOVE_HEAD(&sc->swsc->tx.avail, next);
+ sc->swsc->tx.avail_queue_len--;
STAILQ_INSERT_TAIL(&tmpqueue, slot, next);
++added;
if (padlen > 0) {
- slot = STAILQ_FIRST(&sc->tx.avail);
- STAILQ_REMOVE_HEAD(&sc->tx.avail, next);
- sc->tx.avail_queue_len--;
+ slot = STAILQ_FIRST(&sc->swsc->tx.avail);
+ STAILQ_REMOVE_HEAD(&sc->swsc->tx.avail, next);
+ sc->swsc->tx.avail_queue_len--;
STAILQ_INSERT_TAIL(&tmpqueue, slot, next);
++added;
/* Setup buffer of null pad bytes (definitely EOP) */
- cpsw_cpdma_write_bd_next(sc, prev_slot, slot);
+ cpsw_cpdma_write_bd_next(sc->swsc, prev_slot, slot);
prev_slot = slot;
bd.next = 0;
- bd.bufptr = sc->null_mbuf_paddr;
+ bd.bufptr = sc->swsc->null_mbuf_paddr;
bd.bufoff = 0;
bd.buflen = padlen;
bd.pktlen = 0;
- bd.flags = CPDMA_BD_EOP | CPDMA_BD_OWNER;
- cpsw_cpdma_write_bd(sc, slot, &bd);
+ bd.flags = CPDMA_BD_EOP | CPDMA_BD_OWNER | flags;
+ cpsw_cpdma_write_bd(sc->swsc, slot, &bd);
++nsegs;
}
- if (nsegs > sc->tx.longest_chain)
- sc->tx.longest_chain = nsegs;
+ if (nsegs > sc->swsc->tx.longest_chain)
+ sc->swsc->tx.longest_chain = nsegs;
// TODO: Should we defer the BPF tap until
// after all packets are queued?
@@ -1634,26 +1867,29 @@ cpsw_tx_enqueue(struct cpsw_softc *sc)
}
/* Attach the list of new buffers to the hardware TX queue. */
- last_old_slot = STAILQ_LAST(&sc->tx.active, cpsw_slot, next);
+ last_old_slot = STAILQ_LAST(&sc->swsc->tx.active, cpsw_slot, next);
first_new_slot = STAILQ_FIRST(&tmpqueue);
- STAILQ_CONCAT(&sc->tx.active, &tmpqueue);
+ STAILQ_CONCAT(&sc->swsc->tx.active, &tmpqueue);
if (first_new_slot == NULL) {
return;
} else if (last_old_slot == NULL) {
/* Start a fresh queue. */
- cpsw_write_hdp_slot(sc, &sc->tx, first_new_slot);
+ cpsw_write_hdp_slot(sc->swsc, &sc->swsc->tx, first_new_slot);
} else {
/* Add buffers to end of current queue. */
- cpsw_cpdma_write_bd_next(sc, last_old_slot, first_new_slot);
+ cpsw_cpdma_write_bd_next(sc->swsc, last_old_slot,
+ first_new_slot);
/* If underrun, restart queue. */
- if (cpsw_cpdma_read_bd_flags(sc, last_old_slot) & CPDMA_BD_EOQ) {
- cpsw_write_hdp_slot(sc, &sc->tx, first_new_slot);
+ if (cpsw_cpdma_read_bd_flags(sc->swsc, last_old_slot) &
+ CPDMA_BD_EOQ) {
+ cpsw_write_hdp_slot(sc->swsc, &sc->swsc->tx,
+ first_new_slot);
}
}
- sc->tx.queue_adds += added;
- sc->tx.active_queue_len += added;
- if (sc->tx.active_queue_len > sc->tx.max_active_queue_len) {
- sc->tx.max_active_queue_len = sc->tx.active_queue_len;
+ sc->swsc->tx.queue_adds += added;
+ sc->swsc->tx.active_queue_len += added;
+ if (sc->swsc->tx.active_queue_len > sc->swsc->tx.max_active_queue_len) {
+ sc->swsc->tx.max_active_queue_len = sc->swsc->tx.active_queue_len;
}
}
@@ -1665,7 +1901,7 @@ cpsw_tx_dequeue(struct cpsw_softc *sc)
slot = STAILQ_FIRST(&sc->tx.active);
if (slot == NULL && cpsw_read_cp(sc, &sc->tx) == 0xfffffffc) {
- CPSW_DEBUGF(("TX teardown of an empty queue"));
+ CPSW_DEBUGF(sc, ("TX teardown of an empty queue"));
cpsw_write_cp(sc, &sc->tx, 0xfffffffc);
sc->tx.running = 0;
return (0);
@@ -1677,11 +1913,13 @@ cpsw_tx_dequeue(struct cpsw_softc *sc)
if (flags & CPDMA_BD_OWNER)
break; /* Hardware is still using this packet. */
- CPSW_DEBUGF(("TX removing completed packet"));
+ CPSW_DEBUGF(sc, ("TX removing completed packet"));
bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap);
m_freem(slot->mbuf);
slot->mbuf = NULL;
+ if (slot->ifp)
+ if_inc_counter(slot->ifp, IFCOUNTER_OPACKETS, 1);
/* Dequeue any additional buffers used by this packet. */
while (slot != NULL && slot->mbuf == NULL) {
@@ -1694,7 +1932,7 @@ cpsw_tx_dequeue(struct cpsw_softc *sc)
/* TearDown complete is only marked on the SOP for the packet. */
if (flags & CPDMA_BD_TDOWNCMPLT) {
- CPSW_DEBUGF(("TX teardown in progress"));
+ CPSW_DEBUGF(sc, ("TX teardown in progress"));
cpsw_write_cp(sc, &sc->tx, 0xfffffffc);
// TODO: Increment a count of dropped TX packets
sc->tx.running = 0;
@@ -1725,7 +1963,7 @@ cpsw_intr_rx_thresh(void *arg)
struct cpsw_softc *sc = arg;
uint32_t stat = cpsw_read_4(sc, CPSW_WR_C_RX_THRESH_STAT(0));
- CPSW_DEBUGF(("stat=%x", stat));
+ CPSW_DEBUGF(sc, ("stat=%x", stat));
cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, 0);
}
@@ -1817,16 +2055,20 @@ cpsw_intr_misc(void *arg)
struct cpsw_softc *sc = arg;
uint32_t stat = cpsw_read_4(sc, CPSW_WR_C_MISC_STAT(0));
- if (stat & 16)
- CPSW_DEBUGF(("Time sync event interrupt unimplemented"));
- if (stat & 8)
+ if (stat & CPSW_WR_C_MISC_EVNT_PEND)
+ CPSW_DEBUGF(sc, ("Time sync event interrupt unimplemented"));
+ if (stat & CPSW_WR_C_MISC_STAT_PEND)
cpsw_stats_collect(sc);
- if (stat & 4)
+ if (stat & CPSW_WR_C_MISC_HOST_PEND)
cpsw_intr_misc_host_error(sc);
- if (stat & 2)
- CPSW_DEBUGF(("MDIO link change interrupt unimplemented"));
- if (stat & 1)
- CPSW_DEBUGF(("MDIO operation completed interrupt unimplemented"));
+ if (stat & CPSW_WR_C_MISC_MDIOLINK) {
+ cpsw_write_4(sc, MDIOLINKINTMASKED,
+ cpsw_read_4(sc, MDIOLINKINTMASKED));
+ }
+ if (stat & CPSW_WR_C_MISC_MDIOUSER) {
+ CPSW_DEBUGF(sc,
+ ("MDIO operation completed interrupt unimplemented"));
+ }
cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
}
@@ -1837,56 +2079,51 @@ cpsw_intr_misc(void *arg)
*/
static void
-cpsw_tick(void *msc)
+cpswp_tick(void *msc)
{
- struct cpsw_softc *sc = msc;
-
- /* Check for TX timeout */
- cpsw_tx_watchdog(sc);
+ struct cpswp_softc *sc = msc;
/* Check for media type change */
mii_tick(sc->mii);
- if(sc->cpsw_media_status != sc->mii->mii_media.ifm_media) {
+ if (sc->media_status != sc->mii->mii_media.ifm_media) {
printf("%s: media type changed (ifm_media=%x)\n", __func__,
sc->mii->mii_media.ifm_media);
- cpsw_ifmedia_upd(sc->ifp);
+ cpswp_ifmedia_upd(sc->ifp);
}
/* Schedule another timeout one second from now */
- callout_reset(&sc->watchdog.callout, hz, cpsw_tick, sc);
+ callout_reset(&sc->mii_callout, hz, cpswp_tick, sc);
}
static void
-cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+cpswp_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
{
- struct cpsw_softc *sc = ifp->if_softc;
+ struct cpswp_softc *sc;
struct mii_data *mii;
- CPSW_DEBUGF((""));
- CPSW_TX_LOCK(sc);
+ sc = ifp->if_softc;
+ CPSWP_DEBUGF(sc, (""));
+ CPSW_PORT_LOCK(sc);
mii = sc->mii;
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
-
- CPSW_TX_UNLOCK(sc);
+ CPSW_PORT_UNLOCK(sc);
}
static int
-cpsw_ifmedia_upd(struct ifnet *ifp)
+cpswp_ifmedia_upd(struct ifnet *ifp)
{
- struct cpsw_softc *sc = ifp->if_softc;
+ struct cpswp_softc *sc;
- CPSW_DEBUGF((""));
- if (ifp->if_flags & IFF_UP) {
- CPSW_GLOBAL_LOCK(sc);
- sc->cpsw_media_status = sc->mii->mii_media.ifm_media;
- mii_mediachg(sc->mii);
- cpsw_init_locked(sc);
- CPSW_GLOBAL_UNLOCK(sc);
- }
+ sc = ifp->if_softc;
+ CPSWP_DEBUGF(sc, (""));
+ CPSW_PORT_LOCK(sc);
+ mii_mediachg(sc->mii);
+ sc->media_status = sc->mii->mii_media.ifm_media;
+ CPSW_PORT_UNLOCK(sc);
return (0);
}
@@ -1894,20 +2131,29 @@ cpsw_ifmedia_upd(struct ifnet *ifp)
static void
cpsw_tx_watchdog_full_reset(struct cpsw_softc *sc)
{
+ struct cpswp_softc *psc;
+ int i;
+
cpsw_debugf_head("CPSW watchdog");
- if_printf(sc->ifp, "watchdog timeout\n");
- cpsw_shutdown_locked(sc);
- cpsw_init_locked(sc);
+ device_printf(sc->dev, "watchdog timeout\n");
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ psc = device_get_softc(sc->port[i].dev);
+ CPSW_PORT_LOCK(psc);
+ cpswp_stop_locked(psc);
+ CPSW_PORT_UNLOCK(psc);
+ }
}
static void
-cpsw_tx_watchdog(struct cpsw_softc *sc)
+cpsw_tx_watchdog(void *msc)
{
- struct ifnet *ifp = sc->ifp;
+ struct cpsw_softc *sc;
+ sc = msc;
CPSW_GLOBAL_LOCK(sc);
- if (sc->tx.active_queue_len == 0 || (ifp->if_flags & IFF_UP) == 0 ||
- (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !sc->tx.running) {
+ if (sc->tx.active_queue_len == 0 || !sc->tx.running) {
sc->watchdog.timer = 0; /* Nothing to do. */
} else if (sc->tx.queue_removes > sc->tx.queue_removes_at_last_tick) {
sc->watchdog.timer = 0; /* Stuff done while we weren't looking. */
@@ -1916,15 +2162,17 @@ cpsw_tx_watchdog(struct cpsw_softc *sc)
} else {
/* There was something to do but it didn't get done. */
++sc->watchdog.timer;
- if (sc->watchdog.timer > 2) {
+ if (sc->watchdog.timer > 5) {
sc->watchdog.timer = 0;
- if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
++sc->watchdog.resets;
cpsw_tx_watchdog_full_reset(sc);
}
}
sc->tx.queue_removes_at_last_tick = sc->tx.queue_removes;
CPSW_GLOBAL_UNLOCK(sc);
+
+ /* Schedule another timeout one second from now */
+ callout_reset(&sc->watchdog.callout, hz, cpsw_tx_watchdog, sc);
}
/*
@@ -1951,38 +2199,38 @@ cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
cpsw_write_4(sc, CPSW_ALE_TBLCTL, 1 << 31 | (idx & 1023));
}
-static int
+static void
cpsw_ale_remove_all_mc_entries(struct cpsw_softc *sc)
{
int i;
uint32_t ale_entry[3];
- /* First two entries are link address and broadcast. */
- for (i = 2; i < CPSW_MAX_ALE_ENTRIES; i++) {
+ /* First four entries are link address and broadcast. */
+ for (i = 10; i < CPSW_MAX_ALE_ENTRIES; i++) {
cpsw_ale_read_entry(sc, i, ale_entry);
- if (((ale_entry[1] >> 28) & 3) == 1 && /* Address entry */
- ((ale_entry[1] >> 8) & 1) == 1) { /* MCast link addr */
+ if ((ALE_TYPE(ale_entry) == ALE_TYPE_ADDR ||
+ ALE_TYPE(ale_entry) == ALE_TYPE_VLAN_ADDR) &&
+ ALE_MCAST(ale_entry) == 1) { /* MCast link addr */
ale_entry[0] = ale_entry[1] = ale_entry[2] = 0;
cpsw_ale_write_entry(sc, i, ale_entry);
}
}
- return CPSW_MAX_ALE_ENTRIES;
}
static int
-cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac)
+cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, int vlan,
+ uint8_t *mac)
{
int free_index = -1, matching_index = -1, i;
- uint32_t ale_entry[3];
+ uint32_t ale_entry[3], ale_type;
/* Find a matching entry or a free entry. */
- for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) {
+ for (i = 10; i < CPSW_MAX_ALE_ENTRIES; i++) {
cpsw_ale_read_entry(sc, i, ale_entry);
/* Entry Type[61:60] is 0 for free entry */
- if (free_index < 0 && ((ale_entry[1] >> 28) & 3) == 0) {
+ if (free_index < 0 && ALE_TYPE(ale_entry) == 0)
free_index = i;
- }
if ((((ale_entry[1] >> 8) & 0xFF) == mac[0]) &&
(((ale_entry[1] >> 0) & 0xFF) == mac[1]) &&
@@ -2001,12 +2249,17 @@ cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac)
i = free_index;
}
+ if (vlan != -1)
+ ale_type = ALE_TYPE_VLAN_ADDR << 28 | vlan << 16;
+ else
+ ale_type = ALE_TYPE_ADDR << 28;
+
/* Set MAC address */
ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
ale_entry[1] = mac[0] << 8 | mac[1];
- /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/
- ale_entry[1] |= 0xd0 << 24;
+ /* Entry type[61:60] and Mcast fwd state[63:62] is fw(3). */
+ ale_entry[1] |= ALE_MCAST_FWD | ale_type;
/* Set portmask [68:66] */
ale_entry[2] = (portmap & 7) << 2;
@@ -2022,9 +2275,23 @@ cpsw_ale_dump_table(struct cpsw_softc *sc) {
uint32_t ale_entry[3];
for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) {
cpsw_ale_read_entry(sc, i, ale_entry);
- if (ale_entry[0] || ale_entry[1] || ale_entry[2]) {
- printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[0],
- ale_entry[1], ale_entry[2]);
+ switch (ALE_TYPE(ale_entry)) {
+ case ALE_TYPE_VLAN:
+ printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[2],
+ ale_entry[1], ale_entry[0]);
+ printf("type: %u ", ALE_TYPE(ale_entry));
+ printf("vlan: %u ", ALE_VLAN(ale_entry));
+ printf("untag: %u ", ALE_VLAN_UNTAG(ale_entry));
+ printf("reg flood: %u ", ALE_VLAN_REGFLOOD(ale_entry));
+ printf("unreg flood: %u ", ALE_VLAN_UNREGFLOOD(ale_entry));
+ printf("members: %u ", ALE_VLAN_MEMBERS(ale_entry));
+ printf("\n");
+ break;
+ case ALE_TYPE_ADDR:
+ case ALE_TYPE_VLAN_ADDR:
+ printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[2],
+ ale_entry[1], ale_entry[0]);
+ printf("type: %u ", ALE_TYPE(ale_entry));
printf("mac: %02x:%02x:%02x:%02x:%02x:%02x ",
(ale_entry[1] >> 8) & 0xFF,
(ale_entry[1] >> 0) & 0xFF,
@@ -2032,62 +2299,109 @@ cpsw_ale_dump_table(struct cpsw_softc *sc) {
(ale_entry[0] >>16) & 0xFF,
(ale_entry[0] >> 8) & 0xFF,
(ale_entry[0] >> 0) & 0xFF);
- printf(((ale_entry[1] >> 8) & 1) ? "mcast " : "ucast ");
- printf("type: %u ", (ale_entry[1] >> 28) & 3);
- printf("port: %u ", (ale_entry[2] >> 2) & 7);
+ printf(ALE_MCAST(ale_entry) ? "mcast " : "ucast ");
+ if (ALE_TYPE(ale_entry) == ALE_TYPE_VLAN_ADDR)
+ printf("vlan: %u ", ALE_VLAN(ale_entry));
+ printf("port: %u ", ALE_PORTS(ale_entry));
printf("\n");
+ break;
}
}
printf("\n");
}
static int
-cpsw_ale_update_addresses(struct cpsw_softc *sc, int purge)
+cpswp_ale_update_addresses(struct cpswp_softc *sc, int purge)
{
uint8_t *mac;
- uint32_t ale_entry[3];
- struct ifnet *ifp = sc->ifp;
+ uint32_t ale_entry[3], ale_type, portmask;
struct ifmultiaddr *ifma;
- int i;
- /* Route incoming packets for our MAC address to Port 0 (host). */
- /* For simplicity, keep this entry at table index 0 in the ALE. */
- if_addr_rlock(ifp);
- mac = LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr);
+ if (sc->swsc->dualemac) {
+ ale_type = ALE_TYPE_VLAN_ADDR << 28 | sc->vlan << 16;
+ portmask = 1 << (sc->unit + 1) | 1 << 0;
+ } else {
+ ale_type = ALE_TYPE_ADDR << 28;
+ portmask = 7;
+ }
+
+ /*
+ * Route incoming packets for our MAC address to Port 0 (host).
+ * For simplicity, keep this entry at table index 0 for port 1 and
+ * at index 2 for port 2 in the ALE.
+ */
+ if_addr_rlock(sc->ifp);
+ mac = LLADDR((struct sockaddr_dl *)sc->ifp->if_addr->ifa_addr);
ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
- ale_entry[1] = 0x10 << 24 | mac[0] << 8 | mac[1]; /* addr entry + mac */
+ ale_entry[1] = ale_type | mac[0] << 8 | mac[1]; /* addr entry + mac */
ale_entry[2] = 0; /* port = 0 */
- cpsw_ale_write_entry(sc, 0, ale_entry);
+ cpsw_ale_write_entry(sc->swsc, 0 + 2 * sc->unit, ale_entry);
- /* Set outgoing MAC Address for Ports 1 and 2. */
- for (i = 1; i < 3; ++i) {
- cpsw_write_4(sc, CPSW_PORT_P_SA_HI(i),
- mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]);
- cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i),
- mac[5] << 8 | mac[4]);
- }
- if_addr_runlock(ifp);
+ /* Set outgoing MAC Address for slave port. */
+ cpsw_write_4(sc->swsc, CPSW_PORT_P_SA_HI(sc->unit + 1),
+ mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]);
+ cpsw_write_4(sc->swsc, CPSW_PORT_P_SA_LO(sc->unit + 1),
+ mac[5] << 8 | mac[4]);
+ if_addr_runlock(sc->ifp);
- /* Keep the broadcast address at table entry 1. */
+ /* Keep the broadcast address at table entry 1 (or 3). */
ale_entry[0] = 0xffffffff; /* Lower 32 bits of MAC */
- ale_entry[1] = 0xd000ffff; /* FW (3 << 30), Addr entry (1 << 24), upper 16 bits of Mac */
- ale_entry[2] = 0x0000001c; /* Forward to all ports */
- cpsw_ale_write_entry(sc, 1, ale_entry);
+ /* ALE_MCAST_FWD, Addr type, upper 16 bits of Mac */
+ ale_entry[1] = ALE_MCAST_FWD | ale_type | 0xffff;
+ ale_entry[2] = portmask << 2;
+ cpsw_ale_write_entry(sc->swsc, 1 + 2 * sc->unit, ale_entry);
/* SIOCDELMULTI doesn't specify the particular address
being removed, so we have to remove all and rebuild. */
if (purge)
- cpsw_ale_remove_all_mc_entries(sc);
+ cpsw_ale_remove_all_mc_entries(sc->swsc);
/* Set other multicast addrs desired. */
- if_maddr_rlock(ifp);
- TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if_maddr_rlock(sc->ifp);
+ TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
- cpsw_ale_mc_entry_set(sc, 7,
+ cpsw_ale_mc_entry_set(sc->swsc, portmask, sc->vlan,
LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
}
- if_maddr_runlock(ifp);
+ if_maddr_runlock(sc->ifp);
+
+ return (0);
+}
+
+static int
+cpsw_ale_update_vlan_table(struct cpsw_softc *sc, int vlan, int ports,
+ int untag, int mcregflood, int mcunregflood)
+{
+ int free_index, i, matching_index;
+ uint32_t ale_entry[3];
+
+ free_index = matching_index = -1;
+ /* Find a matching entry or a free entry. */
+ for (i = 5; i < CPSW_MAX_ALE_ENTRIES; i++) {
+ cpsw_ale_read_entry(sc, i, ale_entry);
+
+ /* Entry Type[61:60] is 0 for free entry */
+ if (free_index < 0 && ALE_TYPE(ale_entry) == 0)
+ free_index = i;
+
+ if (ALE_VLAN(ale_entry) == vlan) {
+ matching_index = i;
+ break;
+ }
+ }
+
+ if (matching_index < 0) {
+ if (free_index < 0)
+ return (-1);
+ i = free_index;
+ }
+
+ ale_entry[0] = (untag & 7) << 24 | (mcregflood & 7) << 16 |
+ (mcunregflood & 7) << 8 | (ports & 7);
+ ale_entry[1] = ALE_TYPE_VLAN << 28 | vlan << 16;
+ ale_entry[2] = 0;
+ cpsw_ale_write_entry(sc, i, ale_entry);
return (0);
}
@@ -2108,9 +2422,9 @@ cpsw_stats_dump(struct cpsw_softc *sc)
for (i = 0; i < CPSW_SYSCTL_COUNT; ++i) {
r = cpsw_read_4(sc, CPSW_STATS_OFFSET +
cpsw_stat_sysctls[i].reg);
- CPSW_DEBUGF(("%s: %ju + %u = %ju", cpsw_stat_sysctls[i].oid,
- (intmax_t)sc->shadow_stats[i], r,
- (intmax_t)sc->shadow_stats[i] + r));
+ CPSW_DEBUGF(sc, ("%s: %ju + %u = %ju", cpsw_stat_sysctls[i].oid,
+ (intmax_t)sc->shadow_stats[i], r,
+ (intmax_t)sc->shadow_stats[i] + r));
}
}
#endif
@@ -2121,13 +2435,14 @@ cpsw_stats_collect(struct cpsw_softc *sc)
int i;
uint32_t r;
- CPSW_DEBUGF(("Controller shadow statistics updated."));
+ CPSW_DEBUGF(sc, ("Controller shadow statistics updated."));
for (i = 0; i < CPSW_SYSCTL_COUNT; ++i) {
r = cpsw_read_4(sc, CPSW_STATS_OFFSET +
cpsw_stat_sysctls[i].reg);
sc->shadow_stats[i] += r;
- cpsw_write_4(sc, CPSW_STATS_OFFSET + cpsw_stat_sysctls[i].reg, r);
+ cpsw_write_4(sc, CPSW_STATS_OFFSET + cpsw_stat_sysctls[i].reg,
+ r);
}
}
@@ -2162,11 +2477,13 @@ cpsw_stat_attached(SYSCTL_HANDLER_ARGS)
static int
cpsw_stat_uptime(SYSCTL_HANDLER_ARGS)
{
- struct cpsw_softc *sc;
+ struct cpsw_softc *swsc;
+ struct cpswp_softc *sc;
struct bintime t;
unsigned result;
- sc = (struct cpsw_softc *)arg1;
+ swsc = arg1;
+ sc = device_get_softc(swsc->port[arg2].dev);
if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) {
getbinuptime(&t);
bintime_sub(&t, &sc->init_uptime);
@@ -2177,7 +2494,8 @@ cpsw_stat_uptime(SYSCTL_HANDLER_ARGS)
}
static void
-cpsw_add_queue_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node, struct cpsw_queue *queue)
+cpsw_add_queue_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node,
+ struct cpsw_queue *queue)
{
struct sysctl_oid_list *parent;
@@ -2210,7 +2528,8 @@ cpsw_add_queue_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node, str
}
static void
-cpsw_add_watchdog_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node, struct cpsw_softc *sc)
+cpsw_add_watchdog_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node,
+ struct cpsw_softc *sc)
{
struct sysctl_oid_list *parent;
@@ -2226,18 +2545,35 @@ cpsw_add_sysctls(struct cpsw_softc *sc)
struct sysctl_ctx_list *ctx;
struct sysctl_oid *stats_node, *queue_node, *node;
struct sysctl_oid_list *parent, *stats_parent, *queue_parent;
+ struct sysctl_oid_list *ports_parent, *port_parent;
+ char port[16];
int i;
ctx = device_get_sysctl_ctx(sc->dev);
parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
+ SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "debug",
+ CTLFLAG_RW, &sc->debug, 0, "Enable switch debug messages");
+
SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "attachedSecs",
CTLTYPE_UINT | CTLFLAG_RD, sc, 0, cpsw_stat_attached, "IU",
"Time since driver attach");
- SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "uptime",
- CTLTYPE_UINT | CTLFLAG_RD, sc, 0, cpsw_stat_uptime, "IU",
- "Seconds since driver init");
+ node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "ports",
+ CTLFLAG_RD, NULL, "CPSW Ports Statistics");
+ ports_parent = SYSCTL_CHILDREN(node);
+ for (i = 0; i < CPSW_PORTS; i++) {
+ if (!sc->dualemac && i != sc->active_slave)
+ continue;
+ port[0] = '0' + i;
+ port[1] = '\0';
+ node = SYSCTL_ADD_NODE(ctx, ports_parent, OID_AUTO,
+ port, CTLFLAG_RD, NULL, "CPSW Port Statistics");
+ port_parent = SYSCTL_CHILDREN(node);
+ SYSCTL_ADD_PROC(ctx, port_parent, OID_AUTO, "uptime",
+ CTLTYPE_UINT | CTLFLAG_RD, sc, i,
+ cpsw_stat_uptime, "IU", "Seconds since driver init");
+ }
stats_node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats",
CTLFLAG_RD, NULL, "CPSW Statistics");
@@ -2266,4 +2602,3 @@ cpsw_add_sysctls(struct cpsw_softc *sc)
CTLFLAG_RD, NULL, "Watchdog Statistics");
cpsw_add_watchdog_sysctls(ctx, node, sc);
}
-
diff --git a/sys/arm/ti/cpsw/if_cpswreg.h b/sys/arm/ti/cpsw/if_cpswreg.h
index 98d6033..bea6f19 100644
--- a/sys/arm/ti/cpsw/if_cpswreg.h
+++ b/sys/arm/ti/cpsw/if_cpswreg.h
@@ -29,103 +29,142 @@
#ifndef _IF_CPSWREG_H
#define _IF_CPSWREG_H
-#define CPSW_SS_OFFSET 0x0000
-#define CPSW_SS_IDVER (CPSW_SS_OFFSET + 0x00)
-#define CPSW_SS_SOFT_RESET (CPSW_SS_OFFSET + 0x08)
-#define CPSW_SS_STAT_PORT_EN (CPSW_SS_OFFSET + 0x0C)
-#define CPSW_SS_PTYPE (CPSW_SS_OFFSET + 0x10)
+#define CPSW_SS_OFFSET 0x0000
+#define CPSW_SS_IDVER (CPSW_SS_OFFSET + 0x00)
+#define CPSW_SS_SOFT_RESET (CPSW_SS_OFFSET + 0x08)
+#define CPSW_SS_STAT_PORT_EN (CPSW_SS_OFFSET + 0x0C)
+#define CPSW_SS_PTYPE (CPSW_SS_OFFSET + 0x10)
#define CPSW_SS_FLOW_CONTROL (CPSW_SS_OFFSET + 0x24)
-#define CPSW_PORT_OFFSET 0x0100
+#define CPSW_PORT_OFFSET 0x0100
#define CPSW_PORT_P_MAX_BLKS(p) (CPSW_PORT_OFFSET + 0x08 + ((p) * 0x100))
#define CPSW_PORT_P_BLK_CNT(p) (CPSW_PORT_OFFSET + 0x0C + ((p) * 0x100))
-#define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
-#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C)
-#define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020)
-#define CPSW_PORT_P_SA_LO(p) (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100))
-#define CPSW_PORT_P_SA_HI(p) (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100))
-
-#define CPSW_CPDMA_OFFSET 0x0800
-#define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04)
-#define CPSW_CPDMA_TX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x08)
-#define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14)
-#define CPSW_CPDMA_RX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x18)
-#define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c)
-#define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20)
-#define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24)
-#define CPSW_CPDMA_RX_BUFFER_OFFSET (CPSW_CPDMA_OFFSET + 0x28)
-#define CPSW_CPDMA_TX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0x80)
-#define CPSW_CPDMA_TX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0x84)
-#define CPSW_CPDMA_TX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0x88)
-#define CPSW_CPDMA_TX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0x8C)
-#define CPSW_CPDMA_CPDMA_EOI_VECTOR (CPSW_CPDMA_OFFSET + 0x94)
-#define CPSW_CPDMA_RX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xA0)
-#define CPSW_CPDMA_RX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xA4)
-#define CPSW_CPDMA_RX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xA8)
-#define CPSW_CPDMA_RX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xAc)
-#define CPSW_CPDMA_DMA_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xB0)
-#define CPSW_CPDMA_DMA_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xB4)
-#define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8)
-#define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC)
-#define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
-
-#define CPSW_STATS_OFFSET 0x0900
-
-#define CPSW_STATERAM_OFFSET 0x0A00
-#define CPSW_CPDMA_TX_HDP(p) (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04))
-#define CPSW_CPDMA_RX_HDP(p) (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04))
-#define CPSW_CPDMA_TX_CP(p) (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04))
-#define CPSW_CPDMA_RX_CP(p) (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04))
-
-#define CPSW_CPTS_OFFSET 0x0C00
-
-#define CPSW_ALE_OFFSET 0x0D00
-#define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08)
-#define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20)
-#define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34)
-#define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38)
-#define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C)
-#define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
+#define CPSW_PORT_P_VLAN(p) (CPSW_PORT_OFFSET + 0x14 + ((p) * 0x100))
+#define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
+#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C)
+#define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020)
+#define CPSW_PORT_P_SA_LO(p) (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100))
+#define CPSW_PORT_P_SA_HI(p) (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100))
+
+#define CPSW_CPDMA_OFFSET 0x0800
+#define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04)
+#define CPSW_CPDMA_TX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x08)
+#define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14)
+#define CPSW_CPDMA_RX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x18)
+#define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c)
+#define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20)
+#define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24)
+#define CPSW_CPDMA_RX_BUFFER_OFFSET (CPSW_CPDMA_OFFSET + 0x28)
+#define CPSW_CPDMA_TX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0x80)
+#define CPSW_CPDMA_TX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0x84)
+#define CPSW_CPDMA_TX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0x88)
+#define CPSW_CPDMA_TX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0x8C)
+#define CPSW_CPDMA_CPDMA_EOI_VECTOR (CPSW_CPDMA_OFFSET + 0x94)
+#define CPSW_CPDMA_RX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xA0)
+#define CPSW_CPDMA_RX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xA4)
+#define CPSW_CPDMA_RX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xA8)
+#define CPSW_CPDMA_RX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xAc)
+#define CPSW_CPDMA_DMA_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xB0)
+#define CPSW_CPDMA_DMA_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xB4)
+#define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8)
+#define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC)
+#define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
+
+#define CPSW_STATS_OFFSET 0x0900
+
+#define CPSW_STATERAM_OFFSET 0x0A00
+#define CPSW_CPDMA_TX_HDP(p) (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_HDP(p) (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_CP(p) (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_CP(p) (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04))
+
+#define CPSW_CPTS_OFFSET 0x0C00
+
+#define CPSW_ALE_OFFSET 0x0D00
+#define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08)
+#define CPSW_ALE_CTL_ENABLE (1U << 31)
+#define CPSW_ALE_CTL_CLEAR_TBL (1 << 30)
+#define CPSW_ALE_CTL_BYPASS (1 << 4)
+#define CPSW_ALE_CTL_VLAN_AWARE (1 << 2)
+#define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20)
+#define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34)
+#define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38)
+#define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C)
+#define ALE_MCAST(_a) ((_a[1] >> 8) & 1)
+#define ALE_MCAST_FWD (3 << 30)
+#define ALE_PORTS(_a) ((_a[2] >> 2) & 7)
+#define ALE_TYPE(_a) ((_a[1] >> 28) & 3)
+#define ALE_TYPE_ADDR 1
+#define ALE_TYPE_VLAN 2
+#define ALE_TYPE_VLAN_ADDR 3
+#define ALE_VLAN(_a) ((_a[1] >> 16) & 0xfff)
+#define ALE_VLAN_UNREGFLOOD(_a) ((_a[0] >> 8) & 7)
+#define ALE_VLAN_REGFLOOD(_a) ((_a[0] >> 16) & 7)
+#define ALE_VLAN_UNTAG(_a) ((_a[0] >> 24) & 7)
+#define ALE_VLAN_MEMBERS(_a) (_a[0] & 7)
+#define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
/* SL1 is at 0x0D80, SL2 is at 0x0DC0 */
-#define CPSW_SL_OFFSET 0x0D80
-#define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
-#define CPSW_SL_MACSTATUS(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x08)
-#define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
-#define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
-#define CPSW_SL_RX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x18)
-#define CPSW_SL_TX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x1C)
-#define CPSW_SL_RX_PRI_MAP(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24)
-
-#define MDIO_OFFSET 0x1000
-#define MDIOCONTROL (MDIO_OFFSET + 0x04)
-#define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80)
-#define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84)
-
-#define CPSW_WR_OFFSET 0x1200
-#define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04)
-#define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08)
-#define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c)
-#define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10)
-#define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14)
-#define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18)
-#define CPSW_WR_C_MISC_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C)
-#define CPSW_WR_C_RX_THRESH_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40)
-#define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
-#define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
-#define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
-
-#define CPSW_CPPI_RAM_OFFSET 0x2000
+#define CPSW_SL_OFFSET 0x0D80
+#define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
+#define CPSW_SL_MACTL_IFCTL_B (1 << 16)
+#define CPSW_SL_MACTL_IFCTL_A (1 << 15)
+#define CPSW_SL_MACTL_GIG (1 << 7)
+#define CPSW_SL_MACTL_GMII_ENABLE (1 << 5)
+#define CPSW_SL_MACTL_FULLDUPLEX (1 << 0)
+#define CPSW_SL_MACSTATUS(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x08)
+#define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
+#define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
+#define CPSW_SL_RX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x18)
+#define CPSW_SL_TX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x1C)
+#define CPSW_SL_RX_PRI_MAP(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24)
+
+#define MDIO_OFFSET 0x1000
+#define MDIOCONTROL (MDIO_OFFSET + 0x04)
+#define MDIOCTL_ENABLE (1 << 30)
+#define MDIOCTL_FAULTENB (1 << 18)
+#define MDIOLINKINTRAW (MDIO_OFFSET + 0x10)
+#define MDIOLINKINTMASKED (MDIO_OFFSET + 0x14)
+#define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80)
+#define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84)
+#define MDIOUSERACCESS1 (MDIO_OFFSET + 0x88)
+#define MDIOUSERPHYSEL1 (MDIO_OFFSET + 0x8C)
+#define MDIO_PHYSEL_LINKINTENB (1 << 6)
+#define MDIO_PHYACCESS_GO (1U << 31)
+#define MDIO_PHYACCESS_WRITE (1 << 30)
+#define MDIO_PHYACCESS_ACK (1 << 29)
+
+#define CPSW_WR_OFFSET 0x1200
+#define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04)
+#define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08)
+#define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c)
+#define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10)
+#define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14)
+#define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18)
+#define CPSW_WR_C_MISC_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C)
+#define CPSW_WR_C_RX_THRESH_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40)
+#define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
+#define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
+#define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
+#define CPSW_WR_C_MISC_EVNT_PEND (1 << 4)
+#define CPSW_WR_C_MISC_STAT_PEND (1 << 3)
+#define CPSW_WR_C_MISC_HOST_PEND (1 << 2)
+#define CPSW_WR_C_MISC_MDIOLINK (1 << 1)
+#define CPSW_WR_C_MISC_MDIOUSER (1 << 0)
+
+#define CPSW_CPPI_RAM_OFFSET 0x2000
#define CPSW_CPPI_RAM_SIZE 0x2000
#define CPSW_MEMWINDOW_SIZE 0x4000
-#define CPDMA_BD_SOP (1<<15)
-#define CPDMA_BD_EOP (1<<14)
-#define CPDMA_BD_OWNER (1<<13)
-#define CPDMA_BD_EOQ (1<<12)
-#define CPDMA_BD_TDOWNCMPLT (1<<11)
-#define CPDMA_BD_PKT_ERR_MASK (3<< 4)
+#define CPDMA_BD_SOP (1 << 15)
+#define CPDMA_BD_EOP (1 << 14)
+#define CPDMA_BD_OWNER (1 << 13)
+#define CPDMA_BD_EOQ (1 << 12)
+#define CPDMA_BD_TDOWNCMPLT (1 << 11)
+#define CPDMA_BD_PKT_ERR_MASK (3 << 4)
+#define CPDMA_BD_TO_PORT (1 << 4)
+#define CPDMA_BD_PORT_MASK 3
struct cpsw_cpdma_bd {
volatile uint32_t next;
diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h
index fbd7de5..adf2a37 100644
--- a/sys/arm/ti/cpsw/if_cpswvar.h
+++ b/sys/arm/ti/cpsw/if_cpswvar.h
@@ -29,19 +29,21 @@
#ifndef _IF_CPSWVAR_H
#define _IF_CPSWVAR_H
-#define CPSW_INTR_COUNT 4
+#define CPSW_PORTS 2
+#define CPSW_INTR_COUNT 4
/* MII BUS */
-#define CPSW_MIIBUS_RETRIES 5
-#define CPSW_MIIBUS_DELAY 1000
+#define CPSW_MIIBUS_RETRIES 5
+#define CPSW_MIIBUS_DELAY 1000
-#define CPSW_MAX_ALE_ENTRIES 1024
+#define CPSW_MAX_ALE_ENTRIES 1024
-#define CPSW_SYSCTL_COUNT 34
+#define CPSW_SYSCTL_COUNT 34
struct cpsw_slot {
uint32_t bd_offset; /* Offset of corresponding BD within CPPI RAM. */
bus_dmamap_t dmamap;
+ struct ifnet *ifp;
struct mbuf *mbuf;
STAILQ_ENTRY(cpsw_slot) next;
};
@@ -64,52 +66,43 @@ struct cpsw_queue {
int hdp_offset;
};
+struct cpsw_port {
+ device_t dev;
+ int phy;
+ int vlan;
+};
+
struct cpsw_softc {
- struct ifnet *ifp;
- phandle_t node;
device_t dev;
+ int active_slave;
+ int debug;
+ int dualemac;
+ phandle_t node;
struct bintime attach_uptime; /* system uptime when attach happened. */
- struct bintime init_uptime; /* system uptime when init happened. */
+ struct cpsw_port port[2];
- /* TODO: We should set up a child structure for each port;
- store mac, phy information, etc, in that structure. */
- uint8_t mac_addr[ETHER_ADDR_LEN];
+ /* RX and TX buffer tracking */
+ struct cpsw_queue rx, tx;
- device_t miibus;
- struct mii_data *mii;
/* We expect 1 memory resource and 4 interrupts from the device tree. */
- struct resource *mem_res;
int mem_rid;
+ struct resource *mem_res;
struct resource *irq_res[CPSW_INTR_COUNT];
+ void *ih_cookie[CPSW_INTR_COUNT];
- /* Interrupts get recorded here as we initialize them. */
- /* Interrupt teardown just walks this list. */
- struct {
- struct resource *res;
- void *ih_cookie;
- const char *description;
- } interrupts[CPSW_INTR_COUNT];
- int interrupt_count;
+ /* An mbuf full of nulls for TX padding. */
+ bus_dmamap_t null_mbuf_dmamap;
+ struct mbuf *null_mbuf;
+ bus_addr_t null_mbuf_paddr;
- uint32_t cpsw_if_flags;
- int cpsw_media_status;
+ bus_dma_tag_t mbuf_dtag;
struct {
int resets;
int timer;
- struct callout callout;
+ struct callout callout;
} watchdog;
- bus_dma_tag_t mbuf_dtag;
-
- /* An mbuf full of nulls for TX padding. */
- bus_dmamap_t null_mbuf_dmamap;
- struct mbuf *null_mbuf;
- bus_addr_t null_mbuf_paddr;
-
- /* RX and TX buffer tracking */
- struct cpsw_queue rx, tx;
-
/* 64-bit versions of 32-bit hardware statistics counters */
uint64_t shadow_stats[CPSW_SYSCTL_COUNT];
@@ -123,4 +116,23 @@ struct cpsw_softc {
struct cpsw_slots avail;
};
+struct cpswp_softc {
+ device_t dev;
+ device_t miibus;
+ device_t pdev;
+ int media_status;
+ int unit;
+ int vlan;
+ struct bintime init_uptime; /* system uptime when init happened. */
+ struct callout mii_callout;
+ struct cpsw_softc *swsc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+ struct mtx lock;
+ uint32_t if_flags;
+ uint32_t phy;
+ uint32_t phyaccess;
+ uint32_t physel;
+};
+
#endif /*_IF_CPSWVAR_H */
diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti
index d4daab1..6f571c6 100644
--- a/sys/arm/ti/files.ti
+++ b/sys/arm/ti/files.ti
@@ -18,6 +18,7 @@ arm/ti/ti_gpio.c optional gpio
arm/ti/ti_gpio_if.m optional gpio
arm/ti/ti_i2c.c optional ti_i2c
arm/ti/ti_sdhci.c optional sdhci
+arm/ti/ti_spi.c optional ti_spi
dev/uart/uart_dev_ti8250.c optional uart
dev/uart/uart_dev_ns8250.c optional uart
diff --git a/sys/arm/ti/omap4/omap4_gpio.c b/sys/arm/ti/omap4/omap4_gpio.c
index a261116..dd38f4a 100644
--- a/sys/arm/ti/omap4/omap4_gpio.c
+++ b/sys/arm/ti/omap4/omap4_gpio.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/gpio.h>
#include <machine/bus.h>
+#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
diff --git a/sys/arm/ti/omap4/omap4_wugen.c b/sys/arm/ti/omap4/omap4_wugen.c
index 2b24eaf..f2bed61 100644
--- a/sys/arm/ti/omap4/omap4_wugen.c
+++ b/sys/arm/ti/omap4/omap4_wugen.c
@@ -57,44 +57,64 @@ struct omap4_wugen_sc {
};
static int
-omap4_wugen_register(device_t dev, struct intr_irqsrc *isrc,
- boolean_t *is_percpu)
+omap4_wugen_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- return (PIC_REGISTER(sc->sc_parent, isrc, is_percpu));
+ return (PIC_ALLOC_INTR(sc->sc_parent, isrc, res, data));
}
-static int
-omap4_wugen_unregister(device_t dev, struct intr_irqsrc *isrc)
+static void
+omap4_wugen_disable_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- return (PIC_UNREGISTER(sc->sc_parent, isrc));
+ PIC_DISABLE_INTR(sc->sc_parent, isrc);
}
static void
-omap4_wugen_enable_source(device_t dev, struct intr_irqsrc *isrc)
+omap4_wugen_enable_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- PIC_ENABLE_SOURCE(sc->sc_parent, isrc);
+ PIC_ENABLE_INTR(sc->sc_parent, isrc);
}
-static void
-omap4_wugen_disable_source(device_t dev, struct intr_irqsrc *isrc)
+static int
+omap4_wugen_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- PIC_DISABLE_SOURCE(sc->sc_parent, isrc);
+ return (PIC_MAP_INTR(sc->sc_parent, data, isrcp));
}
-static void
-omap4_wugen_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+static int
+omap4_wugen_release_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- PIC_ENABLE_INTR(sc->sc_parent, isrc);
+ return (PIC_RELEASE_INTR(sc->sc_parent, isrc, res, data));
+}
+
+static int
+omap4_wugen_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct omap4_wugen_sc *sc = device_get_softc(dev);
+
+ return (PIC_SETUP_INTR(sc->sc_parent, isrc, res, data));
+}
+
+static int
+omap4_wugen_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct omap4_wugen_sc *sc = device_get_softc(dev);
+
+ return (PIC_TEARDOWN_INTR(sc->sc_parent, isrc, res, data));
}
static void
@@ -124,11 +144,11 @@ omap4_wugen_post_filter(device_t dev, struct intr_irqsrc *isrc)
#ifdef SMP
static int
-omap4_wugen_bind(device_t dev, struct intr_irqsrc *isrc)
+omap4_wugen_bind_intr(device_t dev, struct intr_irqsrc *isrc)
{
struct omap4_wugen_sc *sc = device_get_softc(dev);
- return (PIC_BIND(sc->sc_parent, isrc));
+ return (PIC_BIND_INTR(sc->sc_parent, isrc));
}
#endif
@@ -207,16 +227,18 @@ static device_method_t omap4_wugen_methods[] = {
DEVMETHOD(device_detach, omap4_wugen_detach),
/* Interrupt controller interface */
- DEVMETHOD(pic_register, omap4_wugen_register),
- DEVMETHOD(pic_unregister, omap4_wugen_unregister),
- DEVMETHOD(pic_enable_source, omap4_wugen_enable_source),
- DEVMETHOD(pic_disable_source, omap4_wugen_disable_source),
+ DEVMETHOD(pic_alloc_intr, omap4_wugen_alloc_intr),
+ DEVMETHOD(pic_disable_intr, omap4_wugen_disable_intr),
DEVMETHOD(pic_enable_intr, omap4_wugen_enable_intr),
+ DEVMETHOD(pic_map_intr, omap4_wugen_map_intr),
+ DEVMETHOD(pic_release_intr, omap4_wugen_release_intr),
+ DEVMETHOD(pic_setup_intr, omap4_wugen_setup_intr),
+ DEVMETHOD(pic_teardown_intr, omap4_wugen_teardown_intr),
DEVMETHOD(pic_pre_ithread, omap4_wugen_pre_ithread),
DEVMETHOD(pic_post_ithread, omap4_wugen_post_ithread),
DEVMETHOD(pic_post_filter, omap4_wugen_post_filter),
#ifdef SMP
- DEVMETHOD(pic_bind, omap4_wugen_bind),
+ DEVMETHOD(pic_bind_intr, omap4_wugen_bind_intr),
#endif
DEVMETHOD_END
};
diff --git a/sys/arm/ti/ti_adc.c b/sys/arm/ti/ti_adc.c
index d65afc6..f11091f 100644
--- a/sys/arm/ti/ti_adc.c
+++ b/sys/arm/ti/ti_adc.c
@@ -161,11 +161,9 @@ ti_adc_input_setup(struct ti_adc_softc *sc, int32_t ain)
/* Set the negative voltage reference. */
val &= ~ADC_STEP_RFM_MSK;
- val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT;
/* Set the positive voltage reference. */
val &= ~ADC_STEP_RFP_MSK;
- val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT;
/* Set the samples average. */
val &= ~ADC_STEP_AVG_MSK;
@@ -450,11 +448,9 @@ ti_adc_idlestep_init(struct ti_adc_softc *sc)
/* Set the negative voltage reference. */
val &= ~ADC_STEP_RFM_MSK;
- val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT;
/* Set the positive voltage reference. */
val &= ~ADC_STEP_RFP_MSK;
- val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT;
/* Connect the input to VREFN. */
val &= ~ADC_STEP_INP_MSK;
@@ -484,6 +480,11 @@ ti_adc_attach(device_t dev)
sc = device_get_softc(dev);
sc->sc_dev = dev;
+ /* Activate the ADC_TSC module. */
+ err = ti_prcm_clk_enable(TSC_ADC_CLK);
+ if (err)
+ return (err);
+
rid = 0;
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
@@ -509,11 +510,6 @@ ti_adc_attach(device_t dev)
return (ENXIO);
}
- /* Activate the ADC_TSC module. */
- err = ti_prcm_clk_enable(TSC_ADC_CLK);
- if (err)
- return (err);
-
/* Check the ADC revision. */
rev = ADC_READ4(sc, ADC_REVISION);
device_printf(dev,
diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c
index 2818bab..633fbf0 100644
--- a/sys/arm/ti/ti_gpio.c
+++ b/sys/arm/ti/ti_gpio.c
@@ -33,12 +33,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/proc.h>
#include <sys/rman.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -46,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/interrupt.h>
#include <machine/bus.h>
+#include <machine/intr.h>
#include <machine/resource.h>
#include <arm/ti/ti_cpuid.h>
@@ -62,6 +66,9 @@ __FBSDID("$FreeBSD$");
#include "gpio_if.h"
#include "ti_gpio_if.h"
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#endif
#if !defined(SOC_OMAP4) && !defined(SOC_TI_AM335X)
#error "Unknown SoC"
@@ -72,12 +79,12 @@ __FBSDID("$FreeBSD$");
#define TI_GPIO_SYSCONFIG 0x0010
#define TI_GPIO_IRQSTATUS_RAW_0 0x0024
#define TI_GPIO_IRQSTATUS_RAW_1 0x0028
-#define TI_GPIO_IRQSTATUS_0 0x002C
-#define TI_GPIO_IRQSTATUS_1 0x0030
-#define TI_GPIO_IRQSTATUS_SET_0 0x0034
-#define TI_GPIO_IRQSTATUS_SET_1 0x0038
-#define TI_GPIO_IRQSTATUS_CLR_0 0x003C
-#define TI_GPIO_IRQSTATUS_CLR_1 0x0040
+#define TI_GPIO_IRQSTATUS_0 0x002C /* writing a 0 has no effect */
+#define TI_GPIO_IRQSTATUS_1 0x0030 /* writing a 0 has no effect */
+#define TI_GPIO_IRQSTATUS_SET_0 0x0034 /* writing a 0 has no effect */
+#define TI_GPIO_IRQSTATUS_SET_1 0x0038 /* writing a 0 has no effect */
+#define TI_GPIO_IRQSTATUS_CLR_0 0x003C /* writing a 0 has no effect */
+#define TI_GPIO_IRQSTATUS_CLR_1 0x0040 /* writing a 0 has no effect */
#define TI_GPIO_IRQWAKEN_0 0x0044
#define TI_GPIO_IRQWAKEN_1 0x0048
#define TI_GPIO_SYSSTATUS 0x0114
@@ -90,10 +97,10 @@ __FBSDID("$FreeBSD$");
#define TI_GPIO_OE 0x0134
#define TI_GPIO_DATAIN 0x0138
#define TI_GPIO_DATAOUT 0x013C
-#define TI_GPIO_LEVELDETECT0 0x0140
-#define TI_GPIO_LEVELDETECT1 0x0144
-#define TI_GPIO_RISINGDETECT 0x0148
-#define TI_GPIO_FALLINGDETECT 0x014C
+#define TI_GPIO_LEVELDETECT0 0x0140 /* RW register */
+#define TI_GPIO_LEVELDETECT1 0x0144 /* RW register */
+#define TI_GPIO_RISINGDETECT 0x0148 /* RW register */
+#define TI_GPIO_FALLINGDETECT 0x014C /* RW register */
#define TI_GPIO_DEBOUNCENABLE 0x0150
#define TI_GPIO_DEBOUNCINGTIME 0x0154
#define TI_GPIO_CLEARWKUPENA 0x0180
@@ -111,8 +118,14 @@ __FBSDID("$FreeBSD$");
#define PINS_PER_BANK 32
#define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK))
+static int ti_gpio_intr(void *arg);
static int ti_gpio_detach(device_t);
+#ifdef ARM_INTRNG
+static int ti_gpio_pic_attach(struct ti_gpio_softc *sc);
+static int ti_gpio_pic_detach(struct ti_gpio_softc *sc);
+#endif
+
static u_int
ti_first_gpio_bank(void)
{
@@ -533,6 +546,7 @@ ti_gpio_pin_toggle(device_t dev, uint32_t pin)
return (0);
}
+#ifndef ARM_INTRNG
/**
* ti_gpio_intr - ISR for all GPIO modules
* @arg: the soft context pointer
@@ -567,6 +581,7 @@ ti_gpio_intr(void *arg)
return (FILTER_HANDLED);
}
+#endif
static int
ti_gpio_bank_init(device_t dev)
@@ -640,7 +655,9 @@ static int
ti_gpio_attach(device_t dev)
{
struct ti_gpio_softc *sc;
+#ifndef ARM_INTRNG
unsigned int i;
+#endif
int err;
sc = device_get_softc(dev);
@@ -679,6 +696,13 @@ ti_gpio_attach(device_t dev)
return (ENXIO);
}
+#ifdef ARM_INTRNG
+ if (ti_gpio_pic_attach(sc) != 0) {
+ device_printf(dev, "WARNING: unable to attach PIC\n");
+ ti_gpio_detach(dev);
+ return (ENXIO);
+ }
+#else
/*
* Initialize the interrupt settings. The default is active-low
* interrupts.
@@ -699,7 +723,7 @@ ti_gpio_attach(device_t dev)
sc->sc_mask_args = malloc(sizeof(struct ti_gpio_mask_arg) * sc->sc_maxpin,
M_DEVBUF, M_WAITOK | M_ZERO);
-
+#endif
/* We need to go through each block and ensure the clocks are running and
* the module is enabled. It might be better to do this only when the
* pins are configured which would result in less power used if the GPIO
@@ -747,6 +771,10 @@ ti_gpio_detach(device_t dev)
if (sc->sc_mem_res != NULL)
ti_gpio_intr_clr(sc, 0xffffffff);
gpiobus_detach_bus(dev);
+#ifdef ARM_INTRNG
+ if (sc->sc_isrcs != NULL)
+ ti_gpio_pic_detach(sc);
+#else
if (sc->sc_events)
free(sc->sc_events, M_DEVBUF);
if (sc->sc_mask_args)
@@ -755,6 +783,7 @@ ti_gpio_detach(device_t dev)
free(sc->sc_irq_polarity, M_DEVBUF);
if (sc->sc_irq_trigger)
free(sc->sc_irq_trigger, M_DEVBUF);
+#endif
/* Release the memory and IRQ resources. */
if (sc->sc_irq_hdl) {
bus_teardown_intr(dev, sc->sc_irq_res,
@@ -769,6 +798,282 @@ ti_gpio_detach(device_t dev)
return (0);
}
+#ifdef ARM_INTRNG
+static inline void
+ti_gpio_rwreg_set(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask)
+{
+
+ ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) | mask);
+}
+
+static inline void
+ti_gpio_rwreg_clr(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask)
+{
+
+ ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) & ~mask);
+}
+
+static inline void
+ti_gpio_isrc_mask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi)
+{
+
+ /* Writing a 0 has no effect. */
+ ti_gpio_intr_clr(sc, tgi->tgi_mask);
+}
+
+static inline void
+ti_gpio_isrc_unmask(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi)
+{
+
+ /* Writing a 0 has no effect. */
+ ti_gpio_intr_set(sc, tgi->tgi_mask);
+}
+
+static inline void
+ti_gpio_isrc_eoi(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi)
+{
+
+ /* Writing a 0 has no effect. */
+ ti_gpio_intr_ack(sc, tgi->tgi_mask);
+}
+
+static inline bool
+ti_gpio_isrc_is_level(struct ti_gpio_irqsrc *tgi)
+{
+
+ return (tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT0 ||
+ tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT1);
+}
+
+static int
+ti_gpio_intr(void *arg)
+{
+ u_int irq;
+ uint32_t reg;
+ struct ti_gpio_softc *sc;
+ struct trapframe *tf;
+ struct ti_gpio_irqsrc *tgi;
+
+ sc = (struct ti_gpio_softc *)arg;
+ tf = curthread->td_intr_frame;
+
+ reg = ti_gpio_intr_status(sc);
+ for (irq = 0; irq < sc->sc_maxpin; irq++) {
+ tgi = &sc->sc_isrcs[irq];
+ if ((reg & tgi->tgi_mask) == 0)
+ continue;
+ if (!ti_gpio_isrc_is_level(tgi))
+ ti_gpio_isrc_eoi(sc, tgi);
+ if (intr_isrc_dispatch(&tgi->tgi_isrc, tf) != 0) {
+ ti_gpio_isrc_mask(sc, tgi);
+ if (ti_gpio_isrc_is_level(tgi))
+ ti_gpio_isrc_eoi(sc, tgi);
+ device_printf(sc->sc_dev, "Stray irq %u disabled\n",
+ irq);
+ }
+ }
+ return (FILTER_HANDLED);
+}
+
+static int
+ti_gpio_pic_attach(struct ti_gpio_softc *sc)
+{
+ int error;
+ uint32_t irq;
+ const char *name;
+
+ sc->sc_isrcs = malloc(sizeof(*sc->sc_isrcs) * sc->sc_maxpin, M_DEVBUF,
+ M_WAITOK | M_ZERO);
+
+ name = device_get_nameunit(sc->sc_dev);
+ for (irq = 0; irq < sc->sc_maxpin; irq++) {
+ sc->sc_isrcs[irq].tgi_irq = irq;
+ sc->sc_isrcs[irq].tgi_mask = TI_GPIO_MASK(irq);
+ sc->sc_isrcs[irq].tgi_cfgreg = 0;
+
+ error = intr_isrc_register(&sc->sc_isrcs[irq].tgi_isrc,
+ sc->sc_dev, 0, "%s,%u", name, irq);
+ if (error != 0)
+ return (error); /* XXX deregister ISRCs */
+ }
+ return (intr_pic_register(sc->sc_dev,
+ OF_xref_from_node(ofw_bus_get_node(sc->sc_dev))));
+}
+
+static int
+ti_gpio_pic_detach(struct ti_gpio_softc *sc)
+{
+
+ /*
+ * There has not been established any procedure yet
+ * how to detach PIC from living system correctly.
+ */
+ device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__);
+ return (EBUSY);
+}
+
+static void
+ti_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ ti_gpio_isrc_mask(sc, tgi);
+}
+
+static void
+ti_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ arm_irq_memory_barrier(tgi->tgi_irq);
+ ti_gpio_isrc_unmask(sc, tgi);
+}
+
+static int
+ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, u_int ncells, pcell_t *cells,
+ u_int *irqp, uint32_t *regp)
+{
+ uint32_t reg;
+
+ /*
+ * The first cell is the interrupt number.
+ * The second cell is used to specify flags:
+ * bits[3:0] trigger type and level flags:
+ * 1 = low-to-high edge triggered.
+ * 2 = high-to-low edge triggered.
+ * 4 = active high level-sensitive.
+ * 8 = active low level-sensitive.
+ */
+ if (ncells != 2 || cells[0] >= sc->sc_maxpin)
+ return (EINVAL);
+
+ /*
+ * All interrupt types could be set for an interrupt at one moment.
+ * At least, the combination of 'low-to-high' and 'high-to-low' edge
+ * triggered interrupt types can make a sense. However, no combo is
+ * supported now.
+ */
+ if (cells[1] == 1)
+ reg = TI_GPIO_RISINGDETECT;
+ else if (cells[1] == 2)
+ reg = TI_GPIO_FALLINGDETECT;
+ else if (cells[1] == 4)
+ reg = TI_GPIO_LEVELDETECT1;
+ else if (cells[1] == 8)
+ reg = TI_GPIO_LEVELDETECT0;
+ else
+ return (EINVAL);
+
+ *irqp = cells[0];
+ if (regp != NULL)
+ *regp = reg;
+ return (0);
+}
+
+static int
+ti_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
+ struct intr_irqsrc **isrcp)
+{
+ int error;
+ u_int irq;
+ struct ti_gpio_softc *sc;
+
+ if (data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+
+ sc = device_get_softc(dev);
+ error = ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq,
+ NULL);
+ if (error == 0)
+ *isrcp = &sc->sc_isrcs[irq].tgi_isrc;
+ return (error);
+}
+
+static void
+ti_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ if (ti_gpio_isrc_is_level(tgi))
+ ti_gpio_isrc_eoi(sc, tgi);
+}
+
+static void
+ti_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ ti_gpio_pic_enable_intr(dev, isrc);
+}
+
+static void
+ti_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ ti_gpio_isrc_mask(sc, tgi);
+ if (ti_gpio_isrc_is_level(tgi))
+ ti_gpio_isrc_eoi(sc, tgi);
+}
+
+static int
+ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ u_int irq;
+ uint32_t cfgreg;
+ struct ti_gpio_softc *sc;
+ struct ti_gpio_irqsrc *tgi;
+
+ if (data == NULL || data->type != INTR_MAP_DATA_FDT)
+ return (ENOTSUP);
+
+ sc = device_get_softc(dev);
+ tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ /* Get and check config for an interrupt. */
+ if (ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq,
+ &cfgreg) != 0 || tgi->tgi_irq != irq)
+ return (EINVAL);
+
+ /*
+ * If this is a setup for another handler,
+ * only check that its configuration match.
+ */
+ if (isrc->isrc_handlers != 0)
+ return (tgi->tgi_cfgreg == cfgreg ? 0 : EINVAL);
+
+ TI_GPIO_LOCK(sc);
+ ti_gpio_rwreg_clr(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask);
+ ti_gpio_rwreg_clr(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask);
+ ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask);
+ ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask);
+ tgi->tgi_cfgreg = cfgreg;
+ ti_gpio_rwreg_set(sc, cfgreg, tgi->tgi_mask);
+ TI_GPIO_UNLOCK(sc);
+ return (0);
+}
+
+static int
+ti_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+{
+ struct ti_gpio_softc *sc = device_get_softc(dev);
+ struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc;
+
+ if (isrc->isrc_handlers == 0) {
+ TI_GPIO_LOCK(sc);
+ ti_gpio_rwreg_clr(sc, tgi->tgi_cfgreg, tgi->tgi_mask);
+ tgi->tgi_cfgreg = 0;
+ TI_GPIO_UNLOCK(sc);
+ }
+ return (0);
+}
+
+#else
static uint32_t
ti_gpio_intr_reg(struct ti_gpio_softc *sc, int irq)
{
@@ -970,6 +1275,7 @@ ti_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires,
return (err);
}
+#endif
static phandle_t
ti_gpio_get_node(device_t bus, device_t dev)
@@ -994,12 +1300,24 @@ static device_method_t ti_gpio_methods[] = {
DEVMETHOD(gpio_pin_set, ti_gpio_pin_set),
DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle),
+#ifdef ARM_INTRNG
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_disable_intr, ti_gpio_pic_disable_intr),
+ DEVMETHOD(pic_enable_intr, ti_gpio_pic_enable_intr),
+ DEVMETHOD(pic_map_intr, ti_gpio_pic_map_intr),
+ DEVMETHOD(pic_setup_intr, ti_gpio_pic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, ti_gpio_pic_teardown_intr),
+ DEVMETHOD(pic_post_filter, ti_gpio_pic_post_filter),
+ DEVMETHOD(pic_post_ithread, ti_gpio_pic_post_ithread),
+ DEVMETHOD(pic_pre_ithread, ti_gpio_pic_pre_ithread),
+#else
/* Bus interface */
DEVMETHOD(bus_activate_resource, ti_gpio_activate_resource),
DEVMETHOD(bus_deactivate_resource, ti_gpio_deactivate_resource),
DEVMETHOD(bus_config_intr, ti_gpio_config_intr),
DEVMETHOD(bus_setup_intr, ti_gpio_setup_intr),
DEVMETHOD(bus_teardown_intr, ti_gpio_teardown_intr),
+#endif
/* ofw_bus interface */
DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node),
diff --git a/sys/arm/ti/ti_gpio.h b/sys/arm/ti/ti_gpio.h
index 6bd53c8..f16728b 100644
--- a/sys/arm/ti/ti_gpio.h
+++ b/sys/arm/ti/ti_gpio.h
@@ -39,10 +39,19 @@
*/
#define MAX_GPIO_INTRS 8
+#ifndef ARM_INTRNG
struct ti_gpio_mask_arg {
void *softc;
int pin;
};
+#else
+struct ti_gpio_irqsrc {
+ struct intr_irqsrc tgi_isrc;
+ u_int tgi_irq;
+ uint32_t tgi_mask;
+ uint32_t tgi_cfgreg;
+};
+#endif
/**
* Structure that stores the driver context.
@@ -52,11 +61,11 @@ struct ti_gpio_mask_arg {
struct ti_gpio_softc {
device_t sc_dev;
device_t sc_busdev;
-
+#ifndef ARM_INTRNG
/* Interrupt trigger type and level. */
enum intr_trigger *sc_irq_trigger;
enum intr_polarity *sc_irq_polarity;
-
+#endif
int sc_bank;
int sc_maxpin;
struct mtx sc_mtx;
@@ -65,11 +74,13 @@ struct ti_gpio_softc {
struct resource *sc_mem_res;
int sc_irq_rid;
struct resource *sc_irq_res;
-
+#ifndef ARM_INTRNG
/* Interrupt events. */
struct intr_event **sc_events;
struct ti_gpio_mask_arg *sc_mask_args;
-
+#else
+ struct ti_gpio_irqsrc *sc_isrcs;
+#endif
/* The handle for the register IRQ handlers. */
void *sc_irq_hdl;
};
diff --git a/sys/arm/ti/ti_hwmods.c b/sys/arm/ti/ti_hwmods.c
index 1488e55..db96235 100644
--- a/sys/arm/ti/ti_hwmods.c
+++ b/sys/arm/ti/ti_hwmods.c
@@ -76,6 +76,9 @@ struct hwmod ti_hwmods[] = {
{"epwmss1", PWMSS1_CLK},
{"epwmss2", PWMSS2_CLK},
+ {"spi0", SPI0_CLK},
+ {"spi1", SPI1_CLK},
+
{"timer1", TIMER1_CLK},
{"timer2", TIMER2_CLK},
{"timer3", TIMER3_CLK},
diff --git a/sys/arm/ti/ti_prcm.h b/sys/arm/ti/ti_prcm.h
index c40439a..61b6960 100644
--- a/sys/arm/ti/ti_prcm.h
+++ b/sys/arm/ti/ti_prcm.h
@@ -158,6 +158,10 @@ typedef enum {
/* RTC module */
RTC_CLK = 1900,
+
+ /* McSPI */
+ SPI0_CLK = 2000,
+ SPI1_CLK,
} clk_ident_t;
/*
diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c
index 6c310b6..a24e693 100644
--- a/sys/arm/ti/ti_sdhci.c
+++ b/sys/arm/ti/ti_sdhci.c
@@ -722,3 +722,4 @@ static driver_t ti_sdhci_driver = {
DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, 0, 0);
MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_ti, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_ti, mmc, 1, 1, 1);
diff --git a/sys/arm/ti/ti_spi.c b/sys/arm/ti/ti_spi.c
new file mode 100644
index 0000000..e35f365
--- /dev/null
+++ b/sys/arm/ti/ti_spi.c
@@ -0,0 +1,582 @@
+/*-
+ * Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/spibus/spi.h>
+#include <dev/spibus/spibusvar.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_spireg.h>
+#include <arm/ti/ti_spivar.h>
+
+#include "spibus_if.h"
+
+static void ti_spi_intr(void *);
+static int ti_spi_detach(device_t);
+
+#undef TI_SPI_DEBUG
+#ifdef TI_SPI_DEBUG
+#define IRQSTATUSBITS \
+ "\020\1TX0_EMPTY\2TX0_UNDERFLOW\3RX0_FULL\4RX0_OVERFLOW" \
+ "\5TX1_EMPTY\6TX1_UNDERFLOW\7RX1_FULL\11TX2_EMPTY" \
+ "\12TX1_UNDERFLOW\13RX2_FULL\15TX3_EMPTY\16TX3_UNDERFLOW" \
+ "\17RX3_FULL\22EOW"
+#define CONFBITS \
+ "\020\1PHA\2POL\7EPOL\17DMAW\20DMAR\21DPE0\22DPE1\23IS" \
+ "\24TURBO\25FORCE\30SBE\31SBPOL\34FFEW\35FFER\36CLKG"
+#define STATBITS \
+ "\020\1RXS\2TXS\3EOT\4TXFFE\5TXFFF\6RXFFE\7RXFFFF"
+#define MODULCTRLBITS \
+ "\020\1SINGLE\2NOSPIEN\3SLAVE\4SYST\10MOA\11FDAA"
+#define CTRLBITS \
+ "\020\1ENABLED"
+
+static void
+ti_spi_printr(device_t dev)
+{
+ int clk, conf, ctrl, div, i, j, wl;
+ struct ti_spi_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+ reg = TI_SPI_READ(sc, MCSPI_SYSCONFIG);
+ device_printf(dev, "SYSCONFIG: %#x\n", reg);
+ reg = TI_SPI_READ(sc, MCSPI_SYSSTATUS);
+ device_printf(dev, "SYSSTATUS: %#x\n", reg);
+ reg = TI_SPI_READ(sc, MCSPI_IRQSTATUS);
+ device_printf(dev, "IRQSTATUS: 0x%b\n", reg, IRQSTATUSBITS);
+ reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
+ device_printf(dev, "IRQENABLE: 0x%b\n", reg, IRQSTATUSBITS);
+ reg = TI_SPI_READ(sc, MCSPI_MODULCTRL);
+ device_printf(dev, "MODULCTRL: 0x%b\n", reg, MODULCTRLBITS);
+ for (i = 0; i < sc->sc_numcs; i++) {
+ ctrl = TI_SPI_READ(sc, MCSPI_CTRL_CH(i));
+ conf = TI_SPI_READ(sc, MCSPI_CONF_CH(i));
+ device_printf(dev, "CH%dCONF: 0x%b\n", i, conf, CONFBITS);
+ if (conf & MCSPI_CONF_CLKG) {
+ div = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK;
+ div |= ((ctrl >> MCSPI_CTRL_EXTCLK_SHIFT) & MCSPI_CTRL_EXTCLK_MSK) << 4;
+ } else {
+ div = 1;
+ j = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK;
+ while (j-- > 0)
+ div <<= 1;
+ }
+ clk = TI_SPI_GCLK / div;
+ wl = ((conf >> MCSPI_CONF_WL_SHIFT) & MCSPI_CONF_WL_MSK) + 1;
+ device_printf(dev, "wordlen: %-2d clock: %d\n", wl, clk);
+ reg = TI_SPI_READ(sc, MCSPI_STAT_CH(i));
+ device_printf(dev, "CH%dSTAT: 0x%b\n", i, reg, STATBITS);
+ device_printf(dev, "CH%dCTRL: 0x%b\n", i, ctrl, CTRLBITS);
+ }
+ reg = TI_SPI_READ(sc, MCSPI_XFERLEVEL);
+ device_printf(dev, "XFERLEVEL: %#x\n", reg);
+}
+#endif
+
+static void
+ti_spi_set_clock(struct ti_spi_softc *sc, int ch, int freq)
+{
+ uint32_t clkdiv, conf, div, extclk, reg;
+
+ clkdiv = TI_SPI_GCLK / freq;
+ if (clkdiv > MCSPI_EXTCLK_MSK) {
+ extclk = 0;
+ clkdiv = 0;
+ div = 1;
+ while (TI_SPI_GCLK / div > freq && clkdiv <= 0xf) {
+ clkdiv++;
+ div <<= 1;
+ }
+ conf = clkdiv << MCSPI_CONF_CLK_SHIFT;
+ } else {
+ extclk = clkdiv >> 4;
+ clkdiv &= MCSPI_CONF_CLK_MSK;
+ conf = MCSPI_CONF_CLKG | clkdiv << MCSPI_CONF_CLK_SHIFT;
+ }
+
+ reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(ch));
+ reg &= ~(MCSPI_CTRL_EXTCLK_MSK << MCSPI_CTRL_EXTCLK_SHIFT);
+ reg |= extclk << MCSPI_CTRL_EXTCLK_SHIFT;
+ TI_SPI_WRITE(sc, MCSPI_CTRL_CH(ch), reg);
+
+ reg = TI_SPI_READ(sc, MCSPI_CONF_CH(ch));
+ reg &= ~(MCSPI_CONF_CLKG | MCSPI_CONF_CLK_MSK << MCSPI_CONF_CLK_SHIFT);
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(ch), reg | conf);
+}
+
+static int
+ti_spi_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "ti,omap4-mcspi"))
+ return (ENXIO);
+
+ device_set_desc(dev, "TI McSPI controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ti_spi_attach(device_t dev)
+{
+ int clk_id, err, i, rid, timeout;
+ struct ti_spi_softc *sc;
+ uint32_t rev;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ /*
+ * Get the MMCHS device id from FDT. If it's not there use the newbus
+ * unit number (which will work as long as the devices are in order and
+ * none are skipped in the fdt). Note that this is a property we made
+ * up and added in freebsd, it doesn't exist in the published bindings.
+ */
+ clk_id = ti_hwmods_get_clock(dev);
+ if (clk_id == INVALID_CLK_IDENT) {
+ device_printf(dev,
+ "failed to get clock based on hwmods property\n");
+ return (EINVAL);
+ }
+
+ /* Activate the McSPI module. */
+ err = ti_prcm_clk_enable(clk_id);
+ if (err) {
+ device_printf(dev, "Error: failed to activate source clock\n");
+ return (err);
+ }
+
+ /* Get the number of available channels. */
+ if ((OF_getencprop(ofw_bus_get_node(dev), "ti,spi-num-cs",
+ &sc->sc_numcs, sizeof(sc->sc_numcs))) <= 0) {
+ sc->sc_numcs = 2;
+ }
+
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_mem_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ return (ENXIO);
+ }
+
+ sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
+ sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
+
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_irq_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "cannot allocate interrupt\n");
+ return (ENXIO);
+ }
+
+ /* Hook up our interrupt handler. */
+ if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, ti_spi_intr, sc, &sc->sc_intrhand)) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "cannot setup the interrupt handler\n");
+ return (ENXIO);
+ }
+
+ mtx_init(&sc->sc_mtx, "ti_spi", NULL, MTX_DEF);
+
+ /* Issue a softreset to the controller */
+ TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+ timeout = 1000;
+ while (!(TI_SPI_READ(sc, MCSPI_SYSSTATUS) &
+ MCSPI_SYSSTATUS_RESETDONE)) {
+ if (--timeout == 0) {
+ device_printf(dev,
+ "Error: Controller reset operation timed out\n");
+ ti_spi_detach(dev);
+ return (ENXIO);
+ }
+ DELAY(100);
+ }
+
+ /* Print the McSPI module revision. */
+ rev = TI_SPI_READ(sc, MCSPI_REVISION);
+ device_printf(dev,
+ "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n",
+ (rev >> MCSPI_REVISION_SCHEME_SHIFT) & MCSPI_REVISION_SCHEME_MSK,
+ (rev >> MCSPI_REVISION_FUNC_SHIFT) & MCSPI_REVISION_FUNC_MSK,
+ (rev >> MCSPI_REVISION_RTL_SHIFT) & MCSPI_REVISION_RTL_MSK,
+ (rev >> MCSPI_REVISION_MAJOR_SHIFT) & MCSPI_REVISION_MAJOR_MSK,
+ (rev >> MCSPI_REVISION_MINOR_SHIFT) & MCSPI_REVISION_MINOR_MSK,
+ (rev >> MCSPI_REVISION_CUSTOM_SHIFT) & MCSPI_REVISION_CUSTOM_MSK);
+
+ /* Set Master mode, single channel. */
+ TI_SPI_WRITE(sc, MCSPI_MODULCTRL, MCSPI_MODULCTRL_SINGLE);
+
+ /* Clear pending interrupts and disable interrupts. */
+ TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0x0);
+ TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff);
+
+ for (i = 0; i < sc->sc_numcs; i++) {
+ /*
+ * Default to SPI mode 0, CS active low, 8 bits word length and
+ * 500kHz clock.
+ */
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(i),
+ MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL |
+ (8 - 1) << MCSPI_CONF_WL_SHIFT);
+ /* Set initial clock - 500kHz. */
+ ti_spi_set_clock(sc, i, 500000);
+ }
+
+#ifdef TI_SPI_DEBUG
+ ti_spi_printr(dev);
+#endif
+
+ device_add_child(dev, "spibus", -1);
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+ti_spi_detach(device_t dev)
+{
+ struct ti_spi_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ /* Clear pending interrupts and disable interrupts. */
+ TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0);
+ TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff);
+
+ /* Reset controller. */
+ TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET);
+
+ bus_generic_detach(dev);
+
+ mtx_destroy(&sc->sc_mtx);
+ if (sc->sc_intrhand)
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
+ if (sc->sc_irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ if (sc->sc_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+
+ return (0);
+}
+
+static int
+ti_spi_fill_fifo(struct ti_spi_softc *sc)
+{
+ int bytes, timeout;
+ struct spi_command *cmd;
+ uint32_t written;
+ uint8_t *data;
+
+ cmd = sc->sc_cmd;
+ bytes = min(sc->sc_len - sc->sc_written, sc->sc_fifolvl);
+ while (bytes-- > 0) {
+ data = (uint8_t *)cmd->tx_cmd;
+ written = sc->sc_written++;
+ if (written >= cmd->tx_cmd_sz) {
+ data = (uint8_t *)cmd->tx_data;
+ written -= cmd->tx_cmd_sz;
+ }
+ if (sc->sc_fifolvl == 1) {
+ /* FIFO disabled. */
+ timeout = 1000;
+ while (--timeout > 0 && (TI_SPI_READ(sc,
+ MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_TXS) == 0) {
+ DELAY(100);
+ }
+ if (timeout == 0)
+ return (-1);
+ }
+ TI_SPI_WRITE(sc, MCSPI_TX_CH(sc->sc_cs), data[written]);
+ }
+
+ return (0);
+}
+
+static int
+ti_spi_drain_fifo(struct ti_spi_softc *sc)
+{
+ int bytes, timeout;
+ struct spi_command *cmd;
+ uint32_t read;
+ uint8_t *data;
+
+ cmd = sc->sc_cmd;
+ bytes = min(sc->sc_len - sc->sc_read, sc->sc_fifolvl);
+ while (bytes-- > 0) {
+ data = (uint8_t *)cmd->rx_cmd;
+ read = sc->sc_read++;
+ if (read >= cmd->rx_cmd_sz) {
+ data = (uint8_t *)cmd->rx_data;
+ read -= cmd->rx_cmd_sz;
+ }
+ if (sc->sc_fifolvl == 1) {
+ /* FIFO disabled. */
+ timeout = 1000;
+ while (--timeout > 0 && (TI_SPI_READ(sc,
+ MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_RXS) == 0) {
+ DELAY(100);
+ }
+ if (timeout == 0)
+ return (-1);
+ }
+ data[read] = TI_SPI_READ(sc, MCSPI_RX_CH(sc->sc_cs));
+ }
+
+ return (0);
+}
+
+static void
+ti_spi_intr(void *arg)
+{
+ int eow;
+ struct ti_spi_softc *sc;
+ uint32_t status;
+
+ eow = 0;
+ sc = (struct ti_spi_softc *)arg;
+ TI_SPI_LOCK(sc);
+ status = TI_SPI_READ(sc, MCSPI_IRQSTATUS);
+
+ /*
+ * No new TX_empty or RX_full event will be asserted while the CPU has
+ * not performed the number of writes or reads defined by
+ * MCSPI_XFERLEVEL[AEL] and MCSPI_XFERLEVEL[AFL]. It is responsibility
+ * of CPU perform the right number of writes and reads.
+ */
+ if (status & MCSPI_IRQ_TX0_EMPTY)
+ ti_spi_fill_fifo(sc);
+ if (status & MCSPI_IRQ_RX0_FULL)
+ ti_spi_drain_fifo(sc);
+
+ if (status & MCSPI_IRQ_EOW)
+ eow = 1;
+
+ /* Clear interrupt status. */
+ TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, status);
+
+ /* Check for end of transfer. */
+ if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) {
+ sc->sc_flags |= TI_SPI_DONE;
+ wakeup(sc->sc_dev);
+ }
+
+ TI_SPI_UNLOCK(sc);
+}
+
+static int
+ti_spi_pio_transfer(struct ti_spi_softc *sc)
+{
+
+ while (sc->sc_len - sc->sc_written > 0) {
+ if (ti_spi_fill_fifo(sc) == -1)
+ return (EIO);
+ if (ti_spi_drain_fifo(sc) == -1)
+ return (EIO);
+ }
+
+ return (0);
+}
+
+static int
+ti_spi_gcd(int a, int b)
+{
+ int m;
+
+ while ((m = a % b) != 0) {
+ a = b;
+ b = m;
+ }
+
+ return (b);
+}
+
+static int
+ti_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+ int cs, err;
+ struct ti_spi_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
+ ("TX/RX command sizes should be equal"));
+ KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
+ ("TX/RX data sizes should be equal"));
+
+ /* Get the proper chip select for this child. */
+ spibus_get_cs(child, &cs);
+ if (cs < 0 || cs > sc->sc_numcs) {
+ device_printf(dev, "Invalid chip select %d requested by %s\n",
+ cs, device_get_nameunit(child));
+ return (EINVAL);
+ }
+
+ TI_SPI_LOCK(sc);
+
+ /* If the controller is in use wait until it is available. */
+ while (sc->sc_flags & TI_SPI_BUSY)
+ mtx_sleep(dev, &sc->sc_mtx, 0, "ti_spi", 0);
+
+ /* Now we have control over SPI controller. */
+ sc->sc_flags = TI_SPI_BUSY;
+
+ /* Save the SPI command data. */
+ sc->sc_cs = cs;
+ sc->sc_cmd = cmd;
+ sc->sc_read = 0;
+ sc->sc_written = 0;
+ sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
+ sc->sc_fifolvl = ti_spi_gcd(sc->sc_len, TI_SPI_FIFOSZ);
+ if (sc->sc_fifolvl < 2 || sc->sc_len > 0xffff)
+ sc->sc_fifolvl = 1; /* FIFO disabled. */
+ /* Disable FIFO for now. */
+ sc->sc_fifolvl = 1;
+
+ /* Use a safe clock - 500kHz. */
+ ti_spi_set_clock(sc, sc->sc_cs, 500000);
+
+ /* Disable the FIFO. */
+ TI_SPI_WRITE(sc, MCSPI_XFERLEVEL, 0);
+
+ /* 8 bits word, d0 miso, d1 mosi, mode 0 and CS active low. */
+ reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
+ reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW | MCSPI_CONF_SBPOL |
+ MCSPI_CONF_SBE | MCSPI_CONF_TURBO | MCSPI_CONF_IS |
+ MCSPI_CONF_DPE1 | MCSPI_CONF_DPE0 | MCSPI_CONF_DMAR |
+ MCSPI_CONF_DMAW | MCSPI_CONF_EPOL);
+ reg |= MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL | MCSPI_CONF_WL8BITS;
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
+
+#if 0
+ /* Enable channel interrupts. */
+ reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
+ reg |= 0xf;
+ TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg);
+#endif
+
+ /* Start the transfer. */
+ reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs));
+ TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg | MCSPI_CTRL_ENABLE);
+
+ /* Force CS on. */
+ reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg |= MCSPI_CONF_FORCE);
+
+ err = 0;
+ if (sc->sc_fifolvl == 1)
+ err = ti_spi_pio_transfer(sc);
+
+ /* Force CS off. */
+ reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
+ reg &= ~MCSPI_CONF_FORCE;
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
+
+ /* Disable IRQs. */
+ reg = TI_SPI_READ(sc, MCSPI_IRQENABLE);
+ reg &= ~0xf;
+ TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg);
+ TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xf);
+
+ /* Disable the SPI channel. */
+ reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs));
+ reg &= ~MCSPI_CTRL_ENABLE;
+ TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg);
+
+ /* Disable FIFO. */
+ reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs));
+ reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW);
+ TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg);
+
+ /* Release the controller and wakeup the next thread waiting for it. */
+ sc->sc_flags = 0;
+ wakeup_one(dev);
+ TI_SPI_UNLOCK(sc);
+
+ return (err);
+}
+
+static phandle_t
+ti_spi_get_node(device_t bus, device_t dev)
+{
+
+ /* Share controller node with spibus. */
+ return (ofw_bus_get_node(bus));
+}
+
+static device_method_t ti_spi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ti_spi_probe),
+ DEVMETHOD(device_attach, ti_spi_attach),
+ DEVMETHOD(device_detach, ti_spi_detach),
+
+ /* SPI interface */
+ DEVMETHOD(spibus_transfer, ti_spi_transfer),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, ti_spi_get_node),
+
+ DEVMETHOD_END
+};
+
+static devclass_t ti_spi_devclass;
+
+static driver_t ti_spi_driver = {
+ "spi",
+ ti_spi_methods,
+ sizeof(struct ti_spi_softc),
+};
+
+DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, ti_spi_devclass, 0, 0);
diff --git a/sys/arm/ti/ti_spireg.h b/sys/arm/ti/ti_spireg.h
new file mode 100644
index 0000000..f31f55e
--- /dev/null
+++ b/sys/arm/ti/ti_spireg.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TI_SPIREG_H_
+#define _TI_SPIREG_H_
+
+#define TI_SPI_GCLK 48000000U
+#define TI_SPI_FIFOSZ 32
+#define MCSPI_REVISION 0x0
+#define MCSPI_REVISION_SCHEME_SHIFT 30
+#define MCSPI_REVISION_SCHEME_MSK 0x3
+#define MCSPI_REVISION_FUNC_SHIFT 16
+#define MCSPI_REVISION_FUNC_MSK 0xfff
+#define MCSPI_REVISION_RTL_SHIFT 11
+#define MCSPI_REVISION_RTL_MSK 0x1f
+#define MCSPI_REVISION_MAJOR_SHIFT 8
+#define MCSPI_REVISION_MAJOR_MSK 0x7
+#define MCSPI_REVISION_CUSTOM_SHIFT 6
+#define MCSPI_REVISION_CUSTOM_MSK 0x3
+#define MCSPI_REVISION_MINOR_SHIFT 0
+#define MCSPI_REVISION_MINOR_MSK 0x3f
+#define MCSPI_SYSCONFIG 0x110
+#define MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
+#define MCSPI_SYSSTATUS 0x114
+#define MCSPI_SYSSTATUS_RESETDONE (1 << 0)
+#define MCSPI_MODULCTRL 0x128
+#define MCSPI_MODULCTRL_SLAVE (1 << 2)
+#define MCSPI_MODULCTRL_SINGLE (1 << 0)
+#define MCSPI_IRQSTATUS 0x118
+#define MCSPI_IRQENABLE 0x11c
+#define MCSPI_IRQ_EOW (1 << 17)
+#define MCSPI_IRQ_RX0_OVERFLOW (1 << 3)
+#define MCSPI_IRQ_RX0_FULL (1 << 2)
+#define MCSPI_IRQ_TX0_UNDERFLOW (1 << 1)
+#define MCSPI_IRQ_TX0_EMPTY (1 << 0)
+#define MCSPI_CONF_CH(_c) (0x12c + 0x14 * (_c))
+#define MCSPI_CONF_CLKG (1 << 29)
+#define MCSPI_CONF_FFER (1 << 28)
+#define MCSPI_CONF_FFEW (1 << 27)
+#define MCSPI_CONF_SBPOL (1 << 24)
+#define MCSPI_CONF_SBE (1 << 23)
+#define MCSPI_CONF_FORCE (1 << 20)
+#define MCSPI_CONF_TURBO (1 << 19)
+#define MCSPI_CONF_IS (1 << 18)
+#define MCSPI_CONF_DPE1 (1 << 17)
+#define MCSPI_CONF_DPE0 (1 << 16)
+#define MCSPI_CONF_DMAR (1 << 15)
+#define MCSPI_CONF_DMAW (1 << 14)
+#define MCSPI_CONF_WL_MSK 0x1f
+#define MCSPI_CONF_WL_SHIFT 7
+#define MCSPI_CONF_WL8BITS (7 << MCSPI_CONF_WL_SHIFT)
+#define MCSPI_CONF_EPOL (1 << 6)
+#define MCSPI_CONF_CLK_MSK 0xf
+#define MCSPI_CONF_CLK_SHIFT 2
+#define MCSPI_CONF_POL (1 << 1)
+#define MCSPI_CONF_PHA (1 << 0)
+#define MCSPI_STAT_CH(_c) (0x130 + 0x14 * (_c))
+#define MCSPI_STAT_TXFFF (1 << 4)
+#define MCSPI_STAT_TXS (1 << 1)
+#define MCSPI_STAT_RXS (1 << 0)
+#define MCSPI_CTRL_CH(_c) (0x134 + 0x14 * (_c))
+#define MCSPI_EXTCLK_MSK 0xfff
+#define MCSPI_CTRL_EXTCLK_MSK 0xff
+#define MCSPI_CTRL_EXTCLK_SHIFT 8
+#define MCSPI_CTRL_ENABLE (1 << 0)
+#define MCSPI_TX_CH(_c) (0x138 + 0x14 * (_c))
+#define MCSPI_RX_CH(_c) (0x13c + 0x14 * (_c))
+#define MCSPI_XFERLEVEL 0x17c
+#define MCSPI_XFERLEVEL_AFL(_a) (((_a) >> 8) & 0xff)
+#define MCSPI_XFERLEVEL_AEL(_a) (((_a) >> 0) & 0xff)
+
+#endif /* _TI_SPIREG_H_ */
diff --git a/sys/arm/ti/ti_spivar.h b/sys/arm/ti/ti_spivar.h
new file mode 100644
index 0000000..89731f3
--- /dev/null
+++ b/sys/arm/ti/ti_spivar.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2016 Rubicon Communications, LLC (Netgate)
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _TI_SPIVAR_H_
+#define _TI_SPIVAR_H_
+
+struct ti_spi_softc {
+ bus_space_tag_t sc_bst;
+ bus_space_handle_t sc_bsh;
+ device_t sc_dev;
+ int sc_numcs;
+ struct mtx sc_mtx;
+ struct resource *sc_mem_res;
+ struct resource *sc_irq_res;
+ struct {
+ int cs;
+ int fifolvl;
+ struct spi_command *cmd;
+ uint32_t len;
+ uint32_t read;
+ uint32_t written;
+ } xfer;
+ uint32_t sc_flags;
+ void *sc_intrhand;
+#define sc_cs xfer.cs
+#define sc_fifolvl xfer.fifolvl
+#define sc_cmd xfer.cmd
+#define sc_len xfer.len
+#define sc_read xfer.read
+#define sc_written xfer.written
+};
+
+#define TI_SPI_BUSY 0x1
+#define TI_SPI_DONE 0x2
+
+#define TI_SPI_WRITE(_sc, _off, _val) \
+ bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off), (_val))
+#define TI_SPI_READ(_sc, _off) \
+ bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off))
+
+#define TI_SPI_LOCK(_sc) \
+ mtx_lock(&(_sc)->sc_mtx)
+#define TI_SPI_UNLOCK(_sc) \
+ mtx_unlock(&(_sc)->sc_mtx)
+
+#endif /* _TI_SPIVAR_H_ */
diff --git a/sys/arm/xscale/ixp425/avila_ata.c b/sys/arm/xscale/ixp425/avila_ata.c
index e3a9a52..f6dfaa6 100644
--- a/sys/arm/xscale/ixp425/avila_ata.c
+++ b/sys/arm/xscale/ixp425/avila_ata.c
@@ -287,7 +287,7 @@ ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
struct ata_avila_softc *sc = device_get_softc(dev);
KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
- ("type %u rid %u start %lu end %lu count %lu flags %u",
+ ("type %u rid %u start %ju end %ju count %ju flags %u",
type, *rid, start, end, count, flags));
/* doesn't matter what we return so reuse the real thing */
diff --git a/sys/arm/xscale/ixp425/ixp425.c b/sys/arm/xscale/ixp425/ixp425.c
index 017d567..20120e6 100644
--- a/sys/arm/xscale/ixp425/ixp425.c
+++ b/sys/arm/xscale/ixp425/ixp425.c
@@ -533,7 +533,7 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
(start - vtrans->hwbase);
if (bootverbose)
device_printf(child,
- "%s: assign 0x%lx:0x%lx%s\n",
+ "%s: assign 0x%jx:0x%jx%s\n",
__func__, start, end - start,
vtrans->isa4x ? " A4X" :
vtrans->isslow ? " SLOW" : "");
@@ -542,14 +542,14 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
vtrans = gethwvtrans(start, end - start);
if (vtrans == NULL) {
/* likely means above table needs to be updated */
- device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n",
+ device_printf(child, "%s: no mapping for 0x%jx:0x%jx\n",
__func__, start, end - start);
return NULL;
}
rv = rman_reserve_resource(&sc->sc_mem_rman, start, end,
end - start, flags, child);
if (rv == NULL) {
- device_printf(child, "%s: cannot reserve 0x%lx:0x%lx\n",
+ device_printf(child, "%s: cannot reserve 0x%jx:0x%jx\n",
__func__, start, end - start);
return NULL;
}
@@ -586,7 +586,7 @@ ixp425_activate_resource(device_t dev, device_t child, int type, int rid,
if (type == SYS_RES_MEMORY) {
vtrans = gethwvtrans(rman_get_start(r), rman_get_size(r));
if (vtrans == NULL) { /* NB: should not happen */
- device_printf(child, "%s: no mapping for 0x%lx:0x%lx\n",
+ device_printf(child, "%s: no mapping for 0x%jx:0x%jx\n",
__func__, rman_get_start(r), rman_get_size(r));
return (ENOENT);
}
diff --git a/sys/arm/xscale/pxa/pxa_obio.c b/sys/arm/xscale/pxa/pxa_obio.c
index 6761ca3..6081588 100644
--- a/sys/arm/xscale/pxa/pxa_obio.c
+++ b/sys/arm/xscale/pxa/pxa_obio.c
@@ -159,9 +159,9 @@ pxa_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
retval += resource_list_print_type(&od->od_resources, "at mem",
- SYS_RES_MEMORY, "0x%08lx");
+ SYS_RES_MEMORY, "0x%08jx");
retval += resource_list_print_type(&od->od_resources, "irq",
- SYS_RES_IRQ, "%ld");
+ SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
@@ -390,7 +390,7 @@ pxa_alloc_gpio_irq(device_t dev, device_t child, int type, int *rid,
}
if (bootverbose)
- device_printf(dev, "lazy allocation of irq %ld for %s\n",
+ device_printf(dev, "lazy allocation of irq %jd for %s\n",
start, device_get_nameunit(child));
return (rv);
diff --git a/sys/arm/xscale/pxa/pxa_smi.c b/sys/arm/xscale/pxa/pxa_smi.c
index 4c49e75..b08a7c7 100644
--- a/sys/arm/xscale/pxa/pxa_smi.c
+++ b/sys/arm/xscale/pxa/pxa_smi.c
@@ -144,9 +144,9 @@ pxa_smi_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
retval += resource_list_print_type(&smid->smid_resources, "at mem",
- SYS_RES_MEMORY, "%#lx");
+ SYS_RES_MEMORY, "%#jx");
retval += resource_list_print_type(&smid->smid_resources, "irq",
- SYS_RES_IRQ, "%ld");
+ SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
diff --git a/sys/arm64/arm64/bzero.S b/sys/arm64/arm64/bzero.S
new file mode 100644
index 0000000..60ac97e
--- /dev/null
+++ b/sys/arm64/arm64/bzero.S
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (C) 2016 Cavium Inc.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+
+#include "assym.s"
+
+ /*
+ * void bzero(void *p, size_t size)
+ *
+ * x0 - p
+ * x1 - size
+ */
+ENTRY(bzero)
+ cbz x1, ending
+
+ /*
+ * x5 is number of cache lines to zero - calculated later and
+ * will become non-zero if buffer is long enough to zero by
+ * cache lines (and if it is allowed.)
+ * We need to zero it before proceeding with buffers of size
+ * smaller than 16 bytes - otherwise the x5 will not be
+ * calculated and will retain random value.
+ * "normal" is used for buffers <= 16 bytes and to align buffer
+ * to cache line for buffers bigger than cache line; non-0 x5
+ * after "normal" has completed indicates that it has been used
+ * to align buffer to cache line and now zero by cache lines will
+ * be performed, and x5 is amount of cache lines to loop through.
+ */
+ mov x5, xzr
+
+ /* No use of cache assisted zero for buffers with size <= 16 */
+ cmp x1, #0x10
+ b.le normal
+
+ /*
+ * Load size of line that will be cleaned by dc zva call.
+ * 0 means that the instruction is not allowed
+ */
+ ldr x7, =dczva_line_size
+ ldr x7, [x7]
+ cbz x7, normal
+
+ /*
+ * Buffer must be larger than cache line for using cache zeroing
+ * (and cache line aligned but this is checked after jump)
+ */
+ cmp x1, x7
+ b.lt normal
+
+ /*
+ * Calculate number of bytes to cache aligned address (x4) nad
+ * number of full cache lines (x5). x6 is final address to zero.
+ */
+ sub x2, x7, #0x01
+ mov x3, -1
+ eor x3, x3, x2
+ add x4, x0, x2
+ and x4, x4, x3
+ subs x4, x4, x0
+ b.eq normal
+
+ /* Calculate number of "lines" in buffer */
+ sub x5, x1, x4
+ rbit x2, x7
+ clz x2, x2
+ lsr x5, x5, x2
+
+ /*
+ * If number of cache lines is 0, we will not be able to zero
+ * by cache lines, so go normal way.
+ */
+ cbz x5, normal
+ /* x6 is final address to zero */
+ add x6, x0, x1
+
+ /*
+ * We are here because x5 is non-0 so normal will be used to
+ * align buffer before cache zeroing. x4 holds number of bytes
+ * needed for alignment.
+ */
+ mov x1, x4
+
+ /* When jumping here: x0 holds pointer, x1 holds size */
+normal:
+ /*
+ * Get buffer offset into 16 byte aligned address; 0 means pointer
+ * is aligned.
+ */
+ ands x2, x0, #0x0f
+ b.eq aligned_to_16
+ /* Calculate one-byte loop runs to 8 byte aligned address. */
+ ands x2, x2, #0x07
+ mov x3, #0x08
+ sub x2, x3, x2
+ /* x2 is number of bytes missing for alignment, x1 is buffer size */
+ cmp x1, x2
+ csel x2, x1, x2, le
+ sub x1, x1, x2
+
+ /*
+ * Byte by byte copy will copy at least enough bytes to align
+ * pointer and at most "size".
+ */
+align:
+ strb wzr, [x0], #0x01
+ subs x2, x2, #0x01
+ b.ne align
+
+ /* Now pointer is aligned to 8 bytes */
+ cmp x1, #0x10
+ b.lt lead_out
+ /*
+ * Check if copy of another 8 bytes is needed to align to 16 byte
+ * address and do it
+ */
+ tbz x0, #0x03, aligned_to_16
+ str xzr, [x0], #0x08
+ sub x1, x1, #0x08
+
+ /* While jumping here: x0 is 16 byte alligned address, x1 is size */
+aligned_to_16:
+ /* If size is less than 16 bytes, use lead_out to copy what remains */
+ cmp x1, #0x10
+ b.lt lead_out
+
+ lsr x2, x1, #0x04
+zero_by_16:
+ stp xzr, xzr, [x0], #0x10
+ subs x2, x2, #0x01
+ b.ne zero_by_16
+
+ /*
+ * Lead out requires addresses to be aligned to 8 bytes. It is used to
+ * zero buffers with sizes < 16 and what can not be zeroed by
+ * zero_by_16 loop.
+ */
+ ands x1, x1, #0x0f
+ b.eq lead_out_end
+lead_out:
+ tbz x1, #0x03, lead_out_dword
+ str xzr, [x0], #0x08
+lead_out_dword:
+ tbz x1, #0x02, lead_out_word
+ str wzr, [x0], #0x04
+lead_out_word:
+ tbz x1, #0x01, lead_out_byte
+ strh wzr, [x0], #0x02
+lead_out_byte:
+ tbz x1, #0x00, lead_out_end
+ strb wzr, [x0], #0x01
+
+lead_out_end:
+ /*
+ * If x5 is non-zero, this means that normal has been used as
+ * a lead in to align buffer address to cache size
+ */
+ cbz x5, ending
+
+ /*
+ * Here x5 holds number of lines to zero; x6 is final address of
+ * buffer. x0 is cache line aligned pointer. x7 is cache line size
+ * in bytes
+ */
+cache_line_zero:
+ dc zva, x0
+ add x0, x0, x7
+ subs x5, x5, #0x01
+ b.ne cache_line_zero
+
+ /* Need to zero remaining bytes? */
+ subs x1, x6, x0
+ b.ne normal
+
+ending:
+ ret
+
+END(bzero)
+
diff --git a/sys/arm64/arm64/copyinout.S b/sys/arm64/arm64/copyinout.S
index 1ba8106..b99dbc2 100644
--- a/sys/arm64/arm64/copyinout.S
+++ b/sys/arm64/arm64/copyinout.S
@@ -51,24 +51,18 @@ END(copyio_fault)
* int copyout(const void *kaddr, void *udaddr, size_t len)
*/
ENTRY(copyout)
- cbz x2, 2f /* If len == 0 then skip loop */
- add x3, x1, x2
+ cbz x2, 1f
+ adds x3, x1, x2
+ b.cs copyio_fault_nopcb
ldr x4, =VM_MAXUSER_ADDRESS
cmp x3, x4
b.hi copyio_fault_nopcb
- adr x6, copyio_fault /* Get the handler address */
- SET_FAULT_HANDLER(x6, x7) /* Set the handler */
-
-1: ldrb w4, [x0], #1 /* Load from kaddr */
- strb w4, [x1], #1 /* Store in uaddr */
- sub x2, x2, #1 /* len-- */
- cbnz x2, 1b
-
- SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+ b copycommon
-2: mov x0, xzr /* return 0 */
+1: mov x0, xzr /* return 0 */
ret
+
END(copyout)
/*
@@ -77,24 +71,18 @@ END(copyout)
* int copyin(const void *uaddr, void *kdaddr, size_t len)
*/
ENTRY(copyin)
- cbz x2, 2f /* If len == 0 then skip loop */
- add x3, x0, x2
+ cbz x2, 1f
+ adds x3, x0, x2
+ b.cs copyio_fault_nopcb
ldr x4, =VM_MAXUSER_ADDRESS
cmp x3, x4
b.hi copyio_fault_nopcb
- adr x6, copyio_fault /* Get the handler address */
- SET_FAULT_HANDLER(x6, x7) /* Set the handler */
-
-1: ldrb w4, [x0], #1 /* Load from uaddr */
- strb w4, [x1], #1 /* Store in kaddr */
- sub x2, x2, #1 /* len-- */
- cbnz x2, 1b
-
- SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+ b copycommon
-2: mov x0, xzr /* return 0 */
+1: mov x0, xzr /* return 0 */
ret
+
END(copyin)
/*
@@ -106,11 +94,11 @@ ENTRY(copyinstr)
mov x5, xzr /* count = 0 */
mov w4, #1 /* If zero return faulure */
cbz x2, 3f /* If len == 0 then skip loop */
- ldr x7, =VM_MAXUSER_ADDRESS
adr x6, copyio_fault /* Get the handler address */
SET_FAULT_HANDLER(x6, x7) /* Set the handler */
+ ldr x7, =VM_MAXUSER_ADDRESS
1: cmp x0, x7
b.cs copyio_fault
ldrb w4, [x0], #1 /* Load from uaddr */
@@ -130,3 +118,101 @@ ENTRY(copyinstr)
csel w0, wzr, w1, eq /* If so return success, else failure */
ret
END(copyinstr)
+
+/*
+ * Local helper
+ *
+ * x0 - src pointer
+ * x1 - dst pointer
+ * x2 - size
+ * lr - the return address, so jump here instead of calling
+ *
+ * This function is optimized to minimize concurrent memory accesses. In
+ * present form it is suited for cores with a single memory prefetching
+ * unit.
+ * ARM64TODO:
+ * Consider using separate functions for each ARM64 core. Adding memory
+ * access interleaving might increase a total throughput on A57 or A72.
+ */
+ .text
+ .align 4
+ .local copycommon
+ .type copycommon,@function
+
+copycommon:
+ adr x6, copyio_fault /* Get the handler address */
+ SET_FAULT_HANDLER(x6, x7) /* Set the handler */
+
+
+ /* Check alignment */
+ orr x3, x0, x1
+ ands x3, x3, 0x07
+ b.eq aligned
+
+ /* Unaligned is byte by byte copy */
+byte_by_byte:
+ ldrb w3, [x0], #0x01
+ strb w3, [x1], #0x01
+ subs x2, x2, #0x01
+ b.ne byte_by_byte
+ b ending
+
+aligned:
+ cmp x2, #0x10
+ b.lt lead_out
+ cmp x2, #0x40
+ b.lt by_dwords_start
+
+ /* Block copy */
+ lsr x15, x2, #0x06
+by_blocks:
+ ldp x3, x4, [x0], #0x10
+ ldp x5, x6, [x0], #0x10
+ ldp x7, x8, [x0], #0x10
+ ldp x9, x10, [x0], #0x10
+ stp x3, x4, [x1], #0x10
+ stp x5, x6, [x1], #0x10
+ stp x7, x8, [x1], #0x10
+ stp x9, x10, [x1], #0x10
+
+ subs x15, x15, #0x01
+ b.ne by_blocks
+
+ and x2, x2, #0x3f
+
+by_dwords_start:
+ lsr x15, x2, #0x04
+ cbz x15, lead_out
+by_dwords:
+ ldp x3, x4, [x0], #0x10
+ stp x3, x4, [x1], #0x10
+ subs x15, x15, #0x01
+ b.ne by_dwords
+
+ /* Less than 16 bytes to copy */
+lead_out:
+ tbz x2, #0x03, last_word
+ ldr x3, [x0], #0x08
+ str x3, [x1], #0x08
+
+last_word:
+ tbz x2, #0x02, last_hword
+ ldr w3, [x0], #0x04
+ str w3, [x1], #0x04
+
+last_hword:
+ tbz x2, #0x01, last_byte
+ ldrh w3, [x0], #0x02
+ strh w3, [x1], #0x02
+
+last_byte:
+ tbz x2, #0x00, ending
+ ldrb w3, [x0]
+ strb w3, [x1]
+
+ending:
+ SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
+
+ mov x0, xzr /* return 0 */
+ ret
+ .size copycommon, . - copycommon
diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S
index c5a358b..63aa04c 100644
--- a/sys/arm64/arm64/exception.S
+++ b/sys/arm64/arm64/exception.S
@@ -150,7 +150,7 @@ END(handle_el1h_sync)
ENTRY(handle_el1h_irq)
save_registers 1
mov x0, sp
- bl arm_cpu_intr
+ bl intr_irq_handler
restore_registers 1
eret
END(handle_el1h_irq)
@@ -171,7 +171,7 @@ END(handle_el0_sync)
ENTRY(handle_el0_irq)
save_registers 0
mov x0, sp
- bl arm_cpu_intr
+ bl intr_irq_handler
do_ast
restore_registers 0
eret
diff --git a/sys/arm64/arm64/genassym.c b/sys/arm64/arm64/genassym.c
index 67c295f..26adc6d 100644
--- a/sys/arm64/arm64/genassym.c
+++ b/sys/arm64/arm64/genassym.c
@@ -52,7 +52,7 @@ ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1));
ASSYM(PCB_SINGLE_STEP_SHIFT, PCB_SINGLE_STEP_SHIFT);
ASSYM(PCB_REGS, offsetof(struct pcb, pcb_x));
ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp));
-ASSYM(PCB_L1ADDR, offsetof(struct pcb, pcb_l1addr));
+ASSYM(PCB_L0ADDR, offsetof(struct pcb, pcb_l0addr));
ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
diff --git a/sys/arm64/arm64/gic.c b/sys/arm64/arm64/gic.c
index 0a13b12..2140086 100644
--- a/sys/arm64/arm64/gic.c
+++ b/sys/arm64/arm64/gic.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
+#define GICD_SGI_TARGET_SHIFT 16
/* CPU Registers */
#define GICC_CTLR 0x0000 /* v1 ICCICR */
@@ -108,6 +109,8 @@ static struct resource_spec arm_gic_spec[] = {
{ -1, 0 }
};
+static u_int arm_gic_map[MAXCPU];
+
static struct arm_gic_softc *arm_gic_sc = NULL;
#define gic_c_read_4(_sc, _reg) \
@@ -124,6 +127,29 @@ static pic_eoi_t gic_eoi;
static pic_mask_t gic_mask_irq;
static pic_unmask_t gic_unmask_irq;
+static uint8_t
+gic_cpu_mask(struct arm_gic_softc *sc)
+{
+ uint32_t mask;
+ int i;
+
+ /* Read the current cpuid mask by reading ITARGETSR{0..7} */
+ for (i = 0; i < 8; i++) {
+ mask = gic_d_read_4(sc, GICD_ITARGETSR(i));
+ if (mask != 0)
+ break;
+ }
+ /* No mask found, assume we are on CPU interface 0 */
+ if (mask == 0)
+ return (1);
+
+ /* Collect the mask in the lower byte */
+ mask |= mask >> 16;
+ mask |= mask >> 8;
+
+ return (mask);
+}
+
#ifdef SMP
static void
gic_init_secondary(device_t dev)
@@ -131,6 +157,9 @@ gic_init_secondary(device_t dev)
struct arm_gic_softc *sc = device_get_softc(dev);
int i;
+ /* Set the mask so we can find this CPU to send it IPIs */
+ arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
+
for (i = 0; i < sc->nirqs; i += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
@@ -162,7 +191,7 @@ arm_gic_attach(device_t dev)
{
struct arm_gic_softc *sc;
int i;
- uint32_t icciidr;
+ uint32_t icciidr, mask;
if (arm_gic_sc)
return (ENXIO);
@@ -212,10 +241,19 @@ arm_gic_attach(device_t dev)
gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
}
+ /* Find the current cpu mask */
+ mask = gic_cpu_mask(sc);
+ /* Set the mask so we can find this CPU to send it IPIs */
+ arm_gic_map[PCPU_GET(cpuid)] = mask;
+ /* Set all four targets to this cpu */
+ mask |= mask << 8;
+ mask |= mask << 16;
+
for (i = 0; i < sc->nirqs; i += 4) {
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
- gic_d_write_4(sc, GICD_ITARGETSR(i >> 2),
- 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
+ if (i > 32) {
+ gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
+ }
}
/* Set all the interrupts to be in Group 0 (secure) */
@@ -299,7 +337,7 @@ gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
for (i = 0; i < MAXCPU; i++)
if (CPU_ISSET(i, &cpus))
- val |= 1 << (16 + i);
+ val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
}
diff --git a/sys/arm64/arm64/intr_machdep.c b/sys/arm64/arm64/intr_machdep.c
index 5994279..d99303e 100644
--- a/sys/arm64/arm64/intr_machdep.c
+++ b/sys/arm64/arm64/intr_machdep.c
@@ -408,7 +408,7 @@ arm_setup_intr(const char *name, driver_filter_t *filt, driver_intr_t handler,
}
int
-arm_teardown_intr(void *cookie)
+intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
{
struct arm64_intr_entry *intr;
int error;
@@ -426,7 +426,7 @@ arm_teardown_intr(void *cookie)
}
int
-arm_config_intr(u_int hw_irq, enum intr_trigger trig, enum intr_polarity pol)
+intr_irq_config(u_int hw_irq, enum intr_trigger trig, enum intr_polarity pol)
{
struct arm64_intr_entry *intr;
@@ -476,7 +476,7 @@ stray:
}
void
-arm_cpu_intr(struct trapframe *tf)
+intr_irq_handler(struct trapframe *tf)
{
critical_enter();
@@ -512,7 +512,7 @@ SYSINIT(arm_intr_smp_init, SI_SUB_SMP, SI_ORDER_ANY, arm_intr_smp_init, NULL);
/* Attempt to bind the specified IRQ to the specified CPU. */
int
-arm_intr_bind(u_int hw_irq, int cpu)
+intr_irq_bind(u_int hw_irq, int cpu)
{
struct arm64_intr_entry *intr;
diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index b1fd3ae..676c1d5 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -35,7 +35,7 @@
#include <machine/param.h>
#include <machine/pte.h>
-#define VIRT_BITS 39
+#define VIRT_BITS 48
.globl kernbase
.set kernbase, KERNBASE
@@ -89,7 +89,8 @@ _start:
/*
* At this point:
* x27 = TTBR0 table
- * x26 = TTBR1 table
+ * x26 = Kernel L1 table
+ * x24 = TTBR1 table
*/
/* Enable the mmu */
@@ -100,16 +101,6 @@ _start:
br x15
virtdone:
- /*
- * Now that we are in virtual address space,
- * we don't need the identity mapping in TTBR0 and
- * can set the TCR to a more useful value.
- */
- ldr x2, tcr
- mrs x3, id_aa64mmfr0_el1
- bfi x2, x3, #32, #3
- msr tcr_el1, x2
-
/* Set up the stack */
adr x25, initstack_end
mov sp, x25
@@ -128,6 +119,7 @@ virtdone:
/* Make the page table base a virtual address */
sub x26, x26, x29
+ sub x24, x24, x29
sub sp, sp, #(64 * 4)
mov x0, sp
@@ -139,6 +131,7 @@ virtdone:
str x26, [x0, 8] /* kern_l1pt */
str x29, [x0, 16] /* kern_delta */
str x25, [x0, 24] /* kern_stack */
+ str x24, [x0, 32] /* kern_l0pt */
/* trace back starts here */
mov fp, #0
@@ -175,7 +168,7 @@ ENTRY(mpentry)
msr contextidr_el1, x1
/* Load the kernel page table */
- adr x26, pagetable_l1_ttbr1
+ adr x24, pagetable_l0_ttbr1
/* Load the identity page table */
adr x27, pagetable_l0_ttbr0
@@ -187,16 +180,6 @@ ENTRY(mpentry)
br x15
mp_virtdone:
- /*
- * Now that we are in virtual address space,
- * we don't need the identity mapping in TTBR0 and
- * can set the TCR to a more useful value.
- */
- ldr x2, tcr
- mrs x3, id_aa64mmfr0_el1
- bfi x2, x3, #32, #3
- msr tcr_el1, x2
-
ldr x4, =secondary_stacks
mov x5, #(PAGE_SIZE * KSTACK_PAGES)
mul x5, x0, x5
@@ -388,11 +371,18 @@ create_pagetables:
mov x6, x26
bl link_l1_pagetable
+ /* Move to the l0 table */
+ add x24, x26, #PAGE_SIZE
+
+ /* Link the l0 -> l1 table */
+ mov x9, x6
+ mov x6, x24
+ bl link_l0_pagetable
/*
* Build the TTBR0 maps.
*/
- add x27, x26, #PAGE_SIZE
+ add x27, x24, #PAGE_SIZE
mov x6, x27 /* The initial page table */
#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
@@ -440,7 +430,7 @@ link_l0_pagetable:
*/
/* Find the table index */
lsr x11, x8, #L0_SHIFT
- and x11, x11, #Ln_ADDR_MASK
+ and x11, x11, #L0_ADDR_MASK
/* Build the L0 block entry */
mov x12, #L0_TABLE
@@ -582,7 +572,7 @@ start_mmu:
/* Load ttbr0 and ttbr1 */
msr ttbr0_el1, x27
- msr ttbr1_el1, x26
+ msr ttbr1_el1, x24
isb
/* Clear the Monitor Debug System control register */
@@ -596,11 +586,8 @@ start_mmu:
/*
* Setup TCR according to PARange bits from ID_AA64MMFR0_EL1.
- * Some machines have physical memory mapped >512GiB, which can not
- * be identity-mapped using the default 39 VA bits. Thus, use
- * 48 VA bits for now and switch back to 39 after the VA jump.
*/
- ldr x2, tcr_early
+ ldr x2, tcr
mrs x3, id_aa64mmfr0_el1
bfi x2, x3, #32, #3
msr tcr_el1, x2
@@ -623,9 +610,6 @@ mair:
tcr:
.quad (TCR_TxSZ(64 - VIRT_BITS) | TCR_ASID_16 | TCR_TG1_4K | \
TCR_CACHE_ATTRS | TCR_SMP_ATTRS)
-tcr_early:
- .quad (TCR_T1SZ(64 - VIRT_BITS) | TCR_T0SZ(64 - 48) | \
- TCR_ASID_16 | TCR_TG1_4K | TCR_CACHE_ATTRS | TCR_SMP_ATTRS)
sctlr_set:
/* Bits to set */
.quad (SCTLR_UCI | SCTLR_nTWE | SCTLR_nTWI | SCTLR_UCT | SCTLR_DZE | \
@@ -651,6 +635,8 @@ pagetable:
.space PAGE_SIZE
pagetable_l1_ttbr1:
.space PAGE_SIZE
+pagetable_l0_ttbr1:
+ .space PAGE_SIZE
pagetable_l1_ttbr0:
.space PAGE_SIZE
pagetable_l0_ttbr0:
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 49c9610..2bf108f 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -108,6 +108,14 @@ struct kva_md_info kmi;
int64_t dcache_line_size; /* The minimum D cache line size */
int64_t icache_line_size; /* The minimum I cache line size */
int64_t idcache_line_size; /* The minimum cache line size */
+int64_t dczva_line_size; /* The size of cache line the dc zva zeroes */
+
+/* pagezero_* implementations are provided in support.S */
+void pagezero_simple(void *);
+void pagezero_cache(void *);
+
+/* pagezero_simple is default pagezero */
+void (*pagezero)(void *p) = pagezero_simple;
static void
cpu_startup(void *dummy)
@@ -129,16 +137,6 @@ cpu_idle_wakeup(int cpu)
return (0);
}
-void
-bzero(void *buf, size_t len)
-{
- uint8_t *p;
-
- p = buf;
- while(len-- > 0)
- *p++ = 0;
-}
-
int
fill_regs(struct thread *td, struct reg *regs)
{
@@ -800,8 +798,9 @@ try_load_dtb(caddr_t kmdp)
static void
cache_setup(void)
{
- int dcache_line_shift, icache_line_shift;
+ int dcache_line_shift, icache_line_shift, dczva_line_shift;
uint32_t ctr_el0;
+ uint32_t dczid_el0;
ctr_el0 = READ_SPECIALREG(ctr_el0);
@@ -815,6 +814,20 @@ cache_setup(void)
icache_line_size = sizeof(int) << icache_line_shift;
idcache_line_size = MIN(dcache_line_size, icache_line_size);
+
+ dczid_el0 = READ_SPECIALREG(dczid_el0);
+
+ /* Check if dc zva is not prohibited */
+ if (dczid_el0 & DCZID_DZP)
+ dczva_line_size = 0;
+ else {
+ /* Same as with above calculations */
+ dczva_line_shift = DCZID_BS_SIZE(dczid_el0);
+ dczva_line_size = sizeof(int) << dczva_line_shift;
+
+ /* Change pagezero function */
+ pagezero = pagezero_cache;
+ }
}
void
@@ -896,8 +909,8 @@ initarm(struct arm64_bootparams *abp)
cache_setup();
/* Bootstrap enough of pmap to enter the kernel proper */
- pmap_bootstrap(abp->kern_l1pt, KERNBASE - abp->kern_delta,
- lastaddr - KERNBASE);
+ pmap_bootstrap(abp->kern_l0pt, abp->kern_l1pt,
+ KERNBASE - abp->kern_delta, lastaddr - KERNBASE);
arm_devmap_bootstrap(0, NULL);
diff --git a/sys/arm64/arm64/minidump_machdep.c b/sys/arm64/arm64/minidump_machdep.c
index 56d1713..27c2081 100644
--- a/sys/arm64/arm64/minidump_machdep.c
+++ b/sys/arm64/arm64/minidump_machdep.c
@@ -218,7 +218,7 @@ blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz)
int
minidumpsys(struct dumperinfo *di)
{
- pd_entry_t *l1, *l2;
+ pd_entry_t *l0, *l1, *l2;
pt_entry_t *l3;
uint32_t pmapsize;
vm_offset_t va;
@@ -236,7 +236,7 @@ minidumpsys(struct dumperinfo *di)
pmapsize = 0;
for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += L2_SIZE) {
pmapsize += PAGE_SIZE;
- if (!pmap_get_tables(pmap_kernel(), va, &l1, &l2, &l3))
+ if (!pmap_get_tables(pmap_kernel(), va, &l0, &l1, &l2, &l3))
continue;
/* We should always be using the l2 table for kvm */
@@ -335,7 +335,7 @@ minidumpsys(struct dumperinfo *di)
/* Dump kernel page directory pages */
bzero(&tmpbuffer, sizeof(tmpbuffer));
for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += L2_SIZE) {
- if (!pmap_get_tables(pmap_kernel(), va, &l1, &l2, &l3)) {
+ if (!pmap_get_tables(pmap_kernel(), va, &l0, &l1, &l2, &l3)) {
/* We always write a page, even if it is zero */
error = blk_write(di, (char *)&tmpbuffer, 0, PAGE_SIZE);
if (error)
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
index b89982d..22c99ba 100644
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -80,6 +80,12 @@ static device_identify_t arm64_cpu_identify;
static device_probe_t arm64_cpu_probe;
static device_attach_t arm64_cpu_attach;
+static void ipi_ast(void *);
+static void ipi_hardclock(void *);
+static void ipi_preempt(void *);
+static void ipi_rendezvous(void *);
+static void ipi_stop(void *);
+
static int ipi_handler(void *arg);
struct mtx ap_boot_mtx;
@@ -179,7 +185,7 @@ release_aps(void *dummy __unused)
int cpu, i;
/* Setup the IPI handler */
- for (i = 0; i < COUNT_IPI; i++)
+ for (i = 0; i < INTR_IPI_COUNT; i++)
arm_setup_ipihandler(ipi_handler, i);
atomic_store_rel_int(&aps_ready, 1);
@@ -238,7 +244,7 @@ init_secondary(uint64_t cpu)
/* Configure the interrupt controller */
arm_init_secondary();
- for (i = 0; i < COUNT_IPI; i++)
+ for (i = 0; i < INTR_IPI_COUNT; i++)
arm_unmask_ipi(i);
/* Start per-CPU event timers. */
@@ -271,13 +277,65 @@ init_secondary(uint64_t cpu)
/* NOTREACHED */
}
+static void
+ipi_ast(void *dummy __unused)
+{
+
+ CTR0(KTR_SMP, "IPI_AST");
+}
+
+static void
+ipi_hardclock(void *dummy __unused)
+{
+
+ CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
+ hardclockintr();
+}
+
+static void
+ipi_preempt(void *dummy __unused)
+{
+ CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
+ sched_preempt(curthread);
+}
+
+static void
+ipi_rendezvous(void *dummy __unused)
+{
+
+ CTR0(KTR_SMP, "IPI_RENDEZVOUS");
+ smp_rendezvous_action();
+}
+
+static void
+ipi_stop(void *dummy __unused)
+{
+ u_int cpu;
+
+ CTR0(KTR_SMP, "IPI_STOP");
+
+ cpu = PCPU_GET(cpuid);
+ savectx(&stoppcbs[cpu]);
+
+ /* Indicate we are stopped */
+ CPU_SET_ATOMIC(cpu, &stopped_cpus);
+
+ /* Wait for restart */
+ while (!CPU_ISSET(cpu, &started_cpus))
+ cpu_spinwait();
+
+ CPU_CLR_ATOMIC(cpu, &started_cpus);
+ CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+ CTR0(KTR_SMP, "IPI_STOP (restart)");
+}
+
static int
ipi_handler(void *arg)
{
u_int cpu, ipi;
arg = (void *)((uintptr_t)arg & ~(1 << 16));
- KASSERT((uintptr_t)arg < COUNT_IPI,
+ KASSERT((uintptr_t)arg < INTR_IPI_COUNT,
("Invalid IPI %ju", (uintptr_t)arg));
cpu = PCPU_GET(cpuid);
@@ -285,35 +343,20 @@ ipi_handler(void *arg)
switch(ipi) {
case IPI_AST:
- CTR0(KTR_SMP, "IPI_AST");
+ ipi_ast(NULL);
break;
case IPI_PREEMPT:
- CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
- sched_preempt(curthread);
+ ipi_preempt(NULL);
break;
case IPI_RENDEZVOUS:
- CTR0(KTR_SMP, "IPI_RENDEZVOUS");
- smp_rendezvous_action();
+ ipi_rendezvous(NULL);
break;
case IPI_STOP:
case IPI_STOP_HARD:
- CTR0(KTR_SMP, (ipi == IPI_STOP) ? "IPI_STOP" : "IPI_STOP_HARD");
- savectx(&stoppcbs[cpu]);
-
- /* Indicate we are stopped */
- CPU_SET_ATOMIC(cpu, &stopped_cpus);
-
- /* Wait for restart */
- while (!CPU_ISSET(cpu, &started_cpus))
- cpu_spinwait();
-
- CPU_CLR_ATOMIC(cpu, &started_cpus);
- CPU_CLR_ATOMIC(cpu, &stopped_cpus);
- CTR0(KTR_SMP, "IPI_STOP (restart)");
+ ipi_stop(NULL);
break;
case IPI_HARDCLOCK:
- CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
- hardclockintr();
+ ipi_hardclock(NULL);
break;
default:
panic("Unknown IPI %#0x on cpu %d", ipi, curcpu);
diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c
index cdc5fc8..f48a7aa 100644
--- a/sys/arm64/arm64/nexus.c
+++ b/sys/arm64/arm64/nexus.c
@@ -39,6 +39,9 @@
* and I/O memory address space.
*/
+#include "opt_acpi.h"
+#include "opt_platform.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -60,9 +63,6 @@ __FBSDID("$FreeBSD$");
#include <machine/resource.h>
#include <machine/intr.h>
-#include "opt_acpi.h"
-#include "opt_platform.h"
-
#ifdef FDT
#include <dev/ofw/openfirm.h>
#include "ofw_bus_if.h"
@@ -271,7 +271,7 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
enum intr_polarity pol)
{
- return (arm_config_intr(irq, trig, pol));
+ return (intr_irq_config(irq, trig, pol));
}
static int
@@ -298,7 +298,7 @@ static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
{
- return (arm_teardown_intr(ih));
+ return (intr_irq_remove_handler(child, rman_get_start(r), ih));
}
#ifdef SMP
@@ -306,7 +306,7 @@ static int
nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
{
- return (arm_intr_bind(rman_get_start(irq), cpu));
+ return (intr_irq_bind(rman_get_start(irq), cpu));
}
#endif
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 5db731d..5eeccdd 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -11,7 +11,7 @@
* All rights reserved.
* Copyright (c) 2014 Andrew Turner
* All rights reserved.
- * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2014-2016 The FreeBSD Foundation
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -142,9 +142,14 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include <machine/pcb.h>
-#define NPDEPG (PAGE_SIZE/(sizeof (pd_entry_t)))
-#define NUPDE (NPDEPG * NPDEPG)
-#define NUSERPGTBLS (NUPDE + NPDEPG)
+#define NL0PG (PAGE_SIZE/(sizeof (pd_entry_t)))
+#define NL1PG (PAGE_SIZE/(sizeof (pd_entry_t)))
+#define NL2PG (PAGE_SIZE/(sizeof (pd_entry_t)))
+#define NL3PG (PAGE_SIZE/(sizeof (pt_entry_t)))
+
+#define NUL0E L0_ENTRIES
+#define NUL1E (NUL0E * NL1PG)
+#define NUL2E (NUL1E * NL2PG)
#if !defined(DIAGNOSTIC)
#ifdef __GNUC_GNU_INLINE__
@@ -266,22 +271,37 @@ pagecopy(void *s, void *d)
memcpy(d, s, PAGE_SIZE);
}
-static __inline void
-pagezero(void *p)
+#define pmap_l0_index(va) (((va) >> L0_SHIFT) & L0_ADDR_MASK)
+#define pmap_l1_index(va) (((va) >> L1_SHIFT) & Ln_ADDR_MASK)
+#define pmap_l2_index(va) (((va) >> L2_SHIFT) & Ln_ADDR_MASK)
+#define pmap_l3_index(va) (((va) >> L3_SHIFT) & Ln_ADDR_MASK)
+
+static __inline pd_entry_t *
+pmap_l0(pmap_t pmap, vm_offset_t va)
{
- bzero(p, PAGE_SIZE);
+ return (&pmap->pm_l0[pmap_l0_index(va)]);
}
-#define pmap_l1_index(va) (((va) >> L1_SHIFT) & Ln_ADDR_MASK)
-#define pmap_l2_index(va) (((va) >> L2_SHIFT) & Ln_ADDR_MASK)
-#define pmap_l3_index(va) (((va) >> L3_SHIFT) & Ln_ADDR_MASK)
+static __inline pd_entry_t *
+pmap_l0_to_l1(pd_entry_t *l0, vm_offset_t va)
+{
+ pd_entry_t *l1;
+
+ l1 = (pd_entry_t *)PHYS_TO_DMAP(pmap_load(l0) & ~ATTR_MASK);
+ return (&l1[pmap_l1_index(va)]);
+}
static __inline pd_entry_t *
pmap_l1(pmap_t pmap, vm_offset_t va)
{
+ pd_entry_t *l0;
- return (&pmap->pm_l1[pmap_l1_index(va)]);
+ l0 = pmap_l0(pmap, va);
+ if ((pmap_load(l0) & ATTR_DESCR_MASK) != L0_TABLE)
+ return (NULL);
+
+ return (pmap_l0_to_l1(l0, va));
}
static __inline pd_entry_t *
@@ -314,28 +334,103 @@ pmap_l2_to_l3(pd_entry_t *l2, vm_offset_t va)
return (&l3[pmap_l3_index(va)]);
}
+/*
+ * Returns the lowest valid pde for a given virtual address.
+ * The next level may or may not point to a valid page or block.
+ */
+static __inline pd_entry_t *
+pmap_pde(pmap_t pmap, vm_offset_t va, int *level)
+{
+ pd_entry_t *l0, *l1, *l2, desc;
+
+ l0 = pmap_l0(pmap, va);
+ desc = pmap_load(l0) & ATTR_DESCR_MASK;
+ if (desc != L0_TABLE) {
+ *level = -1;
+ return (NULL);
+ }
+
+ l1 = pmap_l0_to_l1(l0, va);
+ desc = pmap_load(l1) & ATTR_DESCR_MASK;
+ if (desc != L1_TABLE) {
+ *level = 0;
+ return (l0);
+ }
+
+ l2 = pmap_l1_to_l2(l1, va);
+ desc = pmap_load(l2) & ATTR_DESCR_MASK;
+ if (desc != L2_TABLE) {
+ *level = 1;
+ return (l1);
+ }
+
+ *level = 2;
+ return (l2);
+}
+
+/*
+ * Returns the lowest valid pte block or table entry for a given virtual
+ * address. If there are no valid entries return NULL and set the level to
+ * the first invalid level.
+ */
static __inline pt_entry_t *
-pmap_l3(pmap_t pmap, vm_offset_t va)
+pmap_pte(pmap_t pmap, vm_offset_t va, int *level)
{
- pd_entry_t *l2;
+ pd_entry_t *l1, *l2, desc;
+ pt_entry_t *l3;
- l2 = pmap_l2(pmap, va);
- if (l2 == NULL || (pmap_load(l2) & ATTR_DESCR_MASK) != L2_TABLE)
+ l1 = pmap_l1(pmap, va);
+ if (l1 == NULL) {
+ *level = 0;
return (NULL);
+ }
+ desc = pmap_load(l1) & ATTR_DESCR_MASK;
+ if (desc == L1_BLOCK) {
+ *level = 1;
+ return (l1);
+ }
+
+ if (desc != L1_TABLE) {
+ *level = 1;
+ return (NULL);
+ }
+
+ l2 = pmap_l1_to_l2(l1, va);
+ desc = pmap_load(l2) & ATTR_DESCR_MASK;
+ if (desc == L2_BLOCK) {
+ *level = 2;
+ return (l2);
+ }
- return (pmap_l2_to_l3(l2, va));
+ if (desc != L2_TABLE) {
+ *level = 2;
+ return (NULL);
+ }
+
+ *level = 3;
+ l3 = pmap_l2_to_l3(l2, va);
+ if ((pmap_load(l3) & ATTR_DESCR_MASK) != L3_PAGE)
+ return (NULL);
+
+ return (l3);
}
bool
-pmap_get_tables(pmap_t pmap, vm_offset_t va, pd_entry_t **l1, pd_entry_t **l2,
- pt_entry_t **l3)
+pmap_get_tables(pmap_t pmap, vm_offset_t va, pd_entry_t **l0, pd_entry_t **l1,
+ pd_entry_t **l2, pt_entry_t **l3)
{
- pd_entry_t *l1p, *l2p;
+ pd_entry_t *l0p, *l1p, *l2p;
- if (pmap->pm_l1 == NULL)
+ if (pmap->pm_l0 == NULL)
return (false);
- l1p = pmap_l1(pmap, va);
+ l0p = pmap_l0(pmap, va);
+ *l0 = l0p;
+
+ if ((pmap_load(l0p) & ATTR_DESCR_MASK) != L0_TABLE)
+ return (false);
+
+ l1p = pmap_l0_to_l1(l0p, va);
*l1 = l1p;
if ((pmap_load(l1p) & ATTR_DESCR_MASK) == L1_BLOCK) {
@@ -544,7 +639,8 @@ pmap_bootstrap_l3(vm_offset_t l1pt, vm_offset_t va, vm_offset_t l3_start)
* Bootstrap the system enough to run with virtual memory.
*/
void
-pmap_bootstrap(vm_offset_t l1pt, vm_paddr_t kernstart, vm_size_t kernlen)
+pmap_bootstrap(vm_offset_t l0pt, vm_offset_t l1pt, vm_paddr_t kernstart,
+ vm_size_t kernlen)
{
u_int l1_slot, l2_slot, avail_slot, map_slot, used_map_slot;
uint64_t kern_delta;
@@ -562,7 +658,7 @@ pmap_bootstrap(vm_offset_t l1pt, vm_paddr_t kernstart, vm_size_t kernlen)
printf("%lx\n", (KERNBASE >> L1_SHIFT) & Ln_ADDR_MASK);
/* Set this early so we can use the pagetable walking functions */
- kernel_pmap_store.pm_l1 = (pd_entry_t *)l1pt;
+ kernel_pmap_store.pm_l0 = (pd_entry_t *)l0pt;
PMAP_LOCK_INIT(kernel_pmap);
/*
@@ -805,30 +901,40 @@ pmap_invalidate_all(pmap_t pmap)
vm_paddr_t
pmap_extract(pmap_t pmap, vm_offset_t va)
{
- pd_entry_t *l2p, l2;
- pt_entry_t *l3p, l3;
+ pt_entry_t *pte, tpte;
vm_paddr_t pa;
+ int lvl;
pa = 0;
PMAP_LOCK(pmap);
/*
- * Start with the l2 tabel. We are unable to allocate
- * pages in the l1 table.
+ * Find the block or page map for this virtual address. pmap_pte
+ * will return either a valid block/page entry, or NULL.
*/
- l2p = pmap_l2(pmap, va);
- if (l2p != NULL) {
- l2 = pmap_load(l2p);
- if ((l2 & ATTR_DESCR_MASK) == L2_TABLE) {
- l3p = pmap_l2_to_l3(l2p, va);
- if (l3p != NULL) {
- l3 = pmap_load(l3p);
-
- if ((l3 & ATTR_DESCR_MASK) == L3_PAGE)
- pa = (l3 & ~ATTR_MASK) |
- (va & L3_OFFSET);
- }
- } else if ((l2 & ATTR_DESCR_MASK) == L2_BLOCK)
- pa = (l2 & ~ATTR_MASK) | (va & L2_OFFSET);
+ pte = pmap_pte(pmap, va, &lvl);
+ if (pte != NULL) {
+ tpte = pmap_load(pte);
+ pa = tpte & ~ATTR_MASK;
+ switch(lvl) {
+ case 1:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L1_BLOCK,
+ ("pmap_extract: Invalid L1 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L1_OFFSET);
+ break;
+ case 2:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L2_BLOCK,
+ ("pmap_extract: Invalid L2 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L2_OFFSET);
+ break;
+ case 3:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L3_PAGE,
+ ("pmap_extract: Invalid L3 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L3_OFFSET);
+ break;
+ }
}
PMAP_UNLOCK(pmap);
return (pa);
@@ -844,21 +950,31 @@ pmap_extract(pmap_t pmap, vm_offset_t va)
vm_page_t
pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
{
- pt_entry_t *l3p, l3;
+ pt_entry_t *pte, tpte;
vm_paddr_t pa;
vm_page_t m;
+ int lvl;
pa = 0;
m = NULL;
PMAP_LOCK(pmap);
retry:
- l3p = pmap_l3(pmap, va);
- if (l3p != NULL && (l3 = pmap_load(l3p)) != 0) {
- if (((l3 & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) ||
+ pte = pmap_pte(pmap, va, &lvl);
+ if (pte != NULL) {
+ tpte = pmap_load(pte);
+
+ KASSERT(lvl > 0 && lvl <= 3,
+ ("pmap_extract_and_hold: Invalid level %d", lvl));
+ CTASSERT(L1_BLOCK == L2_BLOCK);
+ KASSERT((lvl == 3 && (tpte & ATTR_DESCR_MASK) == L3_PAGE) ||
+ (lvl < 3 && (tpte & ATTR_DESCR_MASK) == L1_BLOCK),
+ ("pmap_extract_and_hold: Invalid pte at L%d: %lx", lvl,
+ tpte & ATTR_DESCR_MASK));
+ if (((tpte & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) ||
((prot & VM_PROT_WRITE) == 0)) {
- if (vm_page_pa_tryrelock(pmap, l3 & ~ATTR_MASK, &pa))
+ if (vm_page_pa_tryrelock(pmap, tpte & ~ATTR_MASK, &pa))
goto retry;
- m = PHYS_TO_VM_PAGE(l3 & ~ATTR_MASK);
+ m = PHYS_TO_VM_PAGE(tpte & ~ATTR_MASK);
vm_page_hold(m);
}
}
@@ -870,25 +986,39 @@ retry:
vm_paddr_t
pmap_kextract(vm_offset_t va)
{
- pd_entry_t *l2p, l2;
- pt_entry_t *l3;
+ pt_entry_t *pte, tpte;
vm_paddr_t pa;
+ int lvl;
if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) {
pa = DMAP_TO_PHYS(va);
} else {
- l2p = pmap_l2(kernel_pmap, va);
- if (l2p == NULL)
- panic("pmap_kextract: No l2");
- l2 = pmap_load(l2p);
- if ((l2 & ATTR_DESCR_MASK) == L2_BLOCK)
- return ((l2 & ~ATTR_MASK) |
- (va & L2_OFFSET));
-
- l3 = pmap_l2_to_l3(l2p, va);
- if (l3 == NULL)
- panic("pmap_kextract: No l3...");
- pa = (pmap_load(l3) & ~ATTR_MASK) | (va & PAGE_MASK);
+ pa = 0;
+ pte = pmap_pte(kernel_pmap, va, &lvl);
+ if (pte != NULL) {
+ tpte = pmap_load(pte);
+ pa = tpte & ~ATTR_MASK;
+ switch(lvl) {
+ case 1:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L1_BLOCK,
+ ("pmap_kextract: Invalid L1 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L1_OFFSET);
+ break;
+ case 2:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L2_BLOCK,
+ ("pmap_kextract: Invalid L2 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L2_OFFSET);
+ break;
+ case 3:
+ KASSERT((tpte & ATTR_DESCR_MASK) == L3_PAGE,
+ ("pmap_kextract: Invalid L3 pte found: %lx",
+ tpte & ATTR_DESCR_MASK));
+ pa |= (va & L3_OFFSET);
+ break;
+ }
+ }
}
return (pa);
}
@@ -900,8 +1030,10 @@ pmap_kextract(vm_offset_t va)
void
pmap_kenter_device(vm_offset_t sva, vm_size_t size, vm_paddr_t pa)
{
- pt_entry_t *l3;
+ pd_entry_t *pde;
+ pt_entry_t *pte;
vm_offset_t va;
+ int lvl;
KASSERT((pa & L3_OFFSET) == 0,
("pmap_kenter_device: Invalid physical address"));
@@ -912,11 +1044,16 @@ pmap_kenter_device(vm_offset_t sva, vm_size_t size, vm_paddr_t pa)
va = sva;
while (size != 0) {
- l3 = pmap_l3(kernel_pmap, va);
- KASSERT(l3 != NULL, ("Invalid page table, va: 0x%lx", va));
- pmap_load_store(l3, (pa & ~L3_OFFSET) | ATTR_DEFAULT |
+ pde = pmap_pde(kernel_pmap, va, &lvl);
+ KASSERT(pde != NULL,
+ ("pmap_kenter_device: Invalid page entry, va: 0x%lx", va));
+ KASSERT(lvl == 2,
+ ("pmap_kenter_device: Invalid level %d", lvl));
+
+ pte = pmap_l2_to_l3(pde, va);
+ pmap_load_store(pte, (pa & ~L3_OFFSET) | ATTR_DEFAULT |
ATTR_IDX(DEVICE_MEMORY) | L3_PAGE);
- PTE_SYNC(l3);
+ PTE_SYNC(pte);
va += PAGE_SIZE;
pa += PAGE_SIZE;
@@ -927,28 +1064,30 @@ pmap_kenter_device(vm_offset_t sva, vm_size_t size, vm_paddr_t pa)
/*
* Remove a page from the kernel pagetables.
- * Note: not SMP coherent.
*/
PMAP_INLINE void
pmap_kremove(vm_offset_t va)
{
- pt_entry_t *l3;
+ pt_entry_t *pte;
+ int lvl;
- l3 = pmap_l3(kernel_pmap, va);
- KASSERT(l3 != NULL, ("pmap_kremove: Invalid address"));
+ pte = pmap_pte(kernel_pmap, va, &lvl);
+ KASSERT(pte != NULL, ("pmap_kremove: Invalid address"));
+ KASSERT(lvl == 3, ("pmap_kremove: Invalid pte level %d", lvl));
- if (pmap_l3_valid_cacheable(pmap_load(l3)))
+ if (pmap_l3_valid_cacheable(pmap_load(pte)))
cpu_dcache_wb_range(va, L3_SIZE);
- pmap_load_clear(l3);
- PTE_SYNC(l3);
+ pmap_load_clear(pte);
+ PTE_SYNC(pte);
pmap_invalidate_page(kernel_pmap, va);
}
void
pmap_kremove_device(vm_offset_t sva, vm_size_t size)
{
- pt_entry_t *l3;
+ pt_entry_t *pte;
vm_offset_t va;
+ int lvl;
KASSERT((sva & L3_OFFSET) == 0,
("pmap_kremove_device: Invalid virtual address"));
@@ -957,10 +1096,12 @@ pmap_kremove_device(vm_offset_t sva, vm_size_t size)
va = sva;
while (size != 0) {
- l3 = pmap_l3(kernel_pmap, va);
- KASSERT(l3 != NULL, ("Invalid page table, va: 0x%lx", va));
- pmap_load_clear(l3);
- PTE_SYNC(l3);
+ pte = pmap_pte(kernel_pmap, va, &lvl);
+ KASSERT(pte != NULL, ("Invalid page table, va: 0x%lx", va));
+ KASSERT(lvl == 3,
+ ("Invalid device pagetable level: %d != 3", lvl));
+ pmap_load_clear(pte);
+ PTE_SYNC(pte);
va += PAGE_SIZE;
size -= PAGE_SIZE;
@@ -999,19 +1140,26 @@ pmap_map(vm_offset_t *virt, vm_paddr_t start, vm_paddr_t end, int prot)
void
pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count)
{
- pt_entry_t *l3, pa;
+ pd_entry_t *pde;
+ pt_entry_t *pte, pa;
vm_offset_t va;
vm_page_t m;
- int i;
+ int i, lvl;
va = sva;
for (i = 0; i < count; i++) {
+ pde = pmap_pde(kernel_pmap, va, &lvl);
+ KASSERT(pde != NULL,
+ ("pmap_qenter: Invalid page entry, va: 0x%lx", va));
+ KASSERT(lvl == 2,
+ ("pmap_qenter: Invalid level %d", lvl));
+
m = ma[i];
pa = VM_PAGE_TO_PHYS(m) | ATTR_DEFAULT | ATTR_AP(ATTR_AP_RW) |
ATTR_IDX(m->md.pv_memattr) | L3_PAGE;
- l3 = pmap_l3(kernel_pmap, va);
- pmap_load_store(l3, pa);
- PTE_SYNC(l3);
+ pte = pmap_l2_to_l3(pde, va);
+ pmap_load_store(pte, pa);
+ PTE_SYNC(pte);
va += L3_SIZE;
}
@@ -1021,25 +1169,27 @@ pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count)
/*
* This routine tears out page mappings from the
* kernel -- it is meant only for temporary mappings.
- * Note: SMP coherent. Uses a ranged shootdown IPI.
*/
void
pmap_qremove(vm_offset_t sva, int count)
{
- pt_entry_t *l3;
+ pt_entry_t *pte;
vm_offset_t va;
+ int lvl;
KASSERT(sva >= VM_MIN_KERNEL_ADDRESS, ("usermode va %lx", sva));
va = sva;
while (count-- > 0) {
- l3 = pmap_l3(kernel_pmap, va);
- KASSERT(l3 != NULL, ("pmap_kremove: Invalid address"));
-
- if (pmap_l3_valid_cacheable(pmap_load(l3)))
- cpu_dcache_wb_range(va, L3_SIZE);
- pmap_load_clear(l3);
- PTE_SYNC(l3);
+ pte = pmap_pte(kernel_pmap, va, &lvl);
+ KASSERT(lvl == 3,
+ ("Invalid device pagetable level: %d != 3", lvl));
+ if (pte != NULL) {
+ if (pmap_l3_valid_cacheable(pmap_load(pte)))
+ cpu_dcache_wb_range(va, L3_SIZE);
+ pmap_load_clear(pte);
+ PTE_SYNC(pte);
+ }
va += PAGE_SIZE;
}
@@ -1104,26 +1254,47 @@ _pmap_unwire_l3(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free)
/*
* unmap the page table page
*/
- if (m->pindex >= NUPDE) {
- /* PD page */
+ if (m->pindex >= (NUL2E + NUL1E)) {
+ /* l1 page */
+ pd_entry_t *l0;
+
+ l0 = pmap_l0(pmap, va);
+ pmap_load_clear(l0);
+ PTE_SYNC(l0);
+ } else if (m->pindex >= NUL2E) {
+ /* l2 page */
pd_entry_t *l1;
+
l1 = pmap_l1(pmap, va);
pmap_load_clear(l1);
PTE_SYNC(l1);
} else {
- /* PTE page */
+ /* l3 page */
pd_entry_t *l2;
+
l2 = pmap_l2(pmap, va);
pmap_load_clear(l2);
PTE_SYNC(l2);
}
pmap_resident_count_dec(pmap, 1);
- if (m->pindex < NUPDE) {
- /* We just released a PT, unhold the matching PD */
- vm_page_t pdpg;
+ if (m->pindex < NUL2E) {
+ /* We just released an l3, unhold the matching l2 */
+ pd_entry_t *l1, tl1;
+ vm_page_t l2pg;
- pdpg = PHYS_TO_VM_PAGE(*pmap_l1(pmap, va) & ~ATTR_MASK);
- pmap_unwire_l3(pmap, va, pdpg, free);
+ l1 = pmap_l1(pmap, va);
+ tl1 = pmap_load(l1);
+ l2pg = PHYS_TO_VM_PAGE(tl1 & ~ATTR_MASK);
+ pmap_unwire_l3(pmap, va, l2pg, free);
+ } else if (m->pindex < (NUL2E + NUL1E)) {
+ /* We just released an l2, unhold the matching l1 */
+ pd_entry_t *l0, tl0;
+ vm_page_t l1pg;
+
+ l0 = pmap_l0(pmap, va);
+ tl0 = pmap_load(l0);
+ l1pg = PHYS_TO_VM_PAGE(tl0 & ~ATTR_MASK);
+ pmap_unwire_l3(pmap, va, l1pg, free);
}
pmap_invalidate_page(pmap, va);
@@ -1164,27 +1335,27 @@ pmap_pinit0(pmap_t pmap)
PMAP_LOCK_INIT(pmap);
bzero(&pmap->pm_stats, sizeof(pmap->pm_stats));
- pmap->pm_l1 = kernel_pmap->pm_l1;
+ pmap->pm_l0 = kernel_pmap->pm_l0;
}
int
pmap_pinit(pmap_t pmap)
{
- vm_paddr_t l1phys;
- vm_page_t l1pt;
+ vm_paddr_t l0phys;
+ vm_page_t l0pt;
/*
- * allocate the l1 page
+ * allocate the l0 page
*/
- while ((l1pt = vm_page_alloc(NULL, 0xdeadbeef, VM_ALLOC_NORMAL |
+ while ((l0pt = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL)
VM_WAIT;
- l1phys = VM_PAGE_TO_PHYS(l1pt);
- pmap->pm_l1 = (pd_entry_t *)PHYS_TO_DMAP(l1phys);
+ l0phys = VM_PAGE_TO_PHYS(l0pt);
+ pmap->pm_l0 = (pd_entry_t *)PHYS_TO_DMAP(l0phys);
- if ((l1pt->flags & PG_ZERO) == 0)
- pagezero(pmap->pm_l1);
+ if ((l0pt->flags & PG_ZERO) == 0)
+ pagezero(pmap->pm_l0);
bzero(&pmap->pm_stats, sizeof(pmap->pm_stats));
@@ -1205,7 +1376,7 @@ pmap_pinit(pmap_t pmap)
static vm_page_t
_pmap_alloc_l3(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp)
{
- vm_page_t m, /*pdppg, */pdpg;
+ vm_page_t m, l1pg, l2pg;
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
@@ -1237,33 +1408,84 @@ _pmap_alloc_l3(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp)
* it isn't already there.
*/
- if (ptepindex >= NUPDE) {
- pd_entry_t *l1;
- vm_pindex_t l1index;
+ if (ptepindex >= (NUL2E + NUL1E)) {
+ pd_entry_t *l0;
+ vm_pindex_t l0index;
+
+ l0index = ptepindex - (NUL2E + NUL1E);
+ l0 = &pmap->pm_l0[l0index];
+ pmap_load_store(l0, VM_PAGE_TO_PHYS(m) | L0_TABLE);
+ PTE_SYNC(l0);
+ } else if (ptepindex >= NUL2E) {
+ vm_pindex_t l0index, l1index;
+ pd_entry_t *l0, *l1;
+ pd_entry_t tl0;
+
+ l1index = ptepindex - NUL2E;
+ l0index = l1index >> L0_ENTRIES_SHIFT;
+
+ l0 = &pmap->pm_l0[l0index];
+ tl0 = pmap_load(l0);
+ if (tl0 == 0) {
+ /* recurse for allocating page dir */
+ if (_pmap_alloc_l3(pmap, NUL2E + NUL1E + l0index,
+ lockp) == NULL) {
+ --m->wire_count;
+ /* XXX: release mem barrier? */
+ atomic_subtract_int(&vm_cnt.v_wire_count, 1);
+ vm_page_free_zero(m);
+ return (NULL);
+ }
+ } else {
+ l1pg = PHYS_TO_VM_PAGE(tl0 & ~ATTR_MASK);
+ l1pg->wire_count++;
+ }
- l1index = ptepindex - NUPDE;
- l1 = &pmap->pm_l1[l1index];
+ l1 = (pd_entry_t *)PHYS_TO_DMAP(pmap_load(l0) & ~ATTR_MASK);
+ l1 = &l1[ptepindex & Ln_ADDR_MASK];
pmap_load_store(l1, VM_PAGE_TO_PHYS(m) | L1_TABLE);
PTE_SYNC(l1);
-
} else {
- vm_pindex_t l1index;
- pd_entry_t *l1, *l2;
+ vm_pindex_t l0index, l1index;
+ pd_entry_t *l0, *l1, *l2;
+ pd_entry_t tl0, tl1;
- l1index = ptepindex >> (L1_SHIFT - L2_SHIFT);
- l1 = &pmap->pm_l1[l1index];
- if (pmap_load(l1) == 0) {
+ l1index = ptepindex >> Ln_ENTRIES_SHIFT;
+ l0index = l1index >> L0_ENTRIES_SHIFT;
+
+ l0 = &pmap->pm_l0[l0index];
+ tl0 = pmap_load(l0);
+ if (tl0 == 0) {
/* recurse for allocating page dir */
- if (_pmap_alloc_l3(pmap, NUPDE + l1index,
+ if (_pmap_alloc_l3(pmap, NUL2E + l1index,
lockp) == NULL) {
--m->wire_count;
atomic_subtract_int(&vm_cnt.v_wire_count, 1);
vm_page_free_zero(m);
return (NULL);
}
+ tl0 = pmap_load(l0);
+ l1 = (pd_entry_t *)PHYS_TO_DMAP(tl0 & ~ATTR_MASK);
+ l1 = &l1[l1index & Ln_ADDR_MASK];
} else {
- pdpg = PHYS_TO_VM_PAGE(pmap_load(l1) & ~ATTR_MASK);
- pdpg->wire_count++;
+ l1 = (pd_entry_t *)PHYS_TO_DMAP(tl0 & ~ATTR_MASK);
+ l1 = &l1[l1index & Ln_ADDR_MASK];
+ tl1 = pmap_load(l1);
+ if (tl1 == 0) {
+ /* recurse for allocating page dir */
+ if (_pmap_alloc_l3(pmap, NUL2E + l1index,
+ lockp) == NULL) {
+ --m->wire_count;
+ /* XXX: release mem barrier? */
+ atomic_subtract_int(
+ &vm_cnt.v_wire_count, 1);
+ vm_page_free_zero(m);
+ return (NULL);
+ }
+ } else {
+ l2pg = PHYS_TO_VM_PAGE(tl1 & ~ATTR_MASK);
+ l2pg->wire_count++;
+ }
}
l2 = (pd_entry_t *)PHYS_TO_DMAP(pmap_load(l1) & ~ATTR_MASK);
@@ -1281,8 +1503,9 @@ static vm_page_t
pmap_alloc_l3(pmap_t pmap, vm_offset_t va, struct rwlock **lockp)
{
vm_pindex_t ptepindex;
- pd_entry_t *l2;
+ pd_entry_t *pde, tpde;
vm_page_t m;
+ int lvl;
/*
* Calculate pagetable page index
@@ -1292,24 +1515,29 @@ retry:
/*
* Get the page directory entry
*/
- l2 = pmap_l2(pmap, va);
+ pde = pmap_pde(pmap, va, &lvl);
/*
- * If the page table page is mapped, we just increment the
- * hold count, and activate it.
+ * If the page table page is mapped, we just increment the hold count,
+ * and activate it. If we get a level 2 pde it will point to a level 3
+ * table.
*/
- if (l2 != NULL && pmap_load(l2) != 0) {
- m = PHYS_TO_VM_PAGE(pmap_load(l2) & ~ATTR_MASK);
- m->wire_count++;
- } else {
- /*
- * Here if the pte page isn't mapped, or if it has been
- * deallocated.
- */
- m = _pmap_alloc_l3(pmap, ptepindex, lockp);
- if (m == NULL && lockp != NULL)
- goto retry;
+ if (lvl == 2) {
+ tpde = pmap_load(pde);
+ if (tpde != 0) {
+ m = PHYS_TO_VM_PAGE(tpde & ~ATTR_MASK);
+ m->wire_count++;
+ return (m);
+ }
}
+
+ /*
+ * Here if the pte page isn't mapped, or if it has been deallocated.
+ */
+ m = _pmap_alloc_l3(pmap, ptepindex, lockp);
+ if (m == NULL && lockp != NULL)
+ goto retry;
+
return (m);
}
@@ -1332,7 +1560,7 @@ pmap_release(pmap_t pmap)
("pmap_release: pmap resident count %ld != 0",
pmap->pm_stats.resident_count));
- m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_l1));
+ m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_l0));
m->wire_count--;
atomic_subtract_int(&vm_cnt.v_wire_count, 1);
@@ -1369,7 +1597,7 @@ pmap_growkernel(vm_offset_t addr)
{
vm_paddr_t paddr;
vm_page_t nkpg;
- pd_entry_t *l1, *l2;
+ pd_entry_t *l0, *l1, *l2;
mtx_assert(&kernel_map->system_mtx, MA_OWNED);
@@ -1377,7 +1605,11 @@ pmap_growkernel(vm_offset_t addr)
if (addr - 1 >= kernel_map->max_offset)
addr = kernel_map->max_offset;
while (kernel_vm_end < addr) {
- l1 = pmap_l1(kernel_pmap, kernel_vm_end);
+ l0 = pmap_l0(kernel_pmap, kernel_vm_end);
+ KASSERT(pmap_load(l0) != 0,
+ ("pmap_growkernel: No level 0 kernel entry"));
+
+ l1 = pmap_l0_to_l1(l0, kernel_vm_end);
if (pmap_load(l1) == 0) {
/* We need a new PDP entry */
nkpg = vm_page_alloc(NULL, kernel_vm_end >> L1_SHIFT,
@@ -1716,7 +1948,7 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
{
struct rwlock *lock;
vm_offset_t va, va_next;
- pd_entry_t *l1, *l2;
+ pd_entry_t *l0, *l1, *l2;
pt_entry_t l3_paddr, *l3;
struct spglist free;
int anyvalid;
@@ -1739,7 +1971,15 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
if (pmap->pm_stats.resident_count == 0)
break;
- l1 = pmap_l1(pmap, sva);
+ l0 = pmap_l0(pmap, sva);
+ if (pmap_load(l0) == 0) {
+ va_next = (sva + L0_SIZE) & ~L0_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ l1 = pmap_l0_to_l1(l0, sva);
if (pmap_load(l1) == 0) {
va_next = (sva + L1_SIZE) & ~L1_OFFSET;
if (va_next < sva)
@@ -1824,9 +2064,10 @@ pmap_remove_all(vm_page_t m)
{
pv_entry_t pv;
pmap_t pmap;
- pt_entry_t *l3, tl3;
- pd_entry_t *l2, tl2;
+ pd_entry_t *pde, tpde;
+ pt_entry_t *pte, tpte;
struct spglist free;
+ int lvl;
KASSERT((m->oflags & VPO_UNMANAGED) == 0,
("pmap_remove_all: page %p is not managed", m));
@@ -1836,30 +2077,33 @@ pmap_remove_all(vm_page_t m)
pmap = PV_PMAP(pv);
PMAP_LOCK(pmap);
pmap_resident_count_dec(pmap, 1);
- l2 = pmap_l2(pmap, pv->pv_va);
- KASSERT(l2 != NULL, ("pmap_remove_all: no l2 table found"));
- tl2 = pmap_load(l2);
- KASSERT((tl2 & ATTR_DESCR_MASK) == L2_TABLE,
- ("pmap_remove_all: found a table when expecting "
- "a block in %p's pv list", m));
- l3 = pmap_l2_to_l3(l2, pv->pv_va);
+
+ pde = pmap_pde(pmap, pv->pv_va, &lvl);
+ KASSERT(pde != NULL,
+ ("pmap_remove_all: no page directory entry found"));
+ KASSERT(lvl == 2,
+ ("pmap_remove_all: invalid pde level %d", lvl));
+ tpde = pmap_load(pde);
+
+ pte = pmap_l2_to_l3(pde, pv->pv_va);
+ tpte = pmap_load(pte);
if (pmap_is_current(pmap) &&
- pmap_l3_valid_cacheable(pmap_load(l3)))
+ pmap_l3_valid_cacheable(tpte))
cpu_dcache_wb_range(pv->pv_va, L3_SIZE);
- tl3 = pmap_load_clear(l3);
- PTE_SYNC(l3);
+ pmap_load_clear(pte);
+ PTE_SYNC(pte);
pmap_invalidate_page(pmap, pv->pv_va);
- if (tl3 & ATTR_SW_WIRED)
+ if (tpte & ATTR_SW_WIRED)
pmap->pm_stats.wired_count--;
- if ((tl3 & ATTR_AF) != 0)
+ if ((tpte & ATTR_AF) != 0)
vm_page_aflag_set(m, PGA_REFERENCED);
/*
* Update the vm_page_t clean and reference bits.
*/
- if (pmap_page_dirty(tl3))
+ if (pmap_page_dirty(tpte))
vm_page_dirty(m);
- pmap_unuse_l3(pmap, pv->pv_va, tl2, &free);
+ pmap_unuse_l3(pmap, pv->pv_va, tpde, &free);
TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
m->md.pv_gen++;
free_pv_entry(pmap, pv);
@@ -1878,7 +2122,7 @@ void
pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
{
vm_offset_t va, va_next;
- pd_entry_t *l1, *l2;
+ pd_entry_t *l0, *l1, *l2;
pt_entry_t *l3p, l3;
if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
@@ -1892,7 +2136,15 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
PMAP_LOCK(pmap);
for (; sva < eva; sva = va_next) {
- l1 = pmap_l1(pmap, sva);
+ l0 = pmap_l0(pmap, sva);
+ if (pmap_load(l0) == 0) {
+ va_next = (sva + L0_SIZE) & ~L0_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ l1 = pmap_l0_to_l1(l0, sva);
if (pmap_load(l1) == 0) {
va_next = (sva + L1_SIZE) & ~L1_OFFSET;
if (va_next < sva)
@@ -1946,13 +2198,14 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
u_int flags, int8_t psind __unused)
{
struct rwlock *lock;
- pd_entry_t *l1, *l2;
+ pd_entry_t *pde;
pt_entry_t new_l3, orig_l3;
pt_entry_t *l3;
pv_entry_t pv;
- vm_paddr_t opa, pa, l2_pa, l3_pa;
- vm_page_t mpte, om, l2_m, l3_m;
+ vm_paddr_t opa, pa, l1_pa, l2_pa, l3_pa;
+ vm_page_t mpte, om, l1_m, l2_m, l3_m;
boolean_t nosleep;
+ int lvl;
va = trunc_page(va);
if ((m->oflags & VPO_UNMANAGED) == 0 && !vm_page_xbusied(m))
@@ -1986,14 +2239,44 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
PMAP_UNLOCK(pmap);
return (KERN_RESOURCE_SHORTAGE);
}
- l3 = pmap_l3(pmap, va);
+ pde = pmap_pde(pmap, va, &lvl);
+ KASSERT(pde != NULL,
+ ("pmap_enter: Invalid page entry, va: 0x%lx", va));
+ KASSERT(lvl == 2,
+ ("pmap_enter: Invalid level %d", lvl));
+
+ l3 = pmap_l2_to_l3(pde, va);
} else {
- l3 = pmap_l3(pmap, va);
- /* TODO: This is not optimal, but should mostly work */
- if (l3 == NULL) {
- l2 = pmap_l2(pmap, va);
+ pde = pmap_pde(pmap, va, &lvl);
+ /*
+ * If we get a level 2 pde it must point to a level 3 entry
+ * otherwise we will need to create the intermediate tables
+ */
+ if (lvl < 2) {
+ switch(lvl) {
+ default:
+ case -1:
+ /* Get the l0 pde to update */
+ pde = pmap_l0(pmap, va);
+ KASSERT(pde != NULL, ("..."));
+
+ l1_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO);
+ if (l1_m == NULL)
+ panic("pmap_enter: l1 pte_m == NULL");
+ if ((l1_m->flags & PG_ZERO) == 0)
+ pmap_zero_page(l1_m);
+
+ l1_pa = VM_PAGE_TO_PHYS(l1_m);
+ pmap_load_store(pde, l1_pa | L0_TABLE);
+ PTE_SYNC(pde);
+ /* FALLTHROUGH */
+ case 0:
+ /* Get the l1 pde to update */
+ pde = pmap_l1_to_l2(pde, va);
+ KASSERT(pde != NULL, ("..."));
- if (l2 == NULL) {
l2_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
VM_ALLOC_ZERO);
@@ -2003,27 +2286,28 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
pmap_zero_page(l2_m);
l2_pa = VM_PAGE_TO_PHYS(l2_m);
- l1 = pmap_l1(pmap, va);
- pmap_load_store(l1, l2_pa | L1_TABLE);
- PTE_SYNC(l1);
- l2 = pmap_l1_to_l2(l1, va);
+ pmap_load_store(pde, l2_pa | L1_TABLE);
+ PTE_SYNC(pde);
+ /* FALLTHROUGH */
+ case 1:
+ /* Get the l2 pde to update */
+ pde = pmap_l1_to_l2(pde, va);
+
+ l3_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
+ VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO);
+ if (l3_m == NULL)
+ panic("pmap_enter: l3 pte_m == NULL");
+ if ((l3_m->flags & PG_ZERO) == 0)
+ pmap_zero_page(l3_m);
+
+ l3_pa = VM_PAGE_TO_PHYS(l3_m);
+ pmap_load_store(pde, l3_pa | L2_TABLE);
+ PTE_SYNC(pde);
+ break;
}
-
- KASSERT(l2 != NULL,
- ("No l2 table after allocating one"));
-
- l3_m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL |
- VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO);
- if (l3_m == NULL)
- panic("pmap_enter: l3 pte_m == NULL");
- if ((l3_m->flags & PG_ZERO) == 0)
- pmap_zero_page(l3_m);
-
- l3_pa = VM_PAGE_TO_PHYS(l3_m);
- pmap_load_store(l2, l3_pa | L2_TABLE);
- PTE_SYNC(l2);
- l3 = pmap_l2_to_l3(l2, va);
}
+ l3 = pmap_l2_to_l3(pde, va);
pmap_invalidate_page(pmap, va);
}
@@ -2207,9 +2491,10 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
vm_prot_t prot, vm_page_t mpte, struct rwlock **lockp)
{
struct spglist free;
- pd_entry_t *l2;
+ pd_entry_t *pde;
pt_entry_t *l3;
vm_paddr_t pa;
+ int lvl;
KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva ||
(m->oflags & VPO_UNMANAGED) != 0,
@@ -2235,7 +2520,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
/*
* Get the l2 entry
*/
- l2 = pmap_l2(pmap, va);
+ pde = pmap_pde(pmap, va, &lvl);
/*
* If the page table page is mapped, we just increment
@@ -2243,9 +2528,9 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
* attempt to allocate a page table page. If this
* attempt fails, we don't retry. Instead, we give up.
*/
- if (l2 != NULL && pmap_load(l2) != 0) {
+ if (lvl == 2 && pmap_load(pde) != 0) {
mpte =
- PHYS_TO_VM_PAGE(pmap_load(l2) & ~ATTR_MASK);
+ PHYS_TO_VM_PAGE(pmap_load(pde) & ~ATTR_MASK);
mpte->wire_count++;
} else {
/*
@@ -2261,10 +2546,15 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
l3 = &l3[pmap_l3_index(va)];
} else {
mpte = NULL;
- l3 = pmap_l3(kernel_pmap, va);
+ pde = pmap_pde(kernel_pmap, va, &lvl);
+ KASSERT(pde != NULL,
+ ("pmap_enter_quick_locked: Invalid page entry, va: 0x%lx",
+ va));
+ KASSERT(lvl == 2,
+ ("pmap_enter_quick_locked: Invalid level %d", lvl));
+ l3 = pmap_l2_to_l3(pde, va);
}
- if (l3 == NULL)
- panic("pmap_enter_quick_locked: No l3");
+
if (pmap_load(l3) != 0) {
if (mpte != NULL) {
mpte->wire_count--;
@@ -2336,14 +2626,22 @@ void
pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
{
vm_offset_t va_next;
- pd_entry_t *l1, *l2;
+ pd_entry_t *l0, *l1, *l2;
pt_entry_t *l3;
boolean_t pv_lists_locked;
pv_lists_locked = FALSE;
PMAP_LOCK(pmap);
for (; sva < eva; sva = va_next) {
- l1 = pmap_l1(pmap, sva);
+ l0 = pmap_l0(pmap, sva);
+ if (pmap_load(l0) == 0) {
+ va_next = (sva + L0_SIZE) & ~L0_OFFSET;
+ if (va_next < sva)
+ va_next = eva;
+ continue;
+ }
+
+ l1 = pmap_l0_to_l1(l0, sva);
if (pmap_load(l1) == 0) {
va_next = (sva + L1_SIZE) & ~L1_OFFSET;
if (va_next < sva)
@@ -2551,9 +2849,9 @@ pmap_page_wired_mappings(vm_page_t m)
{
struct rwlock *lock;
pmap_t pmap;
- pt_entry_t *l3;
+ pt_entry_t *pte;
pv_entry_t pv;
- int count, md_gen;
+ int count, lvl, md_gen;
if ((m->oflags & VPO_UNMANAGED) != 0)
return (0);
@@ -2574,8 +2872,8 @@ restart:
goto restart;
}
}
- l3 = pmap_l3(pmap, pv->pv_va);
- if (l3 != NULL && (pmap_load(l3) & ATTR_SW_WIRED) != 0)
+ pte = pmap_pte(pmap, pv->pv_va, &lvl);
+ if (pte != NULL && (pmap_load(pte) & ATTR_SW_WIRED) != 0)
count++;
PMAP_UNLOCK(pmap);
}
@@ -2603,8 +2901,8 @@ restart:
void
pmap_remove_pages(pmap_t pmap)
{
- pd_entry_t ptepde, *l2;
- pt_entry_t *l3, tl3;
+ pd_entry_t *pde;
+ pt_entry_t *pte, tpte;
struct spglist free;
vm_page_t m;
pv_entry_t pv;
@@ -2612,7 +2910,7 @@ pmap_remove_pages(pmap_t pmap)
struct rwlock *lock;
int64_t bit;
uint64_t inuse, bitmask;
- int allfree, field, freed, idx;
+ int allfree, field, freed, idx, lvl;
vm_paddr_t pa;
lock = NULL;
@@ -2632,44 +2930,51 @@ pmap_remove_pages(pmap_t pmap)
pv = &pc->pc_pventry[idx];
inuse &= ~bitmask;
- l2 = pmap_l2(pmap, pv->pv_va);
- ptepde = pmap_load(l2);
- l3 = pmap_l2_to_l3(l2, pv->pv_va);
- tl3 = pmap_load(l3);
+ pde = pmap_pde(pmap, pv->pv_va, &lvl);
+ KASSERT(pde != NULL,
+ ("Attempting to remove an unmapped page"));
+ KASSERT(lvl == 2,
+ ("Invalid page directory level: %d", lvl));
+
+ pte = pmap_l2_to_l3(pde, pv->pv_va);
+ KASSERT(pte != NULL,
+ ("Attempting to remove an unmapped page"));
+
+ tpte = pmap_load(pte);
/*
* We cannot remove wired pages from a process' mapping at this time
*/
- if (tl3 & ATTR_SW_WIRED) {
+ if (tpte & ATTR_SW_WIRED) {
allfree = 0;
continue;
}
- pa = tl3 & ~ATTR_MASK;
+ pa = tpte & ~ATTR_MASK;
m = PHYS_TO_VM_PAGE(pa);
KASSERT(m->phys_addr == pa,
("vm_page_t %p phys_addr mismatch %016jx %016jx",
m, (uintmax_t)m->phys_addr,
- (uintmax_t)tl3));
+ (uintmax_t)tpte));
KASSERT((m->flags & PG_FICTITIOUS) != 0 ||
m < &vm_page_array[vm_page_array_size],
- ("pmap_remove_pages: bad l3 %#jx",
- (uintmax_t)tl3));
+ ("pmap_remove_pages: bad pte %#jx",
+ (uintmax_t)tpte));
+ /* XXX: assumes tpte is level 3 */
if (pmap_is_current(pmap) &&
- pmap_l3_valid_cacheable(pmap_load(l3)))
+ pmap_l3_valid_cacheable(tpte))
cpu_dcache_wb_range(pv->pv_va, L3_SIZE);
- pmap_load_clear(l3);
- PTE_SYNC(l3);
+ pmap_load_clear(pte);
+ PTE_SYNC(pte);
pmap_invalidate_page(pmap, pv->pv_va);
/*
* Update the vm_page_t clean/reference bits.
*/
- if ((tl3 & ATTR_AP_RW_BIT) ==
- ATTR_AP(ATTR_AP_RW))
+ if ((tpte & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW))
vm_page_dirty(m);
CHANGE_PV_LIST_LOCK_TO_VM_PAGE(&lock, m);
@@ -2681,7 +2986,8 @@ pmap_remove_pages(pmap_t pmap)
TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
m->md.pv_gen++;
- pmap_unuse_l3(pmap, pv->pv_va, ptepde, &free);
+ pmap_unuse_l3(pmap, pv->pv_va, pmap_load(pde),
+ &free);
freed++;
}
}
@@ -2711,9 +3017,9 @@ pmap_page_test_mappings(vm_page_t m, boolean_t accessed, boolean_t modified)
{
struct rwlock *lock;
pv_entry_t pv;
- pt_entry_t *l3, mask, value;
+ pt_entry_t *pte, mask, value;
pmap_t pmap;
- int md_gen;
+ int lvl, md_gen;
boolean_t rv;
rv = FALSE;
@@ -2733,7 +3039,9 @@ restart:
goto restart;
}
}
- l3 = pmap_l3(pmap, pv->pv_va);
+ pte = pmap_pte(pmap, pv->pv_va, &lvl);
+ KASSERT(lvl == 3,
+ ("pmap_page_test_mappings: Invalid level %d", lvl));
mask = 0;
value = 0;
if (modified) {
@@ -2744,7 +3052,7 @@ restart:
mask |= ATTR_AF | ATTR_DESCR_MASK;
value |= ATTR_AF | L3_PAGE;
}
- rv = (pmap_load(l3) & mask) == value;
+ rv = (pmap_load(pte) & mask) == value;
PMAP_UNLOCK(pmap);
if (rv)
goto out;
@@ -2788,13 +3096,14 @@ pmap_is_modified(vm_page_t m)
boolean_t
pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr)
{
- pt_entry_t *l3;
+ pt_entry_t *pte;
boolean_t rv;
+ int lvl;
rv = FALSE;
PMAP_LOCK(pmap);
- l3 = pmap_l3(pmap, addr);
- if (l3 != NULL && pmap_load(l3) != 0) {
+ pte = pmap_pte(pmap, addr, &lvl);
+ if (pte != NULL && pmap_load(pte) != 0) {
rv = TRUE;
}
PMAP_UNLOCK(pmap);
@@ -2825,8 +3134,8 @@ pmap_remove_write(vm_page_t m)
pmap_t pmap;
struct rwlock *lock;
pv_entry_t pv;
- pt_entry_t *l3, oldl3;
- int md_gen;
+ pt_entry_t oldpte, *pte;
+ int lvl, md_gen;
KASSERT((m->oflags & VPO_UNMANAGED) == 0,
("pmap_remove_write: page %p is not managed", m));
@@ -2856,14 +3165,14 @@ retry_pv_loop:
goto retry_pv_loop;
}
}
- l3 = pmap_l3(pmap, pv->pv_va);
+ pte = pmap_pte(pmap, pv->pv_va, &lvl);
retry:
- oldl3 = pmap_load(l3);
- if ((oldl3 & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) {
- if (!atomic_cmpset_long(l3, oldl3,
- oldl3 | ATTR_AP(ATTR_AP_RO)))
+ oldpte = pmap_load(pte);
+ if ((oldpte & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW)) {
+ if (!atomic_cmpset_long(pte, oldpte,
+ oldpte | ATTR_AP(ATTR_AP_RO)))
goto retry;
- if ((oldl3 & ATTR_AF) != 0)
+ if ((oldpte & ATTR_AF) != 0)
vm_page_dirty(m);
pmap_invalidate_page(pmap, pv->pv_va);
}
@@ -2901,10 +3210,10 @@ pmap_ts_referenced(vm_page_t m)
pv_entry_t pv, pvf;
pmap_t pmap;
struct rwlock *lock;
- pd_entry_t *l2p, l2;
- pt_entry_t *l3;
+ pd_entry_t *pde, tpde;
+ pt_entry_t *pte, tpte;
vm_paddr_t pa;
- int cleared, md_gen, not_cleared;
+ int cleared, md_gen, not_cleared, lvl;
struct spglist free;
KASSERT((m->oflags & VPO_UNMANAGED) == 0,
@@ -2934,28 +3243,31 @@ retry:
goto retry;
}
}
- l2p = pmap_l2(pmap, pv->pv_va);
- KASSERT(l2p != NULL, ("pmap_ts_referenced: no l2 table found"));
- l2 = pmap_load(l2p);
- KASSERT((l2 & ATTR_DESCR_MASK) == L2_TABLE,
+ pde = pmap_pde(pmap, pv->pv_va, &lvl);
+ KASSERT(pde != NULL, ("pmap_ts_referenced: no l2 table found"));
+ KASSERT(lvl == 2,
+ ("pmap_ts_referenced: invalid pde level %d", lvl));
+ tpde = pmap_load(pde);
+ KASSERT((tpde & ATTR_DESCR_MASK) == L2_TABLE,
("pmap_ts_referenced: found an invalid l2 table"));
- l3 = pmap_l2_to_l3(l2p, pv->pv_va);
- if ((pmap_load(l3) & ATTR_AF) != 0) {
- if (safe_to_clear_referenced(pmap, pmap_load(l3))) {
+ pte = pmap_l2_to_l3(pde, pv->pv_va);
+ tpte = pmap_load(pte);
+ if ((tpte & ATTR_AF) != 0) {
+ if (safe_to_clear_referenced(pmap, tpte)) {
/*
* TODO: We don't handle the access flag
* at all. We need to be able to set it in
* the exception handler.
*/
panic("ARM64TODO: safe_to_clear_referenced\n");
- } else if ((pmap_load(l3) & ATTR_SW_WIRED) == 0) {
+ } else if ((tpte & ATTR_SW_WIRED) == 0) {
/*
* Wired pages cannot be paged out so
* doing accessed bit emulation for
* them is wasted effort. We do the
* hard work for unwired pages only.
*/
- pmap_remove_l3(pmap, l3, pv->pv_va, l2,
+ pmap_remove_l3(pmap, pte, pv->pv_va, tpde,
&free, &lock);
pmap_invalidate_page(pmap, pv->pv_va);
cleared++;
@@ -3145,8 +3457,8 @@ pmap_activate(struct thread *td)
critical_enter();
pmap = vmspace_pmap(td->td_proc->p_vmspace);
- td->td_pcb->pcb_l1addr = vtophys(pmap->pm_l1);
- __asm __volatile("msr ttbr0_el1, %0" : : "r"(td->td_pcb->pcb_l1addr));
+ td->td_pcb->pcb_l0addr = vtophys(pmap->pm_l0);
+ __asm __volatile("msr ttbr0_el1, %0" : : "r"(td->td_pcb->pcb_l0addr));
pmap_invalidate_all(pmap);
critical_exit();
}
diff --git a/sys/arm64/arm64/support.S b/sys/arm64/arm64/support.S
index 2f42a84..4938240 100644
--- a/sys/arm64/arm64/support.S
+++ b/sys/arm64/arm64/support.S
@@ -33,6 +33,7 @@
__FBSDID("$FreeBSD$");
#include <machine/setjmp.h>
+#include <machine/param.h>
#include "assym.s"
@@ -290,3 +291,38 @@ ENTRY(longjmp)
mov x0, x1
ret
END(longjmp)
+
+/*
+ * pagezero, simple implementation
+ */
+ENTRY(pagezero_simple)
+ add x1, x0, #PAGE_SIZE
+
+1:
+ stp xzr, xzr, [x0], #0x10
+ stp xzr, xzr, [x0], #0x10
+ stp xzr, xzr, [x0], #0x10
+ stp xzr, xzr, [x0], #0x10
+ cmp x0, x1
+ b.ne 1b
+ ret
+
+END(pagezero_simple)
+
+/*
+ * pagezero, cache assisted
+ */
+ENTRY(pagezero_cache)
+ add x1, x0, #PAGE_SIZE
+
+ ldr x2, =dczva_line_size
+ ldr x2, [x2]
+
+1:
+ dc zva, x0
+ add x0, x0, x2
+ cmp x0, x1
+ b.ne 1b
+ ret
+
+END(pagezero_cache)
diff --git a/sys/arm64/arm64/swtch.S b/sys/arm64/arm64/swtch.S
index 35153c2..1b501a49 100644
--- a/sys/arm64/arm64/swtch.S
+++ b/sys/arm64/arm64/swtch.S
@@ -86,7 +86,7 @@ ENTRY(cpu_throw)
*/
/* Switch to the new pmap */
- ldr x5, [x4, #PCB_L1ADDR]
+ ldr x5, [x4, #PCB_L0ADDR]
msr ttbr0_el1, x5
isb
@@ -183,7 +183,7 @@ ENTRY(cpu_switch)
*/
/* Switch to the new pmap */
- ldr x5, [x4, #PCB_L1ADDR]
+ ldr x5, [x4, #PCB_L0ADDR]
msr ttbr0_el1, x5
isb
diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c
index 6794b1b4..4950fe8 100644
--- a/sys/arm64/arm64/vm_machdep.c
+++ b/sys/arm64/arm64/vm_machdep.c
@@ -84,8 +84,8 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags)
td2->td_pcb = pcb2;
bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
- td2->td_pcb->pcb_l1addr =
- vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l1);
+ td2->td_pcb->pcb_l0addr =
+ vtophys(vmspace_pmap(td2->td_proc->p_vmspace)->pm_l0);
tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1);
bcopy(td1->td_frame, tf, sizeof(*tf));
diff --git a/sys/arm64/cloudabi64/cloudabi64_sysvec.c b/sys/arm64/cloudabi64/cloudabi64_sysvec.c
index cb569cd..a26007a 100644
--- a/sys/arm64/cloudabi64/cloudabi64_sysvec.c
+++ b/sys/arm64/cloudabi64/cloudabi64_sysvec.c
@@ -157,5 +157,6 @@ Elf64_Brandinfo cloudabi64_brand = {
.brand = ELFOSABI_CLOUDABI,
.machine = EM_AARCH64,
.sysvec = &cloudabi64_elf_sysvec,
+ .flags = BI_CAN_EXEC_DYN,
.compat_3_brand = "CloudABI",
};
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index 8b2bc92..40d07f0 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -66,6 +66,12 @@
#define CTR_ILINE_MASK (0xf << CTR_ILINE_SHIFT)
#define CTR_ILINE_SIZE(reg) (((reg) & CTR_ILINE_MASK) >> CTR_ILINE_SHIFT)
+/* DCZID_EL0 - Data Cache Zero ID register */
+#define DCZID_DZP (1 << 4) /* DC ZVA prohibited if non-0 */
+#define DCZID_BS_SHIFT 0
+#define DCZID_BS_MASK (0xf << DCZID_BS_SHIFT)
+#define DCZID_BS_SIZE(reg) (((reg) & DCZID_BS_MASK) >> DCZID_BS_SHIFT)
+
/* ESR_ELx */
#define ESR_ELx_ISS_MASK 0x00ffffff
#define ISS_INSN_FnV (0x01 << 10)
diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h
index 8f14e82..520729c 100644
--- a/sys/arm64/include/cpu.h
+++ b/sys/arm64/include/cpu.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
- * Copyright (c) 2014 The FreeBSD Foundation
+ * Copyright (c) 2014-2016 The FreeBSD Foundation
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -46,7 +46,7 @@
#include <machine/armreg.h>
#define TRAPF_PC(tfp) ((tfp)->tf_lr)
-#define TRAPF_USERMODE(tfp) (((tfp)->tf_elr & (1ul << 63)) == 0)
+#define TRAPF_USERMODE(tfp) (((tfp)->tf_spsr & PSR_M_MASK) == PSR_M_EL0t)
#define cpu_getstack(td) ((td)->td_frame->tf_sp)
#define cpu_setstack(td, sp) ((td)->td_frame->tf_sp = (sp))
diff --git a/sys/arm64/include/intr.h b/sys/arm64/include/intr.h
index 2d7da21..327b249 100644
--- a/sys/arm64/include/intr.h
+++ b/sys/arm64/include/intr.h
@@ -29,8 +29,10 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
-int arm_config_intr(u_int, enum intr_trigger, enum intr_polarity);
-void arm_cpu_intr(struct trapframe *);
+int intr_irq_config(u_int, enum intr_trigger, enum intr_polarity);
+void intr_irq_handler(struct trapframe *);
+int intr_irq_remove_handler(device_t, u_int, void *);
+
void arm_dispatch_intr(u_int, struct trapframe *);
int arm_enable_intr(void);
void arm_mask_irq(u_int);
@@ -44,12 +46,12 @@ int arm_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
int arm_map_msix(device_t, device_t, int, uint64_t *, uint32_t *);
int arm_setup_intr(const char *, driver_filter_t *, driver_intr_t,
void *, u_int, enum intr_type, void **);
-int arm_teardown_intr(void *);
void arm_unmask_irq(u_int);
#ifdef SMP
+int intr_irq_bind(u_int, int);
+
void arm_init_secondary(void);
-int arm_intr_bind(u_int, int);
void arm_setup_ipihandler(driver_filter_t *, u_int);
void arm_unmask_ipi(u_int);
#endif
diff --git a/sys/arm64/include/machdep.h b/sys/arm64/include/machdep.h
index 92c735b..0b1feae 100644
--- a/sys/arm64/include/machdep.h
+++ b/sys/arm64/include/machdep.h
@@ -34,11 +34,13 @@ struct arm64_bootparams {
vm_offset_t kern_l1pt; /* L1 page table for the kernel */
uint64_t kern_delta;
vm_offset_t kern_stack;
+ vm_offset_t kern_l0pt; /* L1 page table for the kernel */
};
extern vm_paddr_t physmap[];
extern u_int physmap_idx;
void initarm(struct arm64_bootparams *);
+extern void (*pagezero)(void *);
#endif /* _MACHINE_MACHDEP_H_ */
diff --git a/sys/arm64/include/pcb.h b/sys/arm64/include/pcb.h
index 55dd6e9..4426226 100644
--- a/sys/arm64/include/pcb.h
+++ b/sys/arm64/include/pcb.h
@@ -40,7 +40,7 @@ struct pcb {
/* These two need to be in order as we access them together */
uint64_t pcb_sp;
uint64_t pcb_tpidr_el0;
- vm_offset_t pcb_l1addr;
+ vm_offset_t pcb_l0addr;
/* Fault handler, the error value is passed in x0 */
vm_offset_t pcb_onfault;
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index 0faf2e8..578eb46 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -78,7 +78,7 @@ struct pv_addr {
struct pmap {
struct mtx pm_mtx;
struct pmap_statistics pm_stats; /* pmap statictics */
- pd_entry_t *pm_l1;
+ pd_entry_t *pm_l0;
TAILQ_HEAD(,pv_chunk) pm_pvchunk; /* list of mappings in pmap */
};
@@ -134,7 +134,7 @@ extern vm_offset_t virtual_end;
#define L1_MAPPABLE_P(va, pa, size) \
((((va) | (pa)) & L1_OFFSET) == 0 && (size) >= L1_SIZE)
-void pmap_bootstrap(vm_offset_t, vm_paddr_t, vm_size_t);
+void pmap_bootstrap(vm_offset_t, vm_offset_t, vm_paddr_t, vm_size_t);
void pmap_kenter_device(vm_offset_t, vm_size_t, vm_paddr_t);
vm_paddr_t pmap_kextract(vm_offset_t va);
void pmap_kremove(vm_offset_t);
@@ -149,7 +149,7 @@ boolean_t pmap_map_io_transient(vm_page_t *, vm_offset_t *, int, boolean_t);
void pmap_unmap_io_transient(vm_page_t *, vm_offset_t *, int, boolean_t);
bool pmap_get_tables(pmap_t, vm_offset_t, pd_entry_t **, pd_entry_t **,
- pt_entry_t **);
+ pd_entry_t **, pt_entry_t **);
#define pmap_page_is_mapped(m) (!TAILQ_EMPTY(&(m)->md.pv_list))
diff --git a/sys/arm64/include/pte.h b/sys/arm64/include/pte.h
index 645cf31..da70dc4 100644
--- a/sys/arm64/include/pte.h
+++ b/sys/arm64/include/pte.h
@@ -73,8 +73,10 @@ typedef uint64_t pt_entry_t; /* page table entry */
/* Level 0 table, 512GiB per entry */
#define L0_SHIFT 39
+#define L0_SIZE (1ul << L0_SHIFT)
+#define L0_OFFSET (L0_SIZE - 1ul)
#define L0_INVAL 0x0 /* An invalid address */
-#define L0_BLOCK 0x1 /* A block */
+ /* 0x1 Level 0 doesn't support block translation */
/* 0x2 also marks an invalid address */
#define L0_TABLE 0x3 /* A next-level table */
@@ -83,16 +85,16 @@ typedef uint64_t pt_entry_t; /* page table entry */
#define L1_SIZE (1 << L1_SHIFT)
#define L1_OFFSET (L1_SIZE - 1)
#define L1_INVAL L0_INVAL
-#define L1_BLOCK L0_BLOCK
+#define L1_BLOCK 0x1
#define L1_TABLE L0_TABLE
/* Level 2 table, 2MiB per entry */
#define L2_SHIFT 21
#define L2_SIZE (1 << L2_SHIFT)
#define L2_OFFSET (L2_SIZE - 1)
-#define L2_INVAL L0_INVAL
-#define L2_BLOCK L0_BLOCK
-#define L2_TABLE L0_TABLE
+#define L2_INVAL L1_INVAL
+#define L2_BLOCK L1_BLOCK
+#define L2_TABLE L1_TABLE
#define L2_BLOCK_MASK UINT64_C(0xffffffe00000)
@@ -106,7 +108,12 @@ typedef uint64_t pt_entry_t; /* page table entry */
/* 0x2 also marks an invalid address */
#define L3_PAGE 0x3
-#define Ln_ENTRIES (1 << 9)
+#define L0_ENTRIES_SHIFT 9
+#define L0_ENTRIES (1 << L0_ENTRIES_SHIFT)
+#define L0_ADDR_MASK (L0_ENTRIES - 1)
+
+#define Ln_ENTRIES_SHIFT 9
+#define Ln_ENTRIES (1 << Ln_ENTRIES_SHIFT)
#define Ln_ADDR_MASK (Ln_ENTRIES - 1)
#define Ln_TABLE_MASK ((1 << 12) - 1)
diff --git a/sys/arm64/include/smp.h b/sys/arm64/include/smp.h
index 0f56396..538981a 100644
--- a/sys/arm64/include/smp.h
+++ b/sys/arm64/include/smp.h
@@ -42,7 +42,7 @@ enum {
IPI_STOP,
IPI_STOP_HARD,
IPI_HARDCLOCK,
- COUNT_IPI,
+ INTR_IPI_COUNT,
};
void ipi_all_but_self(u_int ipi);
diff --git a/sys/arm64/include/vmparam.h b/sys/arm64/include/vmparam.h
index 2752ee1..cd9198e 100644
--- a/sys/arm64/include/vmparam.h
+++ b/sys/arm64/include/vmparam.h
@@ -188,7 +188,7 @@ extern vm_paddr_t dmap_phys_base;
})
#define VM_MIN_USER_ADDRESS (0x0000000000000000UL)
-#define VM_MAX_USER_ADDRESS (0x0000008000000000UL)
+#define VM_MAX_USER_ADDRESS (0x0001000000000000UL)
#define VM_MINUSER_ADDRESS (VM_MIN_USER_ADDRESS)
#define VM_MAXUSER_ADDRESS (VM_MAX_USER_ADDRESS)
diff --git a/sys/boot/Makefile.amd64 b/sys/boot/Makefile.amd64
index 384cf7a..f2ccbad 100644
--- a/sys/boot/Makefile.amd64
+++ b/sys/boot/Makefile.amd64
@@ -3,6 +3,7 @@
SUBDIR+= efi
SUBDIR+= libstand32
SUBDIR+= zfs
+SUBDIR+= geli
SUBDIR+= userboot
.if ${MK_FORTH} != "no"
diff --git a/sys/boot/Makefile.i386 b/sys/boot/Makefile.i386
index e7de353..8244da5 100644
--- a/sys/boot/Makefile.i386
+++ b/sys/boot/Makefile.i386
@@ -3,3 +3,4 @@
SUBDIR+= efi
SUBDIR+= libstand32
SUBDIR+= zfs
+SUBDIR+= geli
diff --git a/sys/boot/common/dev_net.c b/sys/boot/common/dev_net.c
index 873b28d..ed07a2c 100644
--- a/sys/boot/common/dev_net.c
+++ b/sys/boot/common/dev_net.c
@@ -169,6 +169,12 @@ net_open(struct open_file *f, ...)
setenv("boot.netif.gateway", inet_ntoa(gateip), 1);
setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
setenv("boot.nfsroot.path", rootpath, 1);
+ if (intf_mtu != 0) {
+ char mtu[16];
+ sprintf(mtu, "%u", intf_mtu);
+ setenv("boot.netif.mtu", mtu, 1);
+ }
+
}
netdev_opens++;
f->f_devdata = &netdev_sock;
diff --git a/sys/boot/common/disk.c b/sys/boot/common/disk.c
index a8801e1..c862d30 100644
--- a/sys/boot/common/disk.c
+++ b/sys/boot/common/disk.c
@@ -170,7 +170,7 @@ display_size(uint64_t size, u_int sectorsize)
return (buf);
}
-static int
+int
ptblread(void *d, void *buf, size_t blocks, off_t offset)
{
struct disk_devdesc *dev;
diff --git a/sys/boot/common/disk.h b/sys/boot/common/disk.h
index e95256d..d24fb1a 100644
--- a/sys/boot/common/disk.h
+++ b/sys/boot/common/disk.h
@@ -107,6 +107,7 @@ extern int disk_read(struct disk_devdesc *dev, void *buf, off_t offset,
u_int blocks);
extern int disk_write(struct disk_devdesc *dev, void *buf, off_t offset,
u_int blocks);
+extern int ptblread(void *d, void *buf, size_t blocks, off_t offset);
/*
* Print information about slices on a disk.
diff --git a/sys/boot/common/gpt.c b/sys/boot/common/gpt.c
index 8baa64c..7ab3fc6 100644
--- a/sys/boot/common/gpt.c
+++ b/sys/boot/common/gpt.c
@@ -39,8 +39,6 @@ __FBSDID("$FreeBSD$");
#include "util.h"
#include "gpt.h"
-#define MAXTBLENTS 128
-
static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr;
static uint64_t hdr_primary_lba, hdr_backup_lba;
static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS];
diff --git a/sys/boot/common/gpt.h b/sys/boot/common/gpt.h
index c42b40d..9d48564 100644
--- a/sys/boot/common/gpt.h
+++ b/sys/boot/common/gpt.h
@@ -32,6 +32,8 @@
#include <uuid.h>
#include <drv.h>
+#define MAXTBLENTS 128
+
int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf);
int gptfind(const uuid_t *uuid, struct dsk *dskp, int part);
void gptbootfailed(struct dsk *dskp);
diff --git a/sys/boot/efi/Makefile b/sys/boot/efi/Makefile
index 94a975a..21da86f 100644
--- a/sys/boot/efi/Makefile
+++ b/sys/boot/efi/Makefile
@@ -2,8 +2,9 @@
.include <src.opts.mk>
-# In-tree GCC does not support __attribute__((ms_abi)).
-.if ${COMPILER_TYPE} != "gcc"
+# In-tree GCC does not support __attribute__((ms_abi)), but gcc newer
+# than 4.5 supports it.
+.if ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 404500
.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
.if ${MK_FDT} != "no"
@@ -17,7 +18,6 @@ SUBDIR+= fdt
SUBDIR+= libefi loader boot1
.endif
-.endif # ${COMPILER_TYPE} != "gcc"
+.endif # ${COMPILER_TYPE} != "gcc" || ${COMPILER_VERSION} >= 404500
.include <bsd.subdir.mk>
-
diff --git a/sys/boot/fdt/dts/arm/bcm2836.dtsi b/sys/boot/fdt/dts/arm/bcm2836.dtsi
index ce967df..5229d6a 100644
--- a/sys/boot/fdt/dts/arm/bcm2836.dtsi
+++ b/sys/boot/fdt/dts/arm/bcm2836.dtsi
@@ -32,8 +32,8 @@
timer {
compatible = "arm,armv7-timer";
clock-frequency = <19200000>;
- interrupts = <72 73 75 74>;
- interrupt-parent = <&intc>;
+ interrupts = <0 1 3 2>;
+ interrupt-parent = <&local_intc>;
};
SOC: axi {
@@ -41,12 +41,23 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0x3f000000 0x01000000>;
- ranges = <0 0x3f000000 0x01000000>;
+ ranges = <0 0x3f000000 0x01000000>,
+ <0x40000000 0x40000000 0x00001000>;
+
+ local_intc: local_intc {
+ compatible = "brcm,bcm2836-l1-intc";
+ reg = <0x40000000 0x100>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&local_intc>;
+ };
intc: interrupt-controller {
compatible = "broadcom,bcm2835-armctrl-ic",
"broadcom,bcm2708-armctrl-ic";
reg = <0xB200 0x200>;
+ interrupt-parent = <&local_intc>;
+ interrupts = <8>;
interrupt-controller;
#interrupt-cells = <1>;
diff --git a/sys/boot/fdt/dts/arm/beaglebone-black.dts b/sys/boot/fdt/dts/arm/beaglebone-black.dts
index d4f19b2..6605505 100644
--- a/sys/boot/fdt/dts/arm/beaglebone-black.dts
+++ b/sys/boot/fdt/dts/arm/beaglebone-black.dts
@@ -33,15 +33,18 @@
&am33xx_pinmux {
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x158 (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_d1.i2c1_sda */
- 0x15c (PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_cs0.i2c1_scl */
+ AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_d1.i2c1_sda */
+ AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2) /* spi0_cs0.i2c1_scl */
>;
};
- i2c2_pins: pinmux_i2c2_pins {
+ spi1_pins: pinmux_spi1_pins {
pinctrl-single,pins = <
- 0x178 (PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_ctsn.i2c2_sda */
- 0x17c (PIN_INPUT_PULLUP | MUX_MODE3) /* uart1_rtsn.i2c2_scl */
+ AM33XX_IOPAD(0x964, PIN_INPUT_PULLUP | MUX_MODE2) /* eCAP0_in_PWM0_out.spi1_cs1 */
+ AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcasp0_aclkx.spi1_sclk */
+ AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcasp0_fsx.spi1_d0 - miso */
+ AM33XX_IOPAD(0x998, PIN_INPUT_PULLUP | MUX_MODE3) /* mcasp0_axr0.spi1_d1 - mosi */
+ AM33XX_IOPAD(0x99c, PIN_INPUT_PULLUP | MUX_MODE3) /* mcasp0_ahclkr.spi1_cs0 */
>;
};
};
@@ -72,6 +75,13 @@
status = "okay";
};
+&spi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins>;
+
+ status = "okay";
+};
+
&lcdc {
hdmi = <&tda998x>;
};
diff --git a/sys/dev/filemon/filemon_lock.c b/sys/boot/fdt/dts/arm/tegra124-jetson-tk1-fbsd.dts
index 5cac47c..902616b 100644
--- a/sys/dev/filemon/filemon_lock.c
+++ b/sys/boot/fdt/dts/arm/tegra124-jetson-tk1-fbsd.dts
@@ -1,8 +1,11 @@
/*-
- * Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
* All rights reserved.
*
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,10 +15,10 @@
* 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 JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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)
@@ -23,35 +26,21 @@
* 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.
+ *
+ * $FreeBSD$
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-static __inline void
-filemon_lock_read(void)
-{
-
- sx_slock(&access_lock);
-}
-
-static __inline void
-filemon_unlock_read(void)
-{
-
- sx_sunlock(&access_lock);
-}
-
-static __inline void
-filemon_lock_write(void)
-{
+#include "tegra124-jetson-tk1.dts"
- sx_xlock(&access_lock);
-}
+/ {
+ chosen {
+ stdin = &uartd;
+ stdout = &uartd;
+ };
-static __inline void
-filemon_unlock_write(void)
-{
+ memory {
+/* reg = <0x0 0x80000000 0x0 0x80000000>; */
+ reg = <0x0 0x80000000 0x0 0x70000000>;
+ };
- sx_xunlock(&access_lock);
-}
+};
diff --git a/sys/boot/geli/Makefile b/sys/boot/geli/Makefile
new file mode 100644
index 0000000..f5ab243
--- /dev/null
+++ b/sys/boot/geli/Makefile
@@ -0,0 +1,52 @@
+# $FreeBSD$
+# libgeliboot
+
+MAN=
+
+.include <src.opts.mk>
+MK_SSP= no
+
+LIB= geliboot
+INTERNALLIB=
+MK_PROFILE= no
+NO_PIC=
+
+.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
+CFLAGS+= -march=i386
+.endif
+.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -m32
+.endif
+
+WARNS?= 0
+
+# string functions from libc
+.PATH: ${.CURDIR}/../../../lib/libc/string
+SRCS+= bcmp.c bcopy.c bzero.c
+
+# Our password input method
+SRCS+= pwgets.c
+
+# sha256 and sha512 from sys/crypto
+.PATH: ${.CURDIR}/../../crypto/sha2
+CFLAGS+= -DWEAK_REFS
+SRCS+= sha256c.c sha512c.c
+
+# md5 from libmd
+.PATH: ${.CURDIR}/../../../lib/libmd
+SRCS+= md5c.c
+
+# AES implementation from sys/crypto
+.PATH: ${.CURDIR}/../../crypto/rijndael
+CFLAGS+= -I${.CURDIR}/../../
+# Remove asserts
+CFLAGS+= -DNDEBUG
+SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c
+
+# local GELI Implementation
+.PATH: ${.CURDIR}/../../geom/eli
+CFLAGS+= -D_STAND
+SRCS+= geliboot_crypto.c g_eli_hmac.c g_eli_key.c g_eli_key_cache.c pkcs5v2.c
+
+.include <bsd.stand.mk>
+.include <bsd.lib.mk>
diff --git a/sys/boot/geli/Makefile.depend b/sys/boot/geli/Makefile.depend
new file mode 100644
index 0000000..7b57224
--- /dev/null
+++ b/sys/boot/geli/Makefile.depend
@@ -0,0 +1,16 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/libmd \
+ lib/libstand \
+ secure/lib/libcrypto \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/sys/boot/geli/geliboot.c b/sys/boot/geli/geliboot.c
new file mode 100644
index 0000000..becbc5f
--- /dev/null
+++ b/sys/boot/geli/geliboot.c
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head);
+struct geli_list *geli_headp;
+
+static int
+geli_same_device(struct geli_entry *ge, struct dsk *dskp)
+{
+
+ if (geli_e->dsk->drive == dskp->drive &&
+ dskp->part == 255 && geli_e->dsk->part == dskp->slice) {
+ /*
+ * Sometimes slice = slice, and sometimes part = slice
+ * If the incoming struct dsk has part=255, it means look at
+ * the slice instead of the part number
+ */
+ return (0);
+ }
+
+ /* Is this the same device? */
+ if (geli_e->dsk->drive != dskp->drive ||
+ geli_e->dsk->slice != dskp->slice ||
+ geli_e->dsk->part != dskp->part) {
+ return (1);
+ }
+
+ return (0);
+}
+
+void
+geli_init(void)
+{
+
+ geli_count = 0;
+ SLIST_INIT(&geli_head);
+}
+
+/*
+ * Read the last sector of the drive or partition pointed to by dsk and see
+ * if it is GELI encrypted
+ */
+int
+geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf,
+ size_t bytes), struct dsk *dskp, daddr_t lastsector)
+{
+ struct g_eli_metadata md;
+ u_char buf[DEV_BSIZE];
+ int error;
+
+ error = read_func(NULL, dskp, (off_t) lastsector * DEV_BSIZE, &buf,
+ (size_t) DEV_BSIZE);
+ if (error != 0) {
+ return (error);
+ }
+ error = eli_metadata_decode(buf, &md);
+ if (error != 0) {
+ return (error);
+ }
+
+ if ((md.md_flags & G_ELI_FLAG_ONETIME)) {
+ /* Swap device, skip it */
+ return (1);
+ }
+ if (!(md.md_flags & G_ELI_FLAG_BOOT)) {
+ /* Disk is not GELI boot device, skip it */
+ return (1);
+ }
+ if (md.md_iterations < 0) {
+ /* XXX TODO: Support loading key files */
+ /* Disk does not have a passphrase, skip it */
+ return (1);
+ }
+ geli_e = malloc(sizeof(struct geli_entry));
+ if (geli_e == NULL)
+ return (2);
+
+ geli_e->dsk = malloc(sizeof(struct dsk));
+ if (geli_e->dsk == NULL)
+ return (2);
+ memcpy(geli_e->dsk, dskp, sizeof(struct dsk));
+ geli_e->part_end = lastsector;
+ if (dskp->part == 255) {
+ geli_e->dsk->part = dskp->slice;
+ }
+
+ geli_e->md = md;
+ eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE,
+ (lastsector + DEV_BSIZE) * DEV_BSIZE);
+
+ SLIST_INSERT_HEAD(&geli_head, geli_e, entries);
+ geli_count++;
+
+ return (0);
+}
+
+/*
+ * Attempt to decrypt the device
+ */
+int
+geli_attach(struct dsk *dskp, const char *passphrase)
+{
+ u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp;
+ u_int keynum;
+ struct hmac_ctx ctx;
+ int error;
+
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_same_device(geli_e, dskp) != 0) {
+ continue;
+ }
+
+ g_eli_crypto_hmac_init(&ctx, NULL, 0);
+ /*
+ * Prepare Derived-Key from the user passphrase.
+ */
+ if (geli_e->md.md_iterations < 0) {
+ /* XXX TODO: Support loading key files */
+ return (1);
+ } else if (geli_e->md.md_iterations == 0) {
+ g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt,
+ sizeof(geli_e->md.md_salt));
+ g_eli_crypto_hmac_update(&ctx, passphrase,
+ strlen(passphrase));
+ } else if (geli_e->md.md_iterations > 0) {
+ printf("Calculating GELI Decryption Key disk%dp%d @ %lu "
+ "iterations...\n", dskp->unit,
+ (dskp->slice > 0 ? dskp->slice : dskp->part),
+ geli_e->md.md_iterations);
+ u_char dkey[G_ELI_USERKEYLEN];
+
+ pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt,
+ sizeof(geli_e->md.md_salt), passphrase,
+ geli_e->md.md_iterations);
+ g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey));
+ bzero(&dkey, sizeof(dkey));
+ }
+
+ g_eli_crypto_hmac_final(&ctx, key, 0);
+
+ error = g_eli_mkey_decrypt(&geli_e->md, key, mkey, &keynum);
+ bzero(&key, sizeof(key));
+ if (error == -1) {
+ bzero(&mkey, sizeof(mkey));
+ printf("Bad GELI key: %d\n", error);
+ return (error);
+ } else if (error != 0) {
+ bzero(&mkey, sizeof(mkey));
+ printf("Failed to decrypt GELI master key: %d\n", error);
+ return (error);
+ }
+
+ /* Store the keys */
+ bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey));
+ bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey));
+ mkp = mkey + sizeof(geli_e->sc.sc_ivkey);
+ if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) {
+ bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN);
+ } else {
+ /*
+ * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
+ */
+ g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, "\x10", 1,
+ geli_e->sc.sc_ekey, 0);
+ }
+ bzero(&mkey, sizeof(mkey));
+
+ /* Initialize the per-sector IV */
+ switch (geli_e->sc.sc_ealgo) {
+ case CRYPTO_AES_XTS:
+ break;
+ default:
+ SHA256_Init(&geli_e->sc.sc_ivctx);
+ SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey,
+ sizeof(geli_e->sc.sc_ivkey));
+ break;
+ }
+
+ return (0);
+ }
+
+ /* Disk not found */
+ return (2);
+}
+
+int
+is_geli(struct dsk *dskp)
+{
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_same_device(geli_e, dskp) == 0) {
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+int
+geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes)
+{
+ u_char iv[G_ELI_IVKEYLEN];
+ u_char *pbuf;
+ int error;
+ off_t os;
+ uint64_t keyno;
+ size_t n, nb;
+ struct g_eli_key gkey;
+
+ SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) {
+ if (geli_same_device(geli_e, dskp) != 0) {
+ continue;
+ }
+
+ nb = bytes / DEV_BSIZE;
+ for (n = 0; n < nb; n++) {
+ os = offset + (n * DEV_BSIZE);
+ pbuf = buf + (n * DEV_BSIZE);
+
+ g_eli_crypto_ivgen(&geli_e->sc, os, iv, G_ELI_IVKEYLEN);
+
+ /* Get the key that corresponds to this offset */
+ keyno = (os >> G_ELI_KEY_SHIFT) / DEV_BSIZE;
+ g_eli_key_fill(&geli_e->sc, &gkey, keyno);
+
+ error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf,
+ DEV_BSIZE, gkey.gek_key, geli_e->sc.sc_ekeylen, iv);
+
+ if (error != 0) {
+ bzero(&gkey, sizeof(gkey));
+ printf("Failed to decrypt in geli_read()!");
+ return (error);
+ }
+ }
+ bzero(&gkey, sizeof(gkey));
+ return (0);
+ }
+
+ printf("GELI provider not found\n");
+ return (1);
+}
+
+int
+geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp)
+{
+ int i;
+
+ /* TODO: Implement GELI keyfile(s) support */
+ for (i = 0; i < 3; i++) {
+ /* Try cached passphrase */
+ if (i == 0 && pw[0] != '\0') {
+ if (geli_attach(dskp, pw) == 0) {
+ return (0);
+ }
+ }
+ printf("GELI Passphrase for disk%d%c%d: ", disk, parttype, part);
+ pwgets(pw, GELI_PW_MAXLEN);
+ printf("\n");
+ if (geli_attach(dskp, pw) == 0) {
+ return (0);
+ }
+ }
+
+ return (1);
+}
diff --git a/sys/boot/geli/geliboot.h b/sys/boot/geli/geliboot.h
new file mode 100644
index 0000000..36bebcc
--- /dev/null
+++ b/sys/boot/geli/geliboot.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#ifndef _GELIBOOT_H_
+#define _GELIBOOT_H_
+
+#define _STRING_H_
+#define _STRINGS_H_
+#define _STDIO_H_
+#include <geom/eli/g_eli.h>
+#include <geom/eli/pkcs5v2.h>
+
+/* Pull in the md5, sha256, and sha512 implementations */
+#include <md5.h>
+#include <crypto/sha2/sha256.h>
+#include <crypto/sha2/sha512.h>
+
+/* Pull in AES implementation */
+#include <crypto/rijndael/rijndael-api-fst.h>
+
+/* AES-XTS implementation */
+#define _STAND
+#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */
+#include <opencrypto/xform_enc.h>
+
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 512
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define GELI_PW_MAXLEN 256
+extern void pwgets(char *buf, int n);
+
+struct geli_entry {
+ struct dsk *dsk;
+ off_t part_end;
+ struct g_eli_softc sc;
+ struct g_eli_metadata md;
+ SLIST_ENTRY(geli_entry) entries;
+} *geli_e, *geli_e_tmp;
+
+int geli_count;
+
+void geli_init(void);
+int geli_taste(int read_func(void *vdev, void *priv, off_t off,
+ void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector);
+int geli_attach(struct dsk *dskp, const char *passphrase);
+int is_geli(struct dsk *dsk);
+int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes);
+int geli_decrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize, const uint8_t* iv);
+int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp);
+
+#endif /* _GELIBOOT_H_ */
diff --git a/sys/boot/geli/geliboot_crypto.c b/sys/boot/geli/geliboot_crypto.c
new file mode 100644
index 0000000..1596236
--- /dev/null
+++ b/sys/boot/geli/geliboot_crypto.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * Copyright (c) 2015 Allan Jude <allanjude@FreeBSD.org>
+ * 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "geliboot.h"
+
+int
+geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize, u_char *iv)
+{
+ keyInstance aeskey;
+ cipherInstance cipher;
+ struct aes_xts_ctx xtsctx, *ctxp;
+ size_t xts_len;
+ int err, blks, i;
+
+ switch (algo) {
+ case CRYPTO_AES_CBC:
+ err = rijndael_makeKey(&aeskey, !enc, keysize,
+ (const char *)key);
+ if (err < 0) {
+ printf("Failed to setup decryption keys: %d\n", err);
+ return (err);
+ }
+
+ err = rijndael_cipherInit(&cipher, MODE_CBC, iv);
+ if (err < 0) {
+ printf("Failed to setup IV: %d\n", err);
+ return (err);
+ }
+
+ switch (enc) {
+ case 0: /* decrypt */
+ blks = rijndael_blockDecrypt(&cipher, &aeskey, data,
+ datasize * 8, data);
+ break;
+ case 1: /* encrypt */
+ blks = rijndael_blockEncrypt(&cipher, &aeskey, data,
+ datasize * 8, data);
+ break;
+ }
+ if (datasize != (blks / 8)) {
+ printf("Failed to decrypt the entire input: "
+ "%u != %u\n", blks, datasize);
+ return (1);
+ }
+ break;
+ case CRYPTO_AES_XTS:
+ xts_len = keysize << 1;
+ ctxp = &xtsctx;
+
+ rijndael_set_key(&ctxp->key1, key, xts_len / 2);
+ rijndael_set_key(&ctxp->key2, key + (xts_len / 16), xts_len / 2);
+
+ enc_xform_aes_xts.reinit(ctxp, iv);
+
+ switch (enc) {
+ case 0: /* decrypt */
+ for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+ enc_xform_aes_xts.decrypt(ctxp, data + i);
+ }
+ break;
+ case 1: /* encrypt */
+ for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) {
+ enc_xform_aes_xts.encrypt(ctxp, data + i);
+ }
+ break;
+ }
+ break;
+ default:
+ printf("Unsupported crypto algorithm #%d\n", algo);
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+ u_char iv[keysize];
+
+ bzero(iv, sizeof(iv));
+ return (geliboot_crypt(algo, enc, data, datasize, key, keysize, iv));
+}
+
+int
+g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+
+ /* We prefer AES-CBC for metadata protection. */
+ if (algo == CRYPTO_AES_XTS)
+ algo = CRYPTO_AES_CBC;
+
+ return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
+}
+
+int
+g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
+ const u_char *key, size_t keysize)
+{
+
+ /* We prefer AES-CBC for metadata protection. */
+ if (algo == CRYPTO_AES_XTS)
+ algo = CRYPTO_AES_CBC;
+
+ return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
+}
diff --git a/sys/boot/geli/pwgets.c b/sys/boot/geli/pwgets.c
new file mode 100644
index 0000000..aca6c3c
--- /dev/null
+++ b/sys/boot/geli/pwgets.c
@@ -0,0 +1,83 @@
+/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ * @(#)gets.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+/* gets() with constrained input length, for passwords */
+
+void
+pwgets(char *buf, int n)
+{
+ int c;
+ char *lp;
+
+ for (lp = buf;;)
+ switch (c = getchar() & 0177) {
+ case '\n':
+ case '\r':
+ *lp = '\0';
+ putchar('\n');
+ return;
+ case '\b':
+ case '\177':
+ if (lp > buf) {
+ lp--;
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ }
+ break;
+ case 'r'&037: {
+ char *p;
+
+ putchar('\n');
+ for (p = buf; p < lp; ++p)
+ putchar(*p);
+ break;
+ }
+ case 'u'&037:
+ case 'w'&037:
+ lp = buf;
+ putchar('\n');
+ break;
+ default:
+ if ((n < 1) || ((lp - buf) < n - 1)) {
+ *lp++ = c;
+ putchar('*');
+ }
+ }
+ /*NOTREACHED*/
+}
diff --git a/sys/boot/i386/boot0/Makefile b/sys/boot/i386/boot0/Makefile
index 733fc68..f5faef3 100644
--- a/sys/boot/i386/boot0/Makefile
+++ b/sys/boot/i386/boot0/Makefile
@@ -80,4 +80,3 @@ LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.boot0.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile
index 195206f..16ed404 100644
--- a/sys/boot/i386/boot2/Makefile
+++ b/sys/boot/i386/boot2/Makefile
@@ -115,4 +115,3 @@ machine: ${.CURDIR}/../../../i386/include .NOMETA
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.boot1.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/btx/btx/Makefile b/sys/boot/i386/btx/btx/Makefile
index 0f5a468..a07e000 100644
--- a/sys/boot/i386/btx/btx/Makefile
+++ b/sys/boot/i386/btx/btx/Makefile
@@ -31,4 +31,3 @@ LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.btx.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/btx/btxldr/Makefile b/sys/boot/i386/btx/btxldr/Makefile
index 7e57ca3..bf7833d 100644
--- a/sys/boot/i386/btx/btxldr/Makefile
+++ b/sys/boot/i386/btx/btxldr/Makefile
@@ -18,4 +18,3 @@ LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.btxldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/cdboot/Makefile b/sys/boot/i386/cdboot/Makefile
index a3dc251..e9e046b 100644
--- a/sys/boot/i386/cdboot/Makefile
+++ b/sys/boot/i386/cdboot/Makefile
@@ -16,4 +16,3 @@ LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.cdboot.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/common/bootargs.h b/sys/boot/i386/common/bootargs.h
index 4768d68..e6674e1 100644
--- a/sys/boot/i386/common/bootargs.h
+++ b/sys/boot/i386/common/bootargs.h
@@ -64,6 +64,12 @@ struct bootargs
*/
};
+struct geli_boot_args
+{
+ uint32_t size;
+ char gelipw[256];
+};
+
#endif /*__ASSEMBLER__*/
#endif /* !_BOOT_I386_ARGS_H_ */
diff --git a/sys/boot/i386/common/cons.c b/sys/boot/i386/common/cons.c
index 97019c6..b967d9b 100644
--- a/sys/boot/i386/common/cons.c
+++ b/sys/boot/i386/common/cons.c
@@ -97,6 +97,13 @@ xgetc(int fn)
}
int
+getchar(void)
+{
+
+ return (xgetc(0));
+}
+
+int
keyhit(unsigned int secs)
{
uint32_t t0, t1;
diff --git a/sys/boot/i386/common/drv.c b/sys/boot/i386/common/drv.c
index 52933d5..f5133de 100644
--- a/sys/boot/i386/common/drv.c
+++ b/sys/boot/i386/common/drv.c
@@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$");
#include "xreadorg.h"
#endif
-#ifdef GPT
static struct edd_params params;
uint64_t
@@ -50,7 +49,6 @@ drvsize(struct dsk *dskp)
}
return (params.sectors);
}
-#endif /* GPT */
#ifndef USE_XREAD
static struct edd_packet packet;
diff --git a/sys/boot/i386/common/drv.h b/sys/boot/i386/common/drv.h
index 1ecfbc3..8ad3c9c 100644
--- a/sys/boot/i386/common/drv.h
+++ b/sys/boot/i386/common/drv.h
@@ -42,7 +42,7 @@ struct dsk {
int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
#ifdef GPT
int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk);
-uint64_t drvsize(struct dsk *dskp);
#endif /* GPT */
+uint64_t drvsize(struct dsk *dskp);
#endif /* !_DRV_H_ */
diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile
index 1aafe0b..cc8251c 100644
--- a/sys/boot/i386/gptboot/Makefile
+++ b/sys/boot/i386/gptboot/Makefile
@@ -39,6 +39,14 @@ CFLAGS= -DBOOTPROG=\"gptboot\" \
CFLAGS.gcc+= --param max-inline-insns-single=100
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DLOADER_GELI_SUPPORT
+CFLAGS+= -I${.CURDIR}/../../geli
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+OPENCRYPTO_XTS= xform_aes_xts.o
+.endif
+
LD_FLAGS=-static -N --gc-sections
LIBSTAND= ${.OBJDIR}/../../libstand32/libstand.a
@@ -60,14 +68,14 @@ gptldr.bin: gptldr.out
gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
-CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o gpt.o crc32.o drv.o \
- cons.o util.o
+CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o crc32.o drv.o \
+ cons.o util.o ${OPENCRYPTO_XTS}
gptboot.bin: gptboot.out
${OBJCOPY} -S -O binary gptboot.out ${.TARGET}
-gptboot.out: ${BTXCRT} gptboot.o sio.o gpt.o crc32.o drv.o cons.o util.o
- ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o util.o ${OPENCRYPTO_XTS}
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
gptboot.o: ${.CURDIR}/../../common/ufsread.c
@@ -82,4 +90,3 @@ machine: .NOMETA
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.gptldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/gptboot/Makefile.depend b/sys/boot/i386/gptboot/Makefile.depend
index c798603..295be1a 100644
--- a/sys/boot/i386/gptboot/Makefile.depend
+++ b/sys/boot/i386/gptboot/Makefile.depend
@@ -3,6 +3,10 @@
DIRDEPS = \
include \
+ include/xlocale \
+ lib/libmd \
+ lib/libstand \
+ sys/boot/geli \
sys/boot/i386/btx/btx \
sys/boot/i386/btx/lib \
sys/boot/libstand32 \
diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c
index a1f46eb..14438e6 100644
--- a/sys/boot/i386/gptboot/gptboot.c
+++ b/sys/boot/i386/gptboot/gptboot.c
@@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bootinfo.h>
#include <machine/elf.h>
+#include <machine/pc/bios.h>
#include <machine/psl.h>
#include <stdarg.h>
@@ -31,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <btxv86.h>
+#include "bootargs.h"
#include "lib.h"
#include "rbx.h"
#include "drv.h"
@@ -82,14 +84,60 @@ static struct dsk dsk;
static char kname[1024];
static int comspeed = SIOSPD;
static struct bootinfo bootinfo;
+static struct geli_boot_args geliargs;
+
+static vm_offset_t high_heap_base;
+static uint32_t bios_basemem, bios_extmem, high_heap_size;
+
+static struct bios_smap smap;
+
+/*
+ * The minimum amount of memory to reserve in bios_extmem for the heap.
+ */
+#define HEAP_MIN (3 * 1024 * 1024)
+
+static char *heap_next;
+static char *heap_end;
void exit(int);
static void load(void);
static int parse(char *, int *);
static int dskread(void *, daddr_t, unsigned);
-static uint32_t memsize(void);
+void *malloc(size_t n);
+void free(void *ptr);
+#ifdef LOADER_GELI_SUPPORT
+static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf,
+ size_t bytes);
+#endif
+
+void *
+malloc(size_t n)
+{
+ char *p = heap_next;
+ if (p + n > heap_end) {
+ printf("malloc failure\n");
+ for (;;)
+ ;
+ /* NOTREACHED */
+ return (0);
+ }
+ heap_next += n;
+ return (p);
+}
+
+void
+free(void *ptr)
+{
+
+ return;
+}
#include "ufsread.c"
+#include "gpt.c"
+#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.c"
+static char gelipw[GELI_PW_MAXLEN];
+#endif
static inline int
xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
@@ -102,14 +150,90 @@ xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
return (0);
}
-static inline uint32_t
-memsize(void)
+static void
+bios_getmem(void)
{
+ uint64_t size;
- v86.addr = MEM_EXT;
+ /* Parse system memory map */
+ v86.ebx = 0;
+ do {
+ v86.ctl = V86_FLAGS;
+ v86.addr = MEM_EXT; /* int 0x15 function 0xe820*/
+ v86.eax = 0xe820;
+ v86.ecx = sizeof(struct bios_smap);
+ v86.edx = SMAP_SIG;
+ v86.es = VTOPSEG(&smap);
+ v86.edi = VTOPOFF(&smap);
+ v86int();
+ if ((v86.efl & 1) || (v86.eax != SMAP_SIG))
+ break;
+ /* look for a low-memory segment that's large enough */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
+ (smap.length >= (512 * 1024)))
+ bios_basemem = smap.length;
+ /* look for the first segment in 'extended' memory */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0x100000)) {
+ bios_extmem = smap.length;
+ }
+
+ /*
+ * Look for the largest segment in 'extended' memory beyond
+ * 1MB but below 4GB.
+ */
+ if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base > 0x100000) &&
+ (smap.base < 0x100000000ull)) {
+ size = smap.length;
+
+ /*
+ * If this segment crosses the 4GB boundary, truncate it.
+ */
+ if (smap.base + size > 0x100000000ull)
+ size = 0x100000000ull - smap.base;
+
+ if (size > high_heap_size) {
+ high_heap_size = size;
+ high_heap_base = smap.base;
+ }
+ }
+ } while (v86.ebx != 0);
+
+ /* Fall back to the old compatibility function for base memory */
+ if (bios_basemem == 0) {
+ v86.ctl = 0;
+ v86.addr = 0x12; /* int 0x12 */
+ v86int();
+
+ bios_basemem = (v86.eax & 0xffff) * 1024;
+ }
+
+ /* Fall back through several compatibility functions for extended memory */
+ if (bios_extmem == 0) {
+ v86.ctl = V86_FLAGS;
+ v86.addr = 0x15; /* int 0x15 function 0xe801*/
+ v86.eax = 0xe801;
+ v86int();
+ if (!(v86.efl & 1)) {
+ bios_extmem = ((v86.ecx & 0xffff) + ((v86.edx & 0xffff) * 64)) * 1024;
+ }
+ }
+ if (bios_extmem == 0) {
+ v86.ctl = 0;
+ v86.addr = 0x15; /* int 0x15 function 0x88*/
v86.eax = 0x8800;
v86int();
- return (v86.eax);
+ bios_extmem = (v86.eax & 0xffff) * 1024;
+ }
+
+ /*
+ * If we have extended memory and did not find a suitable heap
+ * region in the SMAP, use the last 3MB of 'extended' memory as a
+ * high heap candidate.
+ */
+ if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
+ high_heap_size = HEAP_MIN;
+ high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
+ }
}
static int
@@ -124,6 +248,16 @@ gptinit(void)
printf("%s: no UFS partition was found\n", BOOTPROG);
return (-1);
}
+#ifdef LOADER_GELI_SUPPORT
+ if (geli_taste(vdev_read, &dsk, (gpttable[curent].ent_lba_end -
+ gpttable[curent].ent_lba_start)) == 0) {
+ if (geli_passphrase(&gelipw, dsk.unit, 'p', curent + 1, &dsk) != 0) {
+ printf("%s: unable to decrypt GELI key\n", BOOTPROG);
+ return (-1);
+ }
+ }
+#endif
+
dsk_meta = 0;
return (0);
}
@@ -137,6 +271,17 @@ main(void)
ufs_ino_t ino;
dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+
+ bios_getmem();
+
+ if (high_heap_size > 0) {
+ heap_end = PTOV(high_heap_base + high_heap_size);
+ heap_next = PTOV(high_heap_base);
+ } else {
+ heap_next = (char *)dmadat + sizeof(*dmadat);
+ heap_end = (char *)PTOV(bios_basemem);
+ }
+
v86.ctl = V86_FLAGS;
v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
dsk.drive = *(uint8_t *)PTOV(ARGS);
@@ -146,10 +291,14 @@ main(void)
dsk.start = 0;
bootinfo.bi_version = BOOTINFO_VERSION;
bootinfo.bi_size = sizeof(bootinfo);
- bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */
- bootinfo.bi_extmem = memsize();
+ bootinfo.bi_basemem = bios_basemem / 1024;
+ bootinfo.bi_extmem = bios_extmem / 1024;
bootinfo.bi_memsizes_valid++;
+ bootinfo.bi_bios_dev = dsk.drive;
+#ifdef LOADER_GELI_SUPPORT
+ geli_init();
+#endif
/* Process configuration file */
if (gptinit() != 0)
@@ -327,9 +476,16 @@ load(void)
bootinfo.bi_esymtab = VTOP(p);
bootinfo.bi_kernelname = VTOP(kname);
bootinfo.bi_bios_dev = dsk.drive;
+ geliargs.size = sizeof(geliargs);
+#ifdef LOADER_GELI_SUPPORT
+ bcopy(gelipw, geliargs.gelipw, sizeof(geliargs.gelipw));
+ bzero(gelipw, sizeof(gelipw));
+#else
+ geliargs.gelipw[0] = '\0';
+#endif
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff),
- 0, 0, 0, VTOP(&bootinfo));
+ KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs);
}
static int
@@ -430,6 +586,53 @@ parse(char *cmdstr, int *dskupdated)
static int
dskread(void *buf, daddr_t lba, unsigned nblk)
{
+ int err;
+
+ err = drvread(&dsk, buf, lba + dsk.start, nblk);
- return drvread(&dsk, buf, lba + dsk.start, nblk);
+#ifdef LOADER_GELI_SUPPORT
+ if (err == 0 && is_geli(&dsk) == 0) {
+ /* Decrypt */
+ if (geli_read(&dsk, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE))
+ return (err);
+ }
+#endif
+
+ return (err);
+}
+
+#ifdef LOADER_GELI_SUPPORT
+/*
+ * Read function compartible with the ZFS callback, required to keep the GELI
+ * Implementation the same for both UFS and ZFS
+ */
+static int
+vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes)
+{
+ char *p;
+ daddr_t lba;
+ unsigned int nb;
+ struct dsk *dskp = (struct dsk *) priv;
+
+ if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1)))
+ return (-1);
+
+ p = buf;
+ lba = off / DEV_BSIZE;
+ lba += dskp->start;
+
+ while (bytes > 0) {
+ nb = bytes / DEV_BSIZE;
+ if (nb > VBLKSIZE / DEV_BSIZE)
+ nb = VBLKSIZE / DEV_BSIZE;
+ if (drvread(dskp, dmadat->blkbuf, lba, nb))
+ return (-1);
+ memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE);
+ p += nb * DEV_BSIZE;
+ lba += nb;
+ bytes -= nb * DEV_BSIZE;
+ }
+
+ return (0);
}
+#endif /* LOADER_GELI_SUPPORT */
diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile
index 1406333..97ddd39 100644
--- a/sys/boot/i386/gptzfsboot/Makefile
+++ b/sys/boot/i386/gptzfsboot/Makefile
@@ -35,6 +35,14 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \
-Winline
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DLOADER_GELI_SUPPORT
+CFLAGS+= -I${.CURDIR}/../../geli
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+OPENCRYPTO_XTS= xform_aes_xts.o
+.endif
+
CFLAGS.gcc+= --param max-inline-insns-single=100
LD_FLAGS=-static -N --gc-sections
@@ -59,13 +67,13 @@ gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o
CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o cons.o \
- drv.o gpt.o util.o
+ drv.o gpt.o util.o ${OPENCRYPTO_XTS}
gptzfsboot.bin: gptzfsboot.out
${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET}
-gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o
- ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND}
+gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o ${OPENCRYPTO_XTS}
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} ${LIBGELIBOOT}
zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c
@@ -80,4 +88,3 @@ machine: .NOMETA
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.gptldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/gptzfsboot/Makefile.depend b/sys/boot/i386/gptzfsboot/Makefile.depend
index 63a43d8..295be1a 100644
--- a/sys/boot/i386/gptzfsboot/Makefile.depend
+++ b/sys/boot/i386/gptzfsboot/Makefile.depend
@@ -4,6 +4,9 @@
DIRDEPS = \
include \
include/xlocale \
+ lib/libmd \
+ lib/libstand \
+ sys/boot/geli \
sys/boot/i386/btx/btx \
sys/boot/i386/btx/lib \
sys/boot/libstand32 \
diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile
index f3c1d8d..f1c55f1 100644
--- a/sys/boot/i386/libi386/Makefile
+++ b/sys/boot/i386/libi386/Makefile
@@ -30,6 +30,12 @@ CFLAGS+= -DCOMSPEED=${BOOT_COMCONSOLE_SPEED}
CFLAGS+= -DDISK_DEBUG
.endif
+.if !defined(LOADER_NO_GELI_SUPPORT)
+# Decrypt encrypted drives
+CFLAGS+= -DLOADER_GELI_SUPPORT
+CFLAGS+= -I${.CURDIR}/../../geli
+.endif
+
.if !defined(BOOT_HIDE_SERIAL_NUMBERS)
# Export serial numbers, UUID, and asset tag from loader.
CFLAGS+= -DSMBIOS_SERIAL_NUMBERS
@@ -69,7 +75,6 @@ machine: .NOMETA
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.amd64_tramp.S= ${CLANG_NO_IAS}
CFLAGS.multiboot_tramp.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
.if ${MACHINE_CPUARCH} == "amd64"
beforedepend ${OBJS}: machine
diff --git a/sys/boot/i386/libi386/Makefile.depend b/sys/boot/i386/libi386/Makefile.depend
index 18be76b..df20c96 100644
--- a/sys/boot/i386/libi386/Makefile.depend
+++ b/sys/boot/i386/libi386/Makefile.depend
@@ -4,6 +4,7 @@
DIRDEPS = \
include \
include/xlocale \
+ lib/libmd \
.include <dirdeps.mk>
diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c
index 2a71d64..1c54769 100644
--- a/sys/boot/i386/libi386/biosdisk.c
+++ b/sys/boot/i386/libi386/biosdisk.c
@@ -49,6 +49,34 @@ __FBSDID("$FreeBSD$");
#include "disk.h"
#include "libi386.h"
+#ifdef LOADER_GELI_SUPPORT
+#include "cons.h"
+#include "drv.h"
+#include "gpt.h"
+#include "part.h"
+#include <uuid.h>
+struct pentry {
+ struct ptable_entry part;
+ uint64_t flags;
+ union {
+ uint8_t bsd;
+ uint8_t mbr;
+ uuid_t gpt;
+ uint16_t vtoc8;
+ } type;
+ STAILQ_ENTRY(pentry) entry;
+};
+struct ptable {
+ enum ptable_type type;
+ uint16_t sectorsize;
+ uint64_t sectors;
+
+ STAILQ_HEAD(, pentry) entries;
+};
+
+#include "geliboot.c"
+#endif /* LOADER_GELI_SUPPORT */
+
CTASSERT(sizeof(struct i386_devdesc) >= sizeof(struct disk_devdesc));
#define BIOS_NUMDRIVES 0x475
@@ -108,6 +136,18 @@ static int bd_ioctl(struct open_file *f, u_long cmd, void *data);
static void bd_print(int verbose);
static void bd_cleanup(void);
+#ifdef LOADER_GELI_SUPPORT
+static enum isgeli {
+ ISGELI_UNKNOWN,
+ ISGELI_NO,
+ ISGELI_YES
+};
+static enum isgeli geli_status[MAXBDDEV][MAXTBLENTS];
+
+int bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf,
+ size_t bytes);
+#endif /* LOADER_GELI_SUPPORT */
+
struct devsw biosdisk = {
"disk",
DEVT_DISK,
@@ -154,6 +194,9 @@ bd_init(void)
{
int base, unit, nfd = 0;
+#ifdef LOADER_GELI_SUPPORT
+ geli_init();
+#endif
/* sequence 0, 0x80 */
for (base = 0; base <= 0x80; base += 0x80) {
for (unit = base; (nbdinfo < MAXBDDEV); unit++) {
@@ -299,7 +342,8 @@ bd_print(int verbose)
static int
bd_open(struct open_file *f, ...)
{
- struct disk_devdesc *dev;
+ struct disk_devdesc *dev, rdev;
+ int err, g_err;
va_list ap;
va_start(ap, f);
@@ -309,9 +353,83 @@ bd_open(struct open_file *f, ...)
if (dev->d_unit < 0 || dev->d_unit >= nbdinfo)
return (EIO);
- return (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
+ err = disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize,
BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ?
- DISK_F_NOCACHE: 0));
+ DISK_F_NOCACHE: 0);
+
+#ifdef LOADER_GELI_SUPPORT
+ static char gelipw[GELI_PW_MAXLEN];
+ char *passphrase;
+
+ if (err)
+ return (err);
+
+ /* if we already know there is no GELI, skip the rest */
+ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_UNKNOWN)
+ return (err);
+
+ struct dsk dskp;
+ struct ptable *table = NULL;
+ struct ptable_entry part;
+ struct pentry *entry;
+ int geli_part = 0;
+
+ dskp.drive = bd_unit2bios(dev->d_unit);
+ dskp.type = dev->d_type;
+ dskp.unit = dev->d_unit;
+ dskp.slice = dev->d_slice;
+ dskp.part = dev->d_partition;
+ dskp.start = dev->d_offset;
+
+ memcpy(&rdev, dev, sizeof(rdev));
+ /* to read the GPT table, we need to read the first sector */
+ rdev.d_offset = 0;
+ /* We need the LBA of the end of the partition */
+ table = ptable_open(&rdev, BD(dev).bd_sectors,
+ BD(dev).bd_sectorsize, ptblread);
+ if (table == NULL) {
+ DEBUG("Can't read partition table");
+ /* soft failure, return the exit status of disk_open */
+ return (err);
+ }
+
+ if (table->type == PTABLE_GPT)
+ dskp.part = 255;
+
+ STAILQ_FOREACH(entry, &table->entries, entry) {
+ dskp.slice = entry->part.index;
+ dskp.start = entry->part.start;
+ if (is_geli(&dskp) == 0) {
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
+ return (0);
+ }
+ if (geli_taste(bios_read, &dskp,
+ entry->part.end - entry->part.start) == 0) {
+ if ((passphrase = getenv("kern.geom.eli.passphrase"))
+ != NULL) {
+ /* Use the cached passphrase */
+ bcopy(passphrase, &gelipw, GELI_PW_MAXLEN);
+ }
+ if (geli_passphrase(&gelipw, dskp.unit, 'p',
+ (dskp.slice > 0 ? dskp.slice : dskp.part),
+ &dskp) == 0) {
+ setenv("kern.geom.eli.passphrase", &gelipw, 1);
+ bzero(gelipw, sizeof(gelipw));
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_YES;
+ geli_part++;
+ }
+ } else
+ geli_status[dev->d_unit][dskp.slice] = ISGELI_NO;
+ }
+
+ /* none of the partitions on this disk have GELI */
+ if (geli_part == 0) {
+ /* found no GELI */
+ geli_status[dev->d_unit][dev->d_slice] = ISGELI_NO;
+ }
+#endif /* LOADER_GELI_SUPPORT */
+
+ return (err);
}
static int
@@ -586,6 +704,38 @@ bd_io(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest, int write)
static int
bd_read(struct disk_devdesc *dev, daddr_t dblk, int blks, caddr_t dest)
{
+#ifdef LOADER_GELI_SUPPORT
+ struct dsk dskp;
+ off_t p_off;
+ int err, n;
+
+ /* if we already know there is no GELI, skip the rest */
+ if (geli_status[dev->d_unit][dev->d_slice] != ISGELI_YES)
+ return (bd_io(dev, dblk, blks, dest, 0));
+
+ if (geli_status[dev->d_unit][dev->d_slice] == ISGELI_YES) {
+ err = bd_io(dev, dblk, blks, dest, 0);
+ if (err)
+ return (err);
+
+ dskp.drive = bd_unit2bios(dev->d_unit);
+ dskp.type = dev->d_type;
+ dskp.unit = dev->d_unit;
+ dskp.slice = dev->d_slice;
+ dskp.part = dev->d_partition;
+ dskp.start = dev->d_offset;
+
+ /* GELI needs the offset relative to the partition start */
+ p_off = dblk - dskp.start;
+
+ err = geli_read(&dskp, p_off * BIOSDISK_SECSIZE, dest,
+ blks * BIOSDISK_SECSIZE);
+ if (err)
+ return (err);
+
+ return (0);
+ }
+#endif /* LOADER_GELI_SUPPORT */
return (bd_io(dev, dblk, blks, dest, 0));
}
@@ -682,3 +832,25 @@ bd_getdev(struct i386_devdesc *d)
DEBUG("dev is 0x%x\n", rootdev);
return(rootdev);
}
+
+#ifdef LOADER_GELI_SUPPORT
+int
+bios_read(void *vdev __unused, struct dsk *priv, off_t off, char *buf, size_t bytes)
+{
+ struct disk_devdesc dev;
+
+ dev.d_dev = &biosdisk;
+ dev.d_type = priv->type;
+ dev.d_unit = priv->unit;
+ dev.d_slice = priv->slice;
+ dev.d_partition = priv->part;
+ dev.d_offset = priv->start;
+
+ off = off / BIOSDISK_SECSIZE;
+ /* GELI gives us the offset relative to the partition start */
+ off += dev.d_offset;
+ bytes = bytes / BIOSDISK_SECSIZE;
+
+ return (bd_io(&dev, off, bytes, buf, 0));
+}
+#endif /* LOADER_GELI_SUPPORT */
diff --git a/sys/boot/i386/libi386/pxe.c b/sys/boot/i386/libi386/pxe.c
index efa04fc..d67665e 100644
--- a/sys/boot/i386/libi386/pxe.c
+++ b/sys/boot/i386/libi386/pxe.c
@@ -310,6 +310,11 @@ pxe_open(struct open_file *f, ...)
sprintf(temp, "%6D", bootplayer.CAddr, ":");
setenv("boot.netif.hwaddr", temp, 1);
}
+ if (intf_mtu != 0) {
+ char mtu[16];
+ sprintf(mtu, "%u", intf_mtu);
+ setenv("boot.netif.mtu", mtu, 1);
+ }
#ifdef LOADER_NFS_SUPPORT
printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
printf("pxe_open: server path: %s\n", rootpath);
diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile
index 776ba92..233876a 100644
--- a/sys/boot/i386/loader/Makefile
+++ b/sys/boot/i386/loader/Makefile
@@ -58,6 +58,13 @@ CFLAGS+= -DLOADER_GZIP_SUPPORT
.if defined(LOADER_NANDFS_SUPPORT)
CFLAGS+= -DLOADER_NANDFS_SUPPORT
.endif
+.if !defined(LOADER_NO_GELI_SUPPORT)
+CFLAGS+= -DLOADER_GELI_SUPPORT
+LIBGELIBOOT= ${.OBJDIR}/../../geli/libgeliboot.a
+.PATH: ${.CURDIR}/../../../opencrypto
+SRCS+= xform_aes_xts.c
+CFLAGS+= -I${.CURDIR}/../../.. -D_STAND
+.endif
# Always add MI sources
.PATH: ${.CURDIR}/../../common
@@ -116,8 +123,8 @@ FILES+= loader.rc menu.rc
# XXX crt0.o needs to be first for pxeboot(8) to work
OBJS= ${BTXCRT}
-DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
-LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND}
+DPADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} ${LIBGELIBOOT}
+LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSTAND} ${LIBGELIBOOT}
.include <bsd.prog.mk>
diff --git a/sys/boot/i386/loader/Makefile.depend b/sys/boot/i386/loader/Makefile.depend
index 9650fc0..89d5422 100644
--- a/sys/boot/i386/loader/Makefile.depend
+++ b/sys/boot/i386/loader/Makefile.depend
@@ -6,6 +6,7 @@ DIRDEPS = \
include/xlocale \
lib/libstand \
sys/boot/ficl32 \
+ sys/boot/geli \
sys/boot/i386/btx/btx \
sys/boot/i386/btx/btxldr \
sys/boot/i386/btx/lib \
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index c0782fc..b3e7b41 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -68,7 +68,11 @@ static void extract_currdev(void);
static int isa_inb(int port);
static void isa_outb(int port, int value);
void exit(int code);
+#ifdef LOADER_GELI_SUPPORT
+struct geli_boot_args *gargs;
+#endif
#ifdef LOADER_ZFS_SUPPORT
+struct zfs_boot_args *zargs;
static void i386_zfs_probe(void);
#endif
@@ -164,7 +168,31 @@ main(void)
archsw.arch_isaoutb = isa_outb;
#ifdef LOADER_ZFS_SUPPORT
archsw.arch_zfs_probe = i386_zfs_probe;
-#endif
+
+#ifdef LOADER_GELI_SUPPORT
+ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
+ zargs = (struct zfs_boot_args *)(kargs + 1);
+ if (zargs != NULL && zargs->size >= offsetof(struct zfs_boot_args, gelipw)) {
+ if (zargs->gelipw[0] != '\0') {
+ setenv("kern.geom.eli.passphrase", zargs->gelipw, 1);
+ bzero(zargs->gelipw, sizeof(zargs->gelipw));
+ }
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
+#else /* !LOADER_ZFS_SUPPORT */
+#ifdef LOADER_GELI_SUPPORT
+ if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) {
+ gargs = (struct geli_boot_args *)(kargs + 1);
+ if (gargs != NULL && gargs->size >= offsetof(struct geli_boot_args, gelipw)) {
+ if (gargs->gelipw[0] != '\0') {
+ setenv("kern.geom.eli.passphrase", gargs->gelipw, 1);
+ bzero(gargs->gelipw, sizeof(gargs->gelipw));
+ }
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
+#endif /* LOADER_ZFS_SUPPORT */
/*
* March through the device switch probing for things.
@@ -214,7 +242,6 @@ extract_currdev(void)
struct i386_devdesc new_currdev;
#ifdef LOADER_ZFS_SUPPORT
char buf[20];
- struct zfs_boot_args *zargs;
#endif
int biosdev = -1;
diff --git a/sys/boot/i386/pxeldr/Makefile b/sys/boot/i386/pxeldr/Makefile
index c4e008f..8de2139 100644
--- a/sys/boot/i386/pxeldr/Makefile
+++ b/sys/boot/i386/pxeldr/Makefile
@@ -46,4 +46,3 @@ ${LOADER}: ${LOADERBIN} ${BTXLDR} ${BTXKERN}
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.pxeldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile
index f65e0ad..7f434a8 100644
--- a/sys/boot/i386/zfsboot/Makefile
+++ b/sys/boot/i386/zfsboot/Makefile
@@ -93,4 +93,3 @@ machine: .NOMETA
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.zfsldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c
index 6fbbc6f..4b371dc 100644
--- a/sys/boot/i386/zfsboot/zfsboot.c
+++ b/sys/boot/i386/zfsboot/zfsboot.c
@@ -121,8 +121,10 @@ void exit(int);
static void load(void);
static int parse(void);
static void bios_getmem(void);
+void *malloc(size_t n);
+void free(void *ptr);
-static void *
+void *
malloc(size_t n)
{
char *p = heap_next;
@@ -130,10 +132,18 @@ malloc(size_t n)
printf("malloc failure\n");
for (;;)
;
- return 0;
+ /* NOTREACHED */
+ return (0);
}
heap_next += n;
- return p;
+ return (p);
+}
+
+void
+free(void *ptr)
+{
+
+ return;
}
static char *
@@ -141,9 +151,14 @@ strdup(const char *s)
{
char *p = malloc(strlen(s) + 1);
strcpy(p, s);
- return p;
+ return (p);
}
+#ifdef LOADER_GELI_SUPPORT
+#include "geliboot.c"
+static char gelipw[GELI_PW_MAXLEN];
+#endif
+
#include "zfsimpl.c"
/*
@@ -199,6 +214,14 @@ vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
nb = READ_BUF_SIZE / DEV_BSIZE;
if (drvread(dsk, dmadat->rdbuf, lba, nb))
return -1;
+#ifdef LOADER_GELI_SUPPORT
+ /* decrypt */
+ if (is_geli(dsk) == 0) {
+ if (geli_read(dsk, ((lba - dsk->start) * DEV_BSIZE),
+ dmadat->rdbuf, nb * DEV_BSIZE))
+ return (-1);
+ }
+#endif
memcpy(p, dmadat->rdbuf, nb * DEV_BSIZE);
p += nb * DEV_BSIZE;
lba += nb;
@@ -302,7 +325,7 @@ bios_getmem(void)
high_heap_size = HEAP_MIN;
high_heap_base = bios_extmem + 0x100000 - HEAP_MIN;
}
-}
+}
/*
* Try to detect a device supported by the legacy int13 BIOS
@@ -346,21 +369,39 @@ probe_drive(struct dsk *dsk)
#ifdef GPT
struct gpt_hdr hdr;
struct gpt_ent *ent;
- daddr_t slba, elba;
unsigned part, entries_per_sec;
#endif
+ daddr_t slba, elba;
struct dos_partition *dp;
char *sec;
unsigned i;
/*
- * If we find a vdev on the whole disk, stop here. Otherwise dig
- * out the partition table and probe each slice/partition
- * in turn for a vdev.
+ * If we find a vdev on the whole disk, stop here.
*/
if (vdev_probe(vdev_read, dsk, NULL) == 0)
return;
+#ifdef LOADER_GELI_SUPPORT
+ /*
+ * Taste the disk, if it is GELI encrypted, decrypt it and check to see if
+ * it is a usable vdev then. Otherwise dig
+ * out the partition table and probe each slice/partition
+ * in turn for a vdev or GELI encrypted vdev.
+ */
+ elba = drvsize(dsk);
+ if (elba > 0) {
+ elba--;
+ }
+ if (geli_taste(vdev_read, dsk, elba) == 0) {
+ if (geli_passphrase(&gelipw, dsk->unit, ':', 0, dsk) == 0) {
+ if (vdev_probe(vdev_read, dsk, NULL) == 0) {
+ return;
+ }
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
+
sec = dmadat->secbuf;
dsk->start = 0;
@@ -383,6 +424,8 @@ probe_drive(struct dsk *dsk)
* return the spa_t for the first we find (if requested). This
* will have the effect of booting from the first pool on the
* disk.
+ *
+ * If no vdev is found, GELI decrypting the device and try again
*/
entries_per_sec = DEV_BSIZE / hdr.hdr_entsz;
slba = hdr.hdr_lba_table;
@@ -396,6 +439,8 @@ probe_drive(struct dsk *dsk)
if (memcmp(&ent->ent_type, &freebsd_zfs_uuid,
sizeof(uuid_t)) == 0) {
dsk->start = ent->ent_lba_start;
+ dsk->slice = part + 1;
+ dsk->part = 255;
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
/*
* This slice had a vdev. We need a new dsk
@@ -403,13 +448,31 @@ probe_drive(struct dsk *dsk)
*/
dsk = copy_dsk(dsk);
}
+#ifdef LOADER_GELI_SUPPORT
+ else if (geli_taste(vdev_read, dsk, ent->ent_lba_end -
+ ent->ent_lba_start) == 0) {
+ if (geli_passphrase(&gelipw, dsk->unit, 'p', dsk->slice, dsk) == 0) {
+ /*
+ * This slice has GELI, check it for ZFS.
+ */
+ if (vdev_probe(vdev_read, dsk, NULL) == 0) {
+ /*
+ * This slice had a vdev. We need a new dsk
+ * structure now since the vdev now owns this one.
+ */
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
}
}
slba++;
}
return;
trymbr:
-#endif
+#endif /* GPT */
if (drvread(dsk, sec, DOSBBSECTOR, 1))
return;
@@ -419,13 +482,28 @@ trymbr:
if (!dp[i].dp_typ)
continue;
dsk->start = dp[i].dp_start;
+ dsk->slice = i + 1;
if (vdev_probe(vdev_read, dsk, NULL) == 0) {
- /*
- * This slice had a vdev. We need a new dsk structure now
- * since the vdev now owns this one.
- */
dsk = copy_dsk(dsk);
}
+#ifdef LOADER_GELI_SUPPORT
+ else if (geli_taste(vdev_read, dsk, dp[i].dp_size -
+ dp[i].dp_start) == 0) {
+ if (geli_passphrase(&gelipw, dsk->unit, 's', i, dsk) == 0) {
+ /*
+ * This slice has GELI, check it for ZFS.
+ */
+ if (vdev_probe(vdev_read, dsk, NULL) == 0) {
+ /*
+ * This slice had a vdev. We need a new dsk
+ * structure now since the vdev now owns this one.
+ */
+ dsk = copy_dsk(dsk);
+ }
+ break;
+ }
+ }
+#endif /* LOADER_GELI_SUPPORT */
}
}
@@ -445,8 +523,8 @@ main(void)
heap_end = PTOV(high_heap_base + high_heap_size);
heap_next = PTOV(high_heap_base);
} else {
- heap_next = (char *) dmadat + sizeof(*dmadat);
- heap_end = (char *) PTOV(bios_basemem);
+ heap_next = (char *)dmadat + sizeof(*dmadat);
+ heap_end = (char *)PTOV(bios_basemem);
}
dsk = malloc(sizeof(struct dsk));
@@ -472,6 +550,9 @@ main(void)
autoboot = 1;
+#ifdef LOADER_GELI_SUPPORT
+ geli_init();
+#endif
zfs_init();
/*
@@ -690,6 +771,12 @@ load(void)
zfsargs.pool = zfsmount.spa->spa_guid;
zfsargs.root = zfsmount.rootobj;
zfsargs.primary_pool = primary_spa->spa_guid;
+#ifdef LOADER_GELI_SUPPORT
+ bcopy(gelipw, zfsargs.gelipw, sizeof(zfsargs.gelipw));
+ bzero(gelipw, sizeof(gelipw));
+#else
+ zfsargs.gelipw[0] = '\0';
+#endif
if (primary_vdev != NULL)
zfsargs.primary_vdev = primary_vdev->v_guid;
else
diff --git a/sys/boot/i386/zfsloader/Makefile.depend b/sys/boot/i386/zfsloader/Makefile.depend
index b3810a2..15b0c98 100644
--- a/sys/boot/i386/zfsloader/Makefile.depend
+++ b/sys/boot/i386/zfsloader/Makefile.depend
@@ -6,6 +6,7 @@ DIRDEPS = \
include/xlocale \
lib/libstand \
sys/boot/ficl32 \
+ sys/boot/geli \
sys/boot/i386/btx/btx \
sys/boot/i386/btx/btxldr \
sys/boot/i386/btx/lib \
diff --git a/sys/boot/pc98/boot2/Makefile b/sys/boot/pc98/boot2/Makefile
index 6af4f90..8d5e791 100644
--- a/sys/boot/pc98/boot2/Makefile
+++ b/sys/boot/pc98/boot2/Makefile
@@ -114,4 +114,3 @@ boot2.h: boot1.out
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.boot1.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/pc98/btx/btx/Makefile b/sys/boot/pc98/btx/btx/Makefile
index 905908f..9046d35 100644
--- a/sys/boot/pc98/btx/btx/Makefile
+++ b/sys/boot/pc98/btx/btx/Makefile
@@ -31,4 +31,3 @@ LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.btx.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/pc98/btx/btxldr/Makefile b/sys/boot/pc98/btx/btxldr/Makefile
index 7d34e9e..b0c8996 100644
--- a/sys/boot/pc98/btx/btxldr/Makefile
+++ b/sys/boot/pc98/btx/btxldr/Makefile
@@ -18,4 +18,3 @@ LDFLAGS=-e start -Ttext ${LOADER_ADDRESS} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.btxldr.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/pc98/cdboot/Makefile b/sys/boot/pc98/cdboot/Makefile
index 23543d4..3b91c12 100644
--- a/sys/boot/pc98/cdboot/Makefile
+++ b/sys/boot/pc98/cdboot/Makefile
@@ -16,4 +16,3 @@ LDFLAGS=-e start -Ttext ${ORG} -Wl,-N,-S,--oformat,binary
# XXX: clang integrated-as doesn't grok .codeNN directives yet
CFLAGS.cdboot.S= ${CLANG_NO_IAS}
-CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h
index ee64d1c..58bfd26 100644
--- a/sys/boot/zfs/libzfs.h
+++ b/sys/boot/zfs/libzfs.h
@@ -55,6 +55,7 @@ struct zfs_boot_args
uint64_t root;
uint64_t primary_pool;
uint64_t primary_vdev;
+ char gelipw[256];
};
int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 6ea25c2..38cf46e 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -466,14 +466,6 @@ static struct ada_quirk_entry ada_quirk_table[] =
},
{
/*
- * Samsung 843T Series SSDs
- * 4k optimised
- */
- { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7WD*", "*" },
- /*quirks*/ADA_Q_4K
- },
- {
- /*
* Samsung 850 SSDs
* 4k optimised
*/
@@ -482,10 +474,13 @@ static struct ada_quirk_entry ada_quirk_table[] =
},
{
/*
- * Samsung PM853T Series SSDs
+ * Samsung 843T Series SSDs (MZ7WD*)
+ * Samsung PM851 Series SSDs (MZ7TE*)
+ * Samsung PM853T Series SSDs (MZ7GE*)
+ * Samsung SM863 Series SSDs (MZ7KM*)
* 4k optimised
*/
- { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7GE*", "*" },
+ { T_DIRECT, SIP_MEDIA_FIXED, "*", "SAMSUNG MZ7*", "*" },
/*quirks*/ADA_Q_4K
},
{
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 4e1e6a2..28415ed 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -725,6 +725,13 @@ struct ccb_scsiio {
u_int init_id; /* initiator id of who selected */
};
+static __inline uint8_t *
+scsiio_cdb_ptr(struct ccb_scsiio *ccb)
+{
+ return ((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+ ccb->cdb_io.cdb_ptr : ccb->cdb_io.cdb_bytes);
+}
+
/*
* ATA I/O Request CCB used for the XPT_ATA_IO function code.
*/
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 137128d..8e069db 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -651,6 +651,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
} else {
int error;
+ announce_buf[0] = '\0';
error = cherror(done_ccb, CAM_RETRY_SELTO,
SF_RETRY_UA | SF_NO_PRINT);
/*
@@ -659,7 +660,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb)
*/
if (error == ERESTART) {
/*
- * A retry was scheuled, so
+ * A retry was scheduled, so
* just return.
*/
return;
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index 9d39182..07a6435 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -1138,14 +1138,6 @@ static struct da_quirk_entry da_quirk_table[] =
},
{
/*
- * Samsung 843T Series SSDs
- * 4k optimised
- */
- { T_DIRECT, SIP_MEDIA_FIXED, "ATA", "SAMSUNG MZ7WD*", "*" },
- /*quirks*/DA_Q_4K
- },
- {
- /*
* Samsung 850 SSDs
* 4k optimised & trim only works in 4k requests + 4k aligned
*/
@@ -1154,10 +1146,13 @@ static struct da_quirk_entry da_quirk_table[] =
},
{
/*
- * Samsung PM853T Series SSDs
+ * Samsung 843T Series SSDs (MZ7WD*)
+ * Samsung PM851 Series SSDs (MZ7TE*)
+ * Samsung PM853T Series SSDs (MZ7GE*)
+ * Samsung SM863 Series SSDs (MZ7KM*)
* 4k optimised
*/
- { T_DIRECT, SIP_MEDIA_FIXED, "ATA", "SAMSUNG MZ7GE*", "*" },
+ { T_DIRECT, SIP_MEDIA_FIXED, "ATA", "SAMSUNG MZ7*", "*" },
/*quirks*/DA_Q_4K
},
{
diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c
index a2532f8..49becbc 100644
--- a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c
+++ b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c
@@ -196,6 +196,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
VI_UNLOCK(vp);
vrele(vp);
vfs_unbusy(mp);
+ vfs_freeopts(mp->mnt_optnew);
vfs_mount_destroy(mp);
*vpp = NULL;
return (error);
diff --git a/sys/cddl/compat/opensolaris/sys/vfs.h b/sys/cddl/compat/opensolaris/sys/vfs.h
index e1e49ed..c6e21cc 100644
--- a/sys/cddl/compat/opensolaris/sys/vfs.h
+++ b/sys/cddl/compat/opensolaris/sys/vfs.h
@@ -54,17 +54,6 @@ typedef struct mount vfs_t;
#define VFS_NOSETUID MNT_NOSUID
#define VFS_NOEXEC MNT_NOEXEC
-#define VFS_HOLD(vfsp) do { \
- MNT_ILOCK(vfsp); \
- MNT_REF(vfsp); \
- MNT_IUNLOCK(vfsp); \
-} while (0)
-#define VFS_RELE(vfsp) do { \
- MNT_ILOCK(vfsp); \
- MNT_REL(vfsp); \
- MNT_IUNLOCK(vfsp); \
-} while (0)
-
#define fs_vscan(vp, cr, async) (0)
#define VROOT VV_ROOT
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
index d3bce0e..7ec7dfd 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -246,10 +246,6 @@ static int dtrace_dynvar_failclean; /* dynvars failed to clean */
#ifndef illumos
static struct mtx dtrace_unr_mtx;
MTX_SYSINIT(dtrace_unr_mtx, &dtrace_unr_mtx, "Unique resource identifier", MTX_DEF);
-int dtrace_in_probe; /* non-zero if executing a probe */
-#if defined(__i386__) || defined(__amd64__) || defined(__mips__) || defined(__powerpc__)
-uintptr_t dtrace_in_probe_addr; /* Address of invop when already in probe */
-#endif
static eventhandler_tag dtrace_kld_load_tag;
static eventhandler_tag dtrace_kld_unload_try_tag;
#endif
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c
index 89882f4..c5c5c00 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c
@@ -589,7 +589,9 @@ gfs_root_create(size_t size, vfs_t *vfsp, vnodeops_t *ops, ino64_t ino,
{
vnode_t *vp;
+#ifdef illumos
VFS_HOLD(vfsp);
+#endif
vp = gfs_dir_create(size, NULL, vfsp, ops, entries, inode_cb,
maxlen, readdir_cb, lookup_cb);
/* Manually set the inode */
@@ -700,7 +702,9 @@ found:
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
} else {
ASSERT(vp->v_vfsp != NULL);
+#ifdef illumos
VFS_RELE(vp->v_vfsp);
+#endif
}
#ifdef TODO
if (vp->v_flag & V_XATTRDIR)
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
index 188810b..9e8d86e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c
@@ -107,6 +107,19 @@ dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
dsl_dataset_t *ds = dmu_objset_ds(dsp->dsa_os);
struct uio auio;
struct iovec aiov;
+
+ /*
+ * The code does not rely on this (len being a multiple of 8). We keep
+ * this assertion because of the corresponding assertion in
+ * receive_read(). Keeping this assertion ensures that we do not
+ * inadvertently break backwards compatibility (causing the assertion
+ * in receive_read() to trigger on old software).
+ *
+ * Removing the assertions could be rolled into a new feature that uses
+ * data that isn't 8-byte aligned; if the assertions were removed, a
+ * feature flag would have to be added.
+ */
+
ASSERT0(len % 8);
aiov.iov_base = buf;
@@ -1824,7 +1837,10 @@ receive_read(struct receive_arg *ra, int len, void *buf)
{
int done = 0;
- /* some things will require 8-byte alignment, so everything must */
+ /*
+ * The code doesn't rely on this (lengths being multiples of 8). See
+ * comment in dump_bytes.
+ */
ASSERT0(len % 8);
while (done < len) {
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c
index 12e2771..8586cb6 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_prop.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#include <sys/zfs_context.h>
@@ -41,16 +42,14 @@
#define ZPROP_RECVD_SUFFIX "$recvd"
static int
-dodefault(const char *propname, int intsz, int numints, void *buf)
+dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
{
- zfs_prop_t prop;
-
/*
* The setonce properties are read-only, BUT they still
* have a default value that can be used as the initial
* value.
*/
- if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
+ if (prop == ZPROP_INVAL ||
(zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
return (SET_ERROR(ENOENT));
@@ -148,7 +147,7 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
}
if (err == ENOENT)
- err = dodefault(propname, intsz, numints, buf);
+ err = dodefault(prop, intsz, numints, buf);
strfree(inheritstr);
strfree(recvdstr);
@@ -622,7 +621,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
int err;
uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
- isint = (dodefault(propname, 8, 1, &intval) == 0);
+ isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
if (ds->ds_is_snapshot) {
ASSERT(version >= SPA_VERSION_SNAP_PROPS);
@@ -1180,7 +1179,7 @@ dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
/* Indicate the default source if we can. */
- if (dodefault(propname, 8, 1, &default_value) == 0 &&
+ if (dodefault(prop, 8, 1, &default_value) == 0 &&
value == default_value) {
VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index c24836e..430ed34 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -1443,7 +1443,14 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
mutex_enter(&os->os_user_ptr_lock);
*zfvp = dmu_objset_get_user(os);
if (*zfvp) {
+#ifdef illumos
VFS_HOLD((*zfvp)->z_vfs);
+#else
+ if (vfs_busy((*zfvp)->z_vfs, 0) != 0) {
+ *zfvp = NULL;
+ error = SET_ERROR(ESRCH);
+ }
+#endif
} else {
error = SET_ERROR(ESRCH);
}
@@ -1487,7 +1494,11 @@ zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag)
rrm_exit(&zfsvfs->z_teardown_lock, tag);
if (zfsvfs->z_vfs) {
+#ifdef illumos
VFS_RELE(zfsvfs->z_vfs);
+#else
+ vfs_unbusy(zfsvfs->z_vfs);
+#endif
} else {
dmu_objset_disown(zfsvfs->z_os, zfsvfs);
zfsvfs_free(zfsvfs);
@@ -3018,11 +3029,13 @@ zfs_get_vfs(const char *resource)
mtx_lock(&mountlist_mtx);
TAILQ_FOREACH(vfsp, &mountlist, mnt_list) {
if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
- VFS_HOLD(vfsp);
+ if (vfs_busy(vfsp, MBF_MNTLSTLOCK) != 0)
+ vfsp = NULL;
break;
}
}
- mtx_unlock(&mountlist_mtx);
+ if (vfsp == NULL)
+ mtx_unlock(&mountlist_mtx);
return (vfsp);
}
@@ -3475,7 +3488,11 @@ zfs_unmount_snap(const char *snapname)
ASSERT(!dsl_pool_config_held(dmu_objset_pool(zfsvfs->z_os)));
err = vn_vfswlock(vfsp->vfs_vnodecovered);
+#ifdef illumos
VFS_RELE(vfsp);
+#else
+ vfs_unbusy(vfsp);
+#endif
if (err != 0)
return (SET_ERROR(err));
@@ -3721,7 +3738,11 @@ zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl)
resume_err = zfs_resume_fs(zfsvfs, fsname);
error = error ? error : resume_err;
}
+#ifdef illumos
VFS_RELE(zfsvfs->z_vfs);
+#else
+ vfs_unbusy(zfsvfs->z_vfs);
+#endif
} else {
error = dsl_dataset_rollback(fsname, NULL, outnvl);
}
@@ -4376,7 +4397,11 @@ zfs_ioc_recv(zfs_cmd_t *zc)
if (error == 0)
error = zfs_resume_fs(zfsvfs, tofs);
error = error ? error : end_err;
+#ifdef illumos
VFS_RELE(zfsvfs->z_vfs);
+#else
+ vfs_unbusy(zfsvfs->z_vfs);
+#endif
} else {
error = dmu_recv_end(&drc, NULL);
}
@@ -4925,7 +4950,11 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
}
if (error == 0)
error = dmu_objset_userspace_upgrade(zfsvfs->z_os);
+#ifdef illumos
VFS_RELE(zfsvfs->z_vfs);
+#else
+ vfs_unbusy(zfsvfs->z_vfs);
+#endif
} else {
/* XXX kind of reading contents without owning */
error = dmu_objset_hold(zc->zc_name, FTAG, &os);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
index 5c2b66d..96b1cec 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
@@ -5773,7 +5773,7 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int *rbehind,
off_t startoff, endoff;
int i, error;
vm_pindex_t reqstart, reqend;
- int lsize, reqsize, size;
+ int lsize, size;
object = m[0]->object;
error = 0;
@@ -5797,7 +5797,7 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int *rbehind,
}
PCPU_INC(cnt.v_vnodein);
- PCPU_ADD(cnt.v_vnodepgsin, reqsize);
+ PCPU_ADD(cnt.v_vnodepgsin, count);
lsize = PAGE_SIZE;
if (IDX_TO_OFF(mlast->pindex) + lsize > object->un_pager.vnp.vnp_size)
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
index 04f0b6c..964b453 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
@@ -743,7 +743,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
if (vp->v_type != VFIFO)
VN_LOCK_ASHARE(vp);
+#ifdef illumos
VFS_HOLD(zfsvfs->z_vfs);
+#endif
return (zp);
}
@@ -1428,7 +1430,9 @@ zfs_znode_free(znode_t *zp)
kmem_cache_free(znode_cache, zp);
+#ifdef illumos
VFS_RELE(zfsvfs->z_vfs);
+#endif
}
void
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
index 25fba19..05e16ba 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c
@@ -2775,10 +2775,19 @@ zio_vdev_io_start(zio_t *zio)
(void) atomic_cas_64(&spa->spa_last_io, old, new);
}
+#ifdef illumos
align = 1ULL << vd->vdev_top->vdev_ashift;
if (!(zio->io_flags & ZIO_FLAG_PHYSICAL) &&
P2PHASE(zio->io_size, align) != 0) {
+#else
+ if (zio->io_flags & ZIO_FLAG_PHYSICAL)
+ align = 1ULL << vd->vdev_top->vdev_logical_ashift;
+ else
+ align = 1ULL << vd->vdev_top->vdev_ashift;
+
+ if (P2PHASE(zio->io_size, align) != 0) {
+#endif
/* Transform logical writes to be a full physical block size. */
uint64_t asize = P2ROUNDUP(zio->io_size, align);
char *abuf = NULL;
@@ -2794,6 +2803,7 @@ zio_vdev_io_start(zio_t *zio)
zio_subblock);
}
+#ifdef illumos
/*
* If this is not a physical io, make sure that it is properly aligned
* before proceeding.
@@ -2809,6 +2819,10 @@ zio_vdev_io_start(zio_t *zio)
ASSERT0(P2PHASE(zio->io_offset, SPA_MINBLOCKSIZE));
ASSERT0(P2PHASE(zio->io_size, SPA_MINBLOCKSIZE));
}
+#else
+ ASSERT0(P2PHASE(zio->io_offset, align));
+ ASSERT0(P2PHASE(zio->io_size, align));
+#endif
VERIFY(zio->io_type == ZIO_TYPE_READ || spa_writeable(spa));
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index 0c3cfce..d0c7a74 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -589,7 +589,6 @@ zvol_create_minor(const char *name)
minor_t minor = 0;
char chrbuf[30], blkbuf[30];
#else
- struct cdev *dev;
struct g_provider *pp;
struct g_geom *gp;
uint64_t volsize, mode;
@@ -688,17 +687,25 @@ zvol_create_minor(const char *name)
bioq_init(&zv->zv_queue);
mtx_init(&zv->zv_queue_mtx, "zvol", NULL, MTX_DEF);
} else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
- if (make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
- &dev, &zvol_cdevsw, NULL, UID_ROOT, GID_OPERATOR,
- 0640, "%s/%s", ZVOL_DRIVER, name) != 0) {
+ struct make_dev_args args;
+
+ make_dev_args_init(&args);
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_devsw = &zvol_cdevsw;
+ args.mda_cr = NULL;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_OPERATOR;
+ args.mda_mode = 0640;
+ args.mda_si_drv2 = zv;
+ error = make_dev_s(&args, &zv->zv_dev,
+ "%s/%s", ZVOL_DRIVER, name);
+ if (error != 0) {
kmem_free(zv, sizeof(*zv));
dmu_objset_disown(os, FTAG);
mutex_exit(&zfsdev_state_lock);
- return (SET_ERROR(ENXIO));
+ return (error);
}
- zv->zv_dev = dev;
- dev->si_iosize_max = MAXPHYS;
- dev->si_drv2 = zv;
+ zv->zv_dev->si_iosize_max = MAXPHYS;
}
LIST_INSERT_HEAD(&all_zvols, zv, zv_links);
#endif /* illumos */
@@ -2854,7 +2861,8 @@ zvol_create_snapshots(objset_t *os, const char *name)
break;
}
- if ((error = zvol_create_minor(sname)) != 0) {
+ error = zvol_create_minor(sname);
+ if (error != 0 && error != EEXIST) {
printf("ZFS WARNING: Unable to create ZVOL %s (error=%d).\n",
sname, error);
break;
@@ -2963,18 +2971,29 @@ zvol_rename_minor(zvol_state_t *zv, const char *newname)
g_error_provider(pp, 0);
g_topology_unlock();
} else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
+ struct make_dev_args args;
+
dev = zv->zv_dev;
ASSERT(dev != NULL);
zv->zv_dev = NULL;
destroy_dev(dev);
-
- if (make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
- &dev, &zvol_cdevsw, NULL, UID_ROOT, GID_OPERATOR,
- 0640, "%s/%s", ZVOL_DRIVER, newname) == 0) {
- zv->zv_dev = dev;
- dev->si_iosize_max = MAXPHYS;
- dev->si_drv2 = zv;
+ if (zv->zv_total_opens > 0) {
+ zv->zv_flags &= ~ZVOL_EXCL;
+ zv->zv_total_opens = 0;
+ zvol_last_close(zv);
}
+
+ make_dev_args_init(&args);
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_devsw = &zvol_cdevsw;
+ args.mda_cr = NULL;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_OPERATOR;
+ args.mda_mode = 0640;
+ args.mda_si_drv2 = zv;
+ if (make_dev_s(&args, &zv->zv_dev,
+ "%s/%s", ZVOL_DRIVER, newname) == 0)
+ zv->zv_dev->si_iosize_max = MAXPHYS;
}
strlcpy(zv->zv_name, newname, sizeof(zv->zv_name));
}
@@ -3021,16 +3040,10 @@ zvol_rename_minors(const char *oldname, const char *newname)
static int
zvol_d_open(struct cdev *dev, int flags, int fmt, struct thread *td)
{
- zvol_state_t *zv;
+ zvol_state_t *zv = dev->si_drv2;
int err = 0;
mutex_enter(&zfsdev_state_lock);
- zv = dev->si_drv2;
- if (zv == NULL) {
- mutex_exit(&zfsdev_state_lock);
- return(ENXIO); /* zvol_create_minor() not done yet */
- }
-
if (zv->zv_total_opens == 0)
err = zvol_first_open(zv);
if (err) {
@@ -3068,16 +3081,9 @@ out:
static int
zvol_d_close(struct cdev *dev, int flags, int fmt, struct thread *td)
{
- zvol_state_t *zv;
- int err = 0;
+ zvol_state_t *zv = dev->si_drv2;
mutex_enter(&zfsdev_state_lock);
- zv = dev->si_drv2;
- if (zv == NULL) {
- mutex_exit(&zfsdev_state_lock);
- return(ENXIO);
- }
-
if (zv->zv_flags & ZVOL_EXCL) {
ASSERT(zv->zv_total_opens == 1);
zv->zv_flags &= ~ZVOL_EXCL;
diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c
index 9cf5bc4..78b5637 100644
--- a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c
@@ -45,8 +45,6 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <vm/pmap.h>
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
extern dtrace_id_t dtrace_probeid_error;
extern int (*dtrace_invop_jump_addr)(struct trapframe *);
extern void dtrace_getnanotime(struct timespec *tsp);
diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
index 7f2ec7e..f6577d5 100644
--- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c
@@ -44,9 +44,6 @@
#include <machine/frame.h>
#include <vm/pmap.h>
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
-
extern void dtrace_getnanotime(struct timespec *tsp);
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
diff --git a/sys/cddl/dev/dtrace/arm/dtrace_subr.c b/sys/cddl/dev/dtrace/arm/dtrace_subr.c
index 2aea13e..44dde29 100644
--- a/sys/cddl/dev/dtrace/arm/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/arm/dtrace_subr.c
@@ -51,8 +51,6 @@ __FBSDID("$FreeBSD$");
#define BIT_LR 14
#define BIT_SP 13
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
extern dtrace_id_t dtrace_probeid_error;
extern int (*dtrace_invop_jump_addr)(struct trapframe *);
extern void dtrace_getnanotime(struct timespec *tsp);
diff --git a/sys/cddl/dev/dtrace/i386/dtrace_subr.c b/sys/cddl/dev/dtrace/i386/dtrace_subr.c
index 814019e..be5bd4b 100644
--- a/sys/cddl/dev/dtrace/i386/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/i386/dtrace_subr.c
@@ -46,8 +46,6 @@
#include <vm/pmap.h>
extern uintptr_t kernelbase;
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
extern void dtrace_getnanotime(struct timespec *tsp);
diff --git a/sys/cddl/dev/dtrace/mips/dtrace_subr.c b/sys/cddl/dev/dtrace/mips/dtrace_subr.c
index 4f13b98..a2aa8c7 100644
--- a/sys/cddl/dev/dtrace/mips/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/mips/dtrace_subr.c
@@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$");
#define DELAYBRANCH(x) ((int)(x) < 0)
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
extern dtrace_id_t dtrace_probeid_error;
int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
diff --git a/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c b/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
index c0360fd..33b9e71 100644
--- a/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
+++ b/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c
@@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$");
#define DELAYBRANCH(x) ((int)(x) < 0)
-extern uintptr_t dtrace_in_probe_addr;
-extern int dtrace_in_probe;
extern dtrace_id_t dtrace_probeid_error;
extern int (*dtrace_invop_jump_addr)(struct trapframe *);
diff --git a/sys/compat/cloudabi/cloudabi_clock.c b/sys/compat/cloudabi/cloudabi_clock.c
index ed32cf6..b26d98e 100644
--- a/sys/compat/cloudabi/cloudabi_clock.c
+++ b/sys/compat/cloudabi/cloudabi_clock.c
@@ -31,8 +31,9 @@ __FBSDID("$FreeBSD$");
#include <sys/stdint.h>
#include <sys/syscallsubr.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
#include <compat/cloudabi/cloudabi_util.h>
/* Converts a CloudABI clock ID to a FreeBSD clock ID. */
diff --git a/sys/compat/cloudabi/cloudabi_errno.c b/sys/compat/cloudabi/cloudabi_errno.c
index 5193cfc..38520b9 100644
--- a/sys/compat/cloudabi/cloudabi_errno.c
+++ b/sys/compat/cloudabi/cloudabi_errno.c
@@ -28,7 +28,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_util.h>
/* Converts a FreeBSD errno to a CloudABI errno. */
diff --git a/sys/compat/cloudabi/cloudabi_fd.c b/sys/compat/cloudabi/cloudabi_fd.c
index 17177d2..c044adc 100644
--- a/sys/compat/cloudabi/cloudabi_fd.c
+++ b/sys/compat/cloudabi/cloudabi_fd.c
@@ -38,8 +38,9 @@ __FBSDID("$FreeBSD$");
#include <sys/unistd.h>
#include <sys/vnode.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
#include <compat/cloudabi/cloudabi_util.h>
/* Translation between CloudABI and Capsicum rights. */
diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c
index cdf0585..f48b754 100644
--- a/sys/compat/cloudabi/cloudabi_file.c
+++ b/sys/compat/cloudabi/cloudabi_file.c
@@ -39,8 +39,9 @@ __FBSDID("$FreeBSD$");
#include <sys/uio.h>
#include <sys/vnode.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
#include <compat/cloudabi/cloudabi_util.h>
#include <security/mac/mac_framework.h>
@@ -185,8 +186,8 @@ cloudabi_sys_file_link(struct thread *td,
return (error);
}
- error = kern_linkat(td, uap->fd1, uap->fd2, path1, path2,
- UIO_SYSSPACE, (uap->fd1 & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
+ error = kern_linkat(td, uap->fd1.fd, uap->fd2, path1, path2,
+ UIO_SYSSPACE, (uap->fd1.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
FOLLOW : NOFOLLOW);
cloudabi_freestr(path1);
cloudabi_freestr(path2);
@@ -248,7 +249,7 @@ cloudabi_sys_file_open(struct thread *td,
fflags |= O_SYNC;
cap_rights_set(&rights, CAP_FSYNC);
}
- if ((uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) == 0)
+ if ((uap->dirfd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) == 0)
fflags |= O_NOFOLLOW;
if (write && (fflags & (O_APPEND | O_TRUNC)) == 0)
cap_rights_set(&rights, CAP_SEEK);
@@ -265,7 +266,7 @@ cloudabi_sys_file_open(struct thread *td,
fdrop(fp, td);
return (error);
}
- NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->fd,
+ NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, uap->dirfd.fd,
&rights, td);
error = vn_open(&nd, &fflags, 0777 & ~td->td_proc->p_fd->fd_cmask, fp);
cloudabi_freestr(path);
@@ -657,8 +658,8 @@ cloudabi_sys_file_stat_get(struct thread *td,
return (error);
error = kern_statat(td,
- (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
- AT_SYMLINK_NOFOLLOW, uap->fd, path, UIO_SYSSPACE, &sb, NULL);
+ (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
+ AT_SYMLINK_NOFOLLOW, uap->fd.fd, path, UIO_SYSSPACE, &sb, NULL);
cloudabi_freestr(path);
if (error != 0)
return (error);
@@ -711,8 +712,8 @@ cloudabi_sys_file_stat_put(struct thread *td,
return (error);
convert_utimens_arguments(&fs, uap->flags, ts);
- error = kern_utimensat(td, uap->fd, path, UIO_SYSSPACE, ts,
- UIO_SYSSPACE, (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
+ error = kern_utimensat(td, uap->fd.fd, path, UIO_SYSSPACE, ts,
+ UIO_SYSSPACE, (uap->fd.flags & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) ?
0 : AT_SYMLINK_NOFOLLOW);
cloudabi_freestr(path);
return (error);
@@ -751,7 +752,7 @@ cloudabi_sys_file_unlink(struct thread *td,
if (error != 0)
return (error);
- if (uap->flag & CLOUDABI_UNLINK_REMOVEDIR)
+ if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
else
error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
diff --git a/sys/compat/cloudabi/cloudabi_futex.c b/sys/compat/cloudabi/cloudabi_futex.c
index aec2f33..d12b331 100644
--- a/sys/compat/cloudabi/cloudabi_futex.c
+++ b/sys/compat/cloudabi/cloudabi_futex.c
@@ -37,8 +37,9 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/umtx.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
#include <compat/cloudabi/cloudabi_util.h>
/*
@@ -211,16 +212,16 @@ static int futex_user_cmpxchg(uint32_t *, uint32_t, uint32_t *, uint32_t);
static int
futex_address_create(struct futex_address *fa, struct thread *td,
- const void *object, cloudabi_mflags_t scope)
+ const void *object, cloudabi_scope_t scope)
{
KASSERT(td == curthread,
("Can only create umtx keys for the current thread"));
switch (scope) {
- case CLOUDABI_MAP_PRIVATE:
+ case CLOUDABI_SCOPE_PRIVATE:
return (umtx_key_get(object, TYPE_FUTEX, THREAD_SHARE,
&fa->fa_key));
- case CLOUDABI_MAP_SHARED:
+ case CLOUDABI_SCOPE_SHARED:
return (umtx_key_get(object, TYPE_FUTEX, AUTO_SHARE,
&fa->fa_key));
default:
@@ -258,7 +259,7 @@ futex_condvar_assert(const struct futex_condvar *fc)
static int
futex_condvar_lookup(struct thread *td, const cloudabi_condvar_t *address,
- cloudabi_mflags_t scope, struct futex_condvar **fcret)
+ cloudabi_scope_t scope, struct futex_condvar **fcret)
{
struct futex_address fa_condvar;
struct futex_condvar *fc;
@@ -285,8 +286,8 @@ futex_condvar_lookup(struct thread *td, const cloudabi_condvar_t *address,
static int
futex_condvar_lookup_or_create(struct thread *td,
- const cloudabi_condvar_t *condvar, cloudabi_mflags_t condvar_scope,
- const cloudabi_lock_t *lock, cloudabi_mflags_t lock_scope,
+ const cloudabi_condvar_t *condvar, cloudabi_scope_t condvar_scope,
+ const cloudabi_lock_t *lock, cloudabi_scope_t lock_scope,
struct futex_condvar **fcret)
{
struct futex_address fa_condvar, fa_lock;
@@ -384,7 +385,7 @@ futex_lock_assert(const struct futex_lock *fl)
static int
futex_lock_lookup(struct thread *td, const cloudabi_lock_t *address,
- cloudabi_mflags_t scope, struct futex_lock **flret)
+ cloudabi_scope_t scope, struct futex_lock **flret)
{
struct futex_address fa;
int error;
@@ -973,8 +974,8 @@ futex_user_cmpxchg(uint32_t *obj, uint32_t cmp, uint32_t *old, uint32_t new)
int
cloudabi_futex_condvar_wait(struct thread *td, cloudabi_condvar_t *condvar,
- cloudabi_mflags_t condvar_scope, cloudabi_lock_t *lock,
- cloudabi_mflags_t lock_scope, cloudabi_clockid_t clock_id,
+ cloudabi_scope_t condvar_scope, cloudabi_lock_t *lock,
+ cloudabi_scope_t lock_scope, cloudabi_clockid_t clock_id,
cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
{
struct futex_condvar *fc;
@@ -1046,7 +1047,7 @@ cloudabi_futex_condvar_wait(struct thread *td, cloudabi_condvar_t *condvar,
int
cloudabi_futex_lock_rdlock(struct thread *td, cloudabi_lock_t *lock,
- cloudabi_mflags_t scope, cloudabi_clockid_t clock_id,
+ cloudabi_scope_t scope, cloudabi_clockid_t clock_id,
cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
{
struct futex_lock *fl;
@@ -1065,7 +1066,7 @@ cloudabi_futex_lock_rdlock(struct thread *td, cloudabi_lock_t *lock,
int
cloudabi_futex_lock_wrlock(struct thread *td, cloudabi_lock_t *lock,
- cloudabi_mflags_t scope, cloudabi_clockid_t clock_id,
+ cloudabi_scope_t scope, cloudabi_clockid_t clock_id,
cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
{
struct futex_lock *fl;
diff --git a/sys/compat/cloudabi/cloudabi_mem.c b/sys/compat/cloudabi/cloudabi_mem.c
index 9d82673..34ee14a 100644
--- a/sys/compat/cloudabi/cloudabi_mem.c
+++ b/sys/compat/cloudabi/cloudabi_mem.c
@@ -30,8 +30,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mman.h>
#include <sys/sysproto.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
/* Converts CloudABI's memory protection flags to FreeBSD's. */
static int
diff --git a/sys/compat/cloudabi/cloudabi_proc.c b/sys/compat/cloudabi/cloudabi_proc.c
index 8d0b6e7..139af2c 100644
--- a/sys/compat/cloudabi/cloudabi_proc.c
+++ b/sys/compat/cloudabi/cloudabi_proc.c
@@ -38,8 +38,9 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/unistd.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
int
cloudabi_sys_proc_exec(struct thread *td,
diff --git a/sys/compat/cloudabi/cloudabi_proto.h b/sys/compat/cloudabi/cloudabi_proto.h
index e4baffd..95271fd 100644
--- a/sys/compat/cloudabi/cloudabi_proto.h
+++ b/sys/compat/cloudabi/cloudabi_proto.h
@@ -30,5 +30,7 @@
* calls. Unfortunately, we don't have a separate system call table for
* those, so rely on the system call table from COMPAT_CLOUDABI64.
*/
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi64/cloudabi64_proto.h>
diff --git a/sys/compat/cloudabi/cloudabi_sock.c b/sys/compat/cloudabi/cloudabi_sock.c
index cdccdff..b66f0ab 100644
--- a/sys/compat/cloudabi/cloudabi_sock.c
+++ b/sys/compat/cloudabi/cloudabi_sock.c
@@ -43,8 +43,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
#include <compat/cloudabi/cloudabi_util.h>
/* Converts FreeBSD's struct sockaddr to CloudABI's cloudabi_sockaddr_t. */
@@ -117,12 +118,12 @@ cloudabi_sys_sock_accept(struct thread *td,
if (uap->buf == NULL) {
/* Only return the new file descriptor number. */
- return (kern_accept(td, uap->s, NULL, NULL, NULL));
+ return (kern_accept(td, uap->sock, NULL, NULL, NULL));
} else {
/* Also return properties of the new socket descriptor. */
sal = MAX(sizeof(struct sockaddr_in),
sizeof(struct sockaddr_in6));
- error = kern_accept(td, uap->s, (void *)&sa, &sal, NULL);
+ error = kern_accept(td, uap->sock, (void *)&sa, &sal, NULL);
if (error != 0)
return (error);
@@ -143,7 +144,7 @@ cloudabi_sys_sock_bind(struct thread *td,
error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
if (error != 0)
return (error);
- return (kern_bindat(td, uap->fd, uap->s, (struct sockaddr *)&sun));
+ return (kern_bindat(td, uap->fd, uap->sock, (struct sockaddr *)&sun));
}
int
@@ -156,7 +157,8 @@ cloudabi_sys_sock_connect(struct thread *td,
error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
if (error != 0)
return (error);
- return (kern_connectat(td, uap->fd, uap->s, (struct sockaddr *)&sun));
+ return (kern_connectat(td, uap->fd, uap->sock,
+ (struct sockaddr *)&sun));
}
int
@@ -164,7 +166,7 @@ cloudabi_sys_sock_listen(struct thread *td,
struct cloudabi_sys_sock_listen_args *uap)
{
struct listen_args listen_args = {
- .s = uap->s,
+ .s = uap->sock,
.backlog = uap->backlog,
};
@@ -176,7 +178,7 @@ cloudabi_sys_sock_shutdown(struct thread *td,
struct cloudabi_sys_sock_shutdown_args *uap)
{
struct shutdown_args shutdown_args = {
- .s = uap->fd,
+ .s = uap->sock,
};
switch (uap->how) {
@@ -207,7 +209,7 @@ cloudabi_sys_sock_stat_get(struct thread *td,
struct socket *so;
int error;
- error = getsock_cap(td, uap->fd, cap_rights_init(&rights,
+ error = getsock_cap(td, uap->sock, cap_rights_init(&rights,
CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL);
if (error != 0)
return (error);
@@ -243,7 +245,7 @@ cloudabi_sys_sock_stat_get(struct thread *td,
/* Set ss_state. */
if ((so->so_options & SO_ACCEPTCONN) != 0)
- ss.ss_state |= CLOUDABI_SOCKSTAT_ACCEPTCONN;
+ ss.ss_state |= CLOUDABI_SOCKSTATE_ACCEPTCONN;
fdrop(fp, td);
return (copyout(&ss, uap->buf, sizeof(ss)));
diff --git a/sys/compat/cloudabi/cloudabi_thread.c b/sys/compat/cloudabi/cloudabi_thread.c
index 8aee708..37dc794 100644
--- a/sys/compat/cloudabi/cloudabi_thread.c
+++ b/sys/compat/cloudabi/cloudabi_thread.c
@@ -31,8 +31,9 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/syscallsubr.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
+
#include <compat/cloudabi/cloudabi_proto.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
int
cloudabi_sys_thread_exit(struct thread *td,
diff --git a/sys/compat/cloudabi/cloudabi_util.h b/sys/compat/cloudabi/cloudabi_util.h
index 10da229..c0a02aa 100644
--- a/sys/compat/cloudabi/cloudabi_util.h
+++ b/sys/compat/cloudabi/cloudabi_util.h
@@ -30,7 +30,7 @@
#include <sys/socket.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi_types_common.h>
struct file;
struct thread;
@@ -67,13 +67,13 @@ int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *);
* sleep on a lock or condition variable.
*/
int cloudabi_futex_condvar_wait(struct thread *, cloudabi_condvar_t *,
- cloudabi_mflags_t, cloudabi_lock_t *, cloudabi_mflags_t, cloudabi_clockid_t,
+ cloudabi_scope_t, cloudabi_lock_t *, cloudabi_scope_t, cloudabi_clockid_t,
cloudabi_timestamp_t, cloudabi_timestamp_t);
int cloudabi_futex_lock_rdlock(struct thread *, cloudabi_lock_t *,
- cloudabi_mflags_t, cloudabi_clockid_t, cloudabi_timestamp_t,
+ cloudabi_scope_t, cloudabi_clockid_t, cloudabi_timestamp_t,
cloudabi_timestamp_t);
int cloudabi_futex_lock_wrlock(struct thread *, cloudabi_lock_t *,
- cloudabi_mflags_t, cloudabi_clockid_t, cloudabi_timestamp_t,
+ cloudabi_scope_t, cloudabi_clockid_t, cloudabi_timestamp_t,
cloudabi_timestamp_t);
#endif
diff --git a/sys/compat/cloudabi64/Makefile b/sys/compat/cloudabi64/Makefile
index 3fbef57..83d27a3 100644
--- a/sys/compat/cloudabi64/Makefile
+++ b/sys/compat/cloudabi64/Makefile
@@ -8,5 +8,7 @@ sysent: cloudabi64_sysent.c cloudabi64_syscall.h cloudabi64_proto.h \
cloudabi64_sysent.c cloudabi64_syscall.h cloudabi64_proto.h \
cloudabi64_syscalls.c cloudabi64_systrace_args.c: \
- ../../kern/makesyscalls.sh syscalls.master syscalls.conf
- sh ../../kern/makesyscalls.sh syscalls.master syscalls.conf
+ ../../kern/makesyscalls.sh ../../contrib/cloudabi/syscalls.master \
+ syscalls.conf
+ sh ../../kern/makesyscalls.sh ../../contrib/cloudabi/syscalls.master \
+ syscalls.conf
diff --git a/sys/compat/cloudabi64/cloudabi64_fd.c b/sys/compat/cloudabi64/cloudabi64_fd.c
index b2fd67d..7d0c69a 100644
--- a/sys/compat/cloudabi64/cloudabi64_fd.c
+++ b/sys/compat/cloudabi64/cloudabi64_fd.c
@@ -34,7 +34,8 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/uio.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi64/cloudabi64_proto.h>
/* Copies in 64-bit iovec structures from userspace. */
diff --git a/sys/compat/cloudabi64/cloudabi64_module.c b/sys/compat/cloudabi64/cloudabi64_module.c
index ca8ecf4..de890bc 100644
--- a/sys/compat/cloudabi64/cloudabi64_module.c
+++ b/sys/compat/cloudabi64/cloudabi64_module.c
@@ -36,7 +36,8 @@ __FBSDID("$FreeBSD$");
#include <sys/sysent.h>
#include <sys/systm.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi64/cloudabi64_util.h>
register_t *
@@ -98,6 +99,7 @@ cloudabi64_fixup(register_t **stack_base, struct image_params *imgp)
#define PTR(type, ptr) { .a_type = (type), .a_ptr = (uintptr_t)(ptr) }
PTR(CLOUDABI_AT_ARGDATA, argdata),
VAL(CLOUDABI_AT_ARGDATALEN, argdatalen),
+ VAL(CLOUDABI_AT_BASE, args->base),
PTR(CLOUDABI_AT_CANARY, canary),
VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)),
VAL(CLOUDABI_AT_NCPUS, mp_ncpus),
diff --git a/sys/compat/cloudabi64/cloudabi64_poll.c b/sys/compat/cloudabi64/cloudabi64_poll.c
index c8f1811..e44d69f 100644
--- a/sys/compat/cloudabi64/cloudabi64_poll.c
+++ b/sys/compat/cloudabi64/cloudabi64_poll.c
@@ -30,9 +30,10 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/syscallsubr.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi/cloudabi_util.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
#include <compat/cloudabi64/cloudabi64_proto.h>
/* Converts a FreeBSD signal number to a CloudABI signal number. */
@@ -248,7 +249,7 @@ cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
* Bandaid to support CloudABI futex constructs that are not
* implemented through FreeBSD's kqueue().
*/
- if (uap->nevents == 1) {
+ if (uap->nsubscriptions == 1) {
cloudabi64_subscription_t sub;
cloudabi64_event_t ev = {};
int error;
@@ -291,7 +292,7 @@ cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
td->td_retval[0] = 1;
return (copyout(&ev, uap->out, sizeof(ev)));
}
- } else if (uap->nevents == 2) {
+ } else if (uap->nsubscriptions == 2) {
cloudabi64_subscription_t sub[2];
cloudabi64_event_t ev[2] = {};
int error;
@@ -365,7 +366,7 @@ cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
}
}
- return (kern_kevent_anonymous(td, uap->nevents, &copyops));
+ return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
}
int
diff --git a/sys/compat/cloudabi64/cloudabi64_proto.h b/sys/compat/cloudabi64/cloudabi64_proto.h
index 8c65fe3..79a0f60 100644
--- a/sys/compat/cloudabi64/cloudabi64_proto.h
+++ b/sys/compat/cloudabi64/cloudabi64_proto.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/compat/cloudabi64/syscalls.master 286318 2015-08-05 13:09:46Z ed
+ * created from FreeBSD: head/sys/contrib/cloudabi/syscalls.master 297468 2016-03-31 18:50:06Z ed
*/
#ifndef _CLOUDABI64_SYSPROTO_H_
@@ -43,7 +43,7 @@ struct cloudabi_sys_clock_time_get_args {
};
struct cloudabi_sys_condvar_signal_args {
char condvar_l_[PADL_(cloudabi_condvar_t *)]; cloudabi_condvar_t * condvar; char condvar_r_[PADR_(cloudabi_condvar_t *)];
- char scope_l_[PADL_(cloudabi_mflags_t)]; cloudabi_mflags_t scope; char scope_r_[PADR_(cloudabi_mflags_t)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
char nwaiters_l_[PADL_(cloudabi_nthreads_t)]; cloudabi_nthreads_t nwaiters; char nwaiters_r_[PADR_(cloudabi_nthreads_t)];
};
struct cloudabi_sys_fd_close_args {
@@ -64,19 +64,19 @@ struct cloudabi_sys_fd_dup_args {
struct cloudabi64_sys_fd_pread_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char iov_l_[PADL_(const cloudabi64_iovec_t *)]; const cloudabi64_iovec_t * iov; char iov_r_[PADR_(const cloudabi64_iovec_t *)];
- char iovcnt_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t iovcnt; char iovcnt_r_[PADR_(cloudabi64_size_t)];
+ char iovcnt_l_[PADL_(size_t)]; size_t iovcnt; char iovcnt_r_[PADR_(size_t)];
char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
};
struct cloudabi64_sys_fd_pwrite_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char iov_l_[PADL_(const cloudabi64_ciovec_t *)]; const cloudabi64_ciovec_t * iov; char iov_r_[PADR_(const cloudabi64_ciovec_t *)];
- char iovcnt_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t iovcnt; char iovcnt_r_[PADR_(cloudabi64_size_t)];
+ char iovcnt_l_[PADL_(size_t)]; size_t iovcnt; char iovcnt_r_[PADR_(size_t)];
char offset_l_[PADL_(cloudabi_filesize_t)]; cloudabi_filesize_t offset; char offset_r_[PADR_(cloudabi_filesize_t)];
};
struct cloudabi64_sys_fd_read_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char iov_l_[PADL_(const cloudabi64_iovec_t *)]; const cloudabi64_iovec_t * iov; char iov_r_[PADR_(const cloudabi64_iovec_t *)];
- char iovcnt_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t iovcnt; char iovcnt_r_[PADR_(cloudabi64_size_t)];
+ char iovcnt_l_[PADL_(size_t)]; size_t iovcnt; char iovcnt_r_[PADR_(size_t)];
};
struct cloudabi_sys_fd_replace_args {
char from_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t from; char from_r_[PADR_(cloudabi_fd_t)];
@@ -102,7 +102,7 @@ struct cloudabi_sys_fd_sync_args {
struct cloudabi64_sys_fd_write_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char iov_l_[PADL_(const cloudabi64_ciovec_t *)]; const cloudabi64_ciovec_t * iov; char iov_r_[PADR_(const cloudabi64_ciovec_t *)];
- char iovcnt_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t iovcnt; char iovcnt_r_[PADR_(cloudabi64_size_t)];
+ char iovcnt_l_[PADL_(size_t)]; size_t iovcnt; char iovcnt_r_[PADR_(size_t)];
};
struct cloudabi_sys_file_advise_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
@@ -130,7 +130,7 @@ struct cloudabi_sys_file_link_args {
char path2len_l_[PADL_(size_t)]; size_t path2len; char path2len_r_[PADR_(size_t)];
};
struct cloudabi_sys_file_open_args {
- char fd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t fd; char fd_r_[PADR_(cloudabi_lookup_t)];
+ char dirfd_l_[PADL_(cloudabi_lookup_t)]; cloudabi_lookup_t dirfd; char dirfd_r_[PADR_(cloudabi_lookup_t)];
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char pathlen_l_[PADL_(size_t)]; size_t pathlen; char pathlen_r_[PADR_(size_t)];
char oflags_l_[PADL_(cloudabi_oflags_t)]; cloudabi_oflags_t oflags; char oflags_r_[PADR_(cloudabi_oflags_t)];
@@ -146,7 +146,7 @@ struct cloudabi_sys_file_readlink_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char pathlen_l_[PADL_(size_t)]; size_t pathlen; char pathlen_r_[PADR_(size_t)];
- char buf_l_[PADL_(void *)]; void * buf; char buf_r_[PADR_(void *)];
+ char buf_l_[PADL_(char *)]; char * buf; char buf_r_[PADR_(char *)];
char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)];
};
struct cloudabi_sys_file_rename_args {
@@ -190,11 +190,11 @@ struct cloudabi_sys_file_unlink_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char pathlen_l_[PADL_(size_t)]; size_t pathlen; char pathlen_r_[PADR_(size_t)];
- char flag_l_[PADL_(cloudabi_ulflags_t)]; cloudabi_ulflags_t flag; char flag_r_[PADR_(cloudabi_ulflags_t)];
+ char flags_l_[PADL_(cloudabi_ulflags_t)]; cloudabi_ulflags_t flags; char flags_r_[PADR_(cloudabi_ulflags_t)];
};
struct cloudabi_sys_lock_unlock_args {
char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
- char scope_l_[PADL_(cloudabi_mflags_t)]; cloudabi_mflags_t scope; char scope_r_[PADR_(cloudabi_mflags_t)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
};
struct cloudabi_sys_mem_advise_args {
char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
@@ -234,7 +234,7 @@ struct cloudabi_sys_mem_unmap_args {
struct cloudabi64_sys_poll_args {
char in_l_[PADL_(const cloudabi64_subscription_t *)]; const cloudabi64_subscription_t * in; char in_r_[PADR_(const cloudabi64_subscription_t *)];
char out_l_[PADL_(cloudabi64_event_t *)]; cloudabi64_event_t * out; char out_r_[PADR_(cloudabi64_event_t *)];
- char nevents_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t nevents; char nevents_r_[PADR_(cloudabi64_size_t)];
+ char nsubscriptions_l_[PADL_(size_t)]; size_t nsubscriptions; char nsubscriptions_r_[PADR_(size_t)];
};
struct cloudabi_sys_proc_exec_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
@@ -257,41 +257,41 @@ struct cloudabi_sys_random_get_args {
char nbyte_l_[PADL_(size_t)]; size_t nbyte; char nbyte_r_[PADR_(size_t)];
};
struct cloudabi_sys_sock_accept_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char buf_l_[PADL_(cloudabi_sockstat_t *)]; cloudabi_sockstat_t * buf; char buf_r_[PADR_(cloudabi_sockstat_t *)];
};
struct cloudabi_sys_sock_bind_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char pathlen_l_[PADL_(size_t)]; size_t pathlen; char pathlen_r_[PADR_(size_t)];
};
struct cloudabi_sys_sock_connect_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
char pathlen_l_[PADL_(size_t)]; size_t pathlen; char pathlen_r_[PADR_(size_t)];
};
struct cloudabi_sys_sock_listen_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char backlog_l_[PADL_(cloudabi_backlog_t)]; cloudabi_backlog_t backlog; char backlog_r_[PADR_(cloudabi_backlog_t)];
};
struct cloudabi64_sys_sock_recv_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char in_l_[PADL_(const cloudabi64_recv_in_t *)]; const cloudabi64_recv_in_t * in; char in_r_[PADR_(const cloudabi64_recv_in_t *)];
char out_l_[PADL_(cloudabi64_recv_out_t *)]; cloudabi64_recv_out_t * out; char out_r_[PADR_(cloudabi64_recv_out_t *)];
};
struct cloudabi64_sys_sock_send_args {
- char s_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t s; char s_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char in_l_[PADL_(const cloudabi64_send_in_t *)]; const cloudabi64_send_in_t * in; char in_r_[PADR_(const cloudabi64_send_in_t *)];
char out_l_[PADL_(cloudabi64_send_out_t *)]; cloudabi64_send_out_t * out; char out_r_[PADR_(cloudabi64_send_out_t *)];
};
struct cloudabi_sys_sock_shutdown_args {
- char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char how_l_[PADL_(cloudabi_sdflags_t)]; cloudabi_sdflags_t how; char how_r_[PADR_(cloudabi_sdflags_t)];
};
struct cloudabi_sys_sock_stat_get_args {
- char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
+ char sock_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t sock; char sock_r_[PADR_(cloudabi_fd_t)];
char buf_l_[PADL_(cloudabi_sockstat_t *)]; cloudabi_sockstat_t * buf; char buf_r_[PADR_(cloudabi_sockstat_t *)];
char flags_l_[PADL_(cloudabi_ssflags_t)]; cloudabi_ssflags_t flags; char flags_r_[PADR_(cloudabi_ssflags_t)];
};
@@ -300,7 +300,7 @@ struct cloudabi64_sys_thread_create_args {
};
struct cloudabi_sys_thread_exit_args {
char lock_l_[PADL_(cloudabi_lock_t *)]; cloudabi_lock_t * lock; char lock_r_[PADR_(cloudabi_lock_t *)];
- char scope_l_[PADL_(cloudabi_mflags_t)]; cloudabi_mflags_t scope; char scope_r_[PADR_(cloudabi_mflags_t)];
+ char scope_l_[PADL_(cloudabi_scope_t)]; cloudabi_scope_t scope; char scope_r_[PADR_(cloudabi_scope_t)];
};
struct cloudabi_sys_thread_tcb_set_args {
char tcb_l_[PADL_(void *)]; void * tcb; char tcb_r_[PADR_(void *)];
@@ -311,9 +311,9 @@ struct cloudabi_sys_thread_yield_args {
struct cloudabi64_sys_poll_fd_args {
char fd_l_[PADL_(cloudabi_fd_t)]; cloudabi_fd_t fd; char fd_r_[PADR_(cloudabi_fd_t)];
char in_l_[PADL_(const cloudabi64_subscription_t *)]; const cloudabi64_subscription_t * in; char in_r_[PADR_(const cloudabi64_subscription_t *)];
- char nin_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t nin; char nin_r_[PADR_(cloudabi64_size_t)];
+ char nin_l_[PADL_(size_t)]; size_t nin; char nin_r_[PADR_(size_t)];
char out_l_[PADL_(cloudabi64_event_t *)]; cloudabi64_event_t * out; char out_r_[PADR_(cloudabi64_event_t *)];
- char nout_l_[PADL_(cloudabi64_size_t)]; cloudabi64_size_t nout; char nout_r_[PADR_(cloudabi64_size_t)];
+ char nout_l_[PADL_(size_t)]; size_t nout; char nout_r_[PADR_(size_t)];
char timeout_l_[PADL_(const cloudabi64_subscription_t *)]; const cloudabi64_subscription_t * timeout; char timeout_r_[PADR_(const cloudabi64_subscription_t *)];
};
int cloudabi_sys_clock_res_get(struct thread *, struct cloudabi_sys_clock_res_get_args *);
diff --git a/sys/compat/cloudabi64/cloudabi64_sock.c b/sys/compat/cloudabi64/cloudabi64_sock.c
index c612a32..e6b9c94 100644
--- a/sys/compat/cloudabi64/cloudabi64_sock.c
+++ b/sys/compat/cloudabi64/cloudabi64_sock.c
@@ -35,9 +35,10 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/uio.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi/cloudabi_util.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
#include <compat/cloudabi64/cloudabi64_proto.h>
static MALLOC_DEFINE(M_SOCKET, "socket", "CloudABI socket");
@@ -82,7 +83,7 @@ cloudabi64_sys_sock_recv(struct thread *td,
msghdr.msg_flags |= MSG_WAITALL;
/* TODO(ed): Add file descriptor passing. */
- error = kern_recvit(td, uap->s, &msghdr, UIO_SYSSPACE, NULL);
+ error = kern_recvit(td, uap->sock, &msghdr, UIO_SYSSPACE, NULL);
free(msghdr.msg_iov, M_SOCKET);
if (error != 0)
return (error);
@@ -132,7 +133,7 @@ cloudabi64_sys_sock_send(struct thread *td,
flags |= MSG_EOR;
/* TODO(ed): Add file descriptor passing. */
- error = kern_sendit(td, uap->s, &msghdr, flags, NULL, UIO_USERSPACE);
+ error = kern_sendit(td, uap->sock, &msghdr, flags, NULL, UIO_USERSPACE);
free(msghdr.msg_iov, M_SOCKET);
if (error != 0)
return (error);
diff --git a/sys/compat/cloudabi64/cloudabi64_syscall.h b/sys/compat/cloudabi64/cloudabi64_syscall.h
index 40c017a..b5694bf 100644
--- a/sys/compat/cloudabi64/cloudabi64_syscall.h
+++ b/sys/compat/cloudabi64/cloudabi64_syscall.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/compat/cloudabi64/syscalls.master 286318 2015-08-05 13:09:46Z ed
+ * created from FreeBSD: head/sys/contrib/cloudabi/syscalls.master 297468 2016-03-31 18:50:06Z ed
*/
#define CLOUDABI64_SYS_cloudabi_sys_clock_res_get 0
diff --git a/sys/compat/cloudabi64/cloudabi64_syscalls.c b/sys/compat/cloudabi64/cloudabi64_syscalls.c
index 5c0732b..03407ff 100644
--- a/sys/compat/cloudabi64/cloudabi64_syscalls.c
+++ b/sys/compat/cloudabi64/cloudabi64_syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/compat/cloudabi64/syscalls.master 286318 2015-08-05 13:09:46Z ed
+ * created from FreeBSD: head/sys/contrib/cloudabi/syscalls.master 297468 2016-03-31 18:50:06Z ed
*/
const char *cloudabi64_syscallnames[] = {
diff --git a/sys/compat/cloudabi64/cloudabi64_sysent.c b/sys/compat/cloudabi64/cloudabi64_sysent.c
index 2ed5042..50f4a65 100644
--- a/sys/compat/cloudabi64/cloudabi64_sysent.c
+++ b/sys/compat/cloudabi64/cloudabi64_sysent.c
@@ -3,12 +3,12 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/compat/cloudabi64/syscalls.master 286318 2015-08-05 13:09:46Z ed
+ * created from FreeBSD: head/sys/contrib/cloudabi/syscalls.master 297468 2016-03-31 18:50:06Z ed
*/
#include <sys/sysent.h>
#include <sys/sysproto.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
#include <compat/cloudabi64/cloudabi64_proto.h>
#define AS(name) (sizeof(struct name) / sizeof(register_t))
diff --git a/sys/compat/cloudabi64/cloudabi64_systrace_args.c b/sys/compat/cloudabi64/cloudabi64_systrace_args.c
index b3176aa..9429e8e 100644
--- a/sys/compat/cloudabi64/cloudabi64_systrace_args.c
+++ b/sys/compat/cloudabi64/cloudabi64_systrace_args.c
@@ -30,7 +30,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 2: {
struct cloudabi_sys_condvar_signal_args *p = params;
uarg[0] = (intptr_t) p->condvar; /* cloudabi_condvar_t * */
- iarg[1] = p->scope; /* cloudabi_mflags_t */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
iarg[2] = p->nwaiters; /* cloudabi_nthreads_t */
*n_args = 3;
break;
@@ -75,7 +75,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_fd_pread_args *p = params;
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->iov; /* const cloudabi64_iovec_t * */
- iarg[2] = p->iovcnt; /* cloudabi64_size_t */
+ uarg[2] = p->iovcnt; /* size_t */
iarg[3] = p->offset; /* cloudabi_filesize_t */
*n_args = 4;
break;
@@ -85,7 +85,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_fd_pwrite_args *p = params;
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->iov; /* const cloudabi64_ciovec_t * */
- iarg[2] = p->iovcnt; /* cloudabi64_size_t */
+ uarg[2] = p->iovcnt; /* size_t */
iarg[3] = p->offset; /* cloudabi_filesize_t */
*n_args = 4;
break;
@@ -95,7 +95,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_fd_read_args *p = params;
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->iov; /* const cloudabi64_iovec_t * */
- iarg[2] = p->iovcnt; /* cloudabi64_size_t */
+ uarg[2] = p->iovcnt; /* size_t */
*n_args = 3;
break;
}
@@ -145,7 +145,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_fd_write_args *p = params;
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->iov; /* const cloudabi64_ciovec_t * */
- iarg[2] = p->iovcnt; /* cloudabi64_size_t */
+ uarg[2] = p->iovcnt; /* size_t */
*n_args = 3;
break;
}
@@ -193,7 +193,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_file_open */
case 21: {
struct cloudabi_sys_file_open_args *p = params;
- iarg[0] = p->fd; /* cloudabi_lookup_t */
+ iarg[0] = p->dirfd; /* cloudabi_lookup_t */
uarg[1] = (intptr_t) p->path; /* const char * */
uarg[2] = p->pathlen; /* size_t */
iarg[3] = p->oflags; /* cloudabi_oflags_t */
@@ -217,7 +217,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->path; /* const char * */
uarg[2] = p->pathlen; /* size_t */
- uarg[3] = (intptr_t) p->buf; /* void * */
+ uarg[3] = (intptr_t) p->buf; /* char * */
uarg[4] = p->bufsize; /* size_t */
*n_args = 5;
break;
@@ -289,7 +289,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->path; /* const char * */
uarg[2] = p->pathlen; /* size_t */
- iarg[3] = p->flag; /* cloudabi_ulflags_t */
+ iarg[3] = p->flags; /* cloudabi_ulflags_t */
*n_args = 4;
break;
}
@@ -297,7 +297,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 31: {
struct cloudabi_sys_lock_unlock_args *p = params;
uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
- iarg[1] = p->scope; /* cloudabi_mflags_t */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
*n_args = 2;
break;
}
@@ -369,7 +369,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_poll_args *p = params;
uarg[0] = (intptr_t) p->in; /* const cloudabi64_subscription_t * */
uarg[1] = (intptr_t) p->out; /* cloudabi64_event_t * */
- iarg[2] = p->nevents; /* cloudabi64_size_t */
+ uarg[2] = p->nsubscriptions; /* size_t */
*n_args = 3;
break;
}
@@ -414,7 +414,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_accept */
case 45: {
struct cloudabi_sys_sock_accept_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->buf; /* cloudabi_sockstat_t * */
*n_args = 2;
break;
@@ -422,7 +422,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_bind */
case 46: {
struct cloudabi_sys_sock_bind_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
iarg[1] = p->fd; /* cloudabi_fd_t */
uarg[2] = (intptr_t) p->path; /* const char * */
uarg[3] = p->pathlen; /* size_t */
@@ -432,7 +432,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_connect */
case 47: {
struct cloudabi_sys_sock_connect_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
iarg[1] = p->fd; /* cloudabi_fd_t */
uarg[2] = (intptr_t) p->path; /* const char * */
uarg[3] = p->pathlen; /* size_t */
@@ -442,7 +442,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_listen */
case 48: {
struct cloudabi_sys_sock_listen_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
iarg[1] = p->backlog; /* cloudabi_backlog_t */
*n_args = 2;
break;
@@ -450,7 +450,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi64_sys_sock_recv */
case 49: {
struct cloudabi64_sys_sock_recv_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->in; /* const cloudabi64_recv_in_t * */
uarg[2] = (intptr_t) p->out; /* cloudabi64_recv_out_t * */
*n_args = 3;
@@ -459,7 +459,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi64_sys_sock_send */
case 50: {
struct cloudabi64_sys_sock_send_args *p = params;
- iarg[0] = p->s; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->in; /* const cloudabi64_send_in_t * */
uarg[2] = (intptr_t) p->out; /* cloudabi64_send_out_t * */
*n_args = 3;
@@ -468,7 +468,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_shutdown */
case 51: {
struct cloudabi_sys_sock_shutdown_args *p = params;
- iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
iarg[1] = p->how; /* cloudabi_sdflags_t */
*n_args = 2;
break;
@@ -476,7 +476,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
/* cloudabi_sys_sock_stat_get */
case 52: {
struct cloudabi_sys_sock_stat_get_args *p = params;
- iarg[0] = p->fd; /* cloudabi_fd_t */
+ iarg[0] = p->sock; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->buf; /* cloudabi_sockstat_t * */
iarg[2] = p->flags; /* cloudabi_ssflags_t */
*n_args = 3;
@@ -493,7 +493,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 54: {
struct cloudabi_sys_thread_exit_args *p = params;
uarg[0] = (intptr_t) p->lock; /* cloudabi_lock_t * */
- iarg[1] = p->scope; /* cloudabi_mflags_t */
+ iarg[1] = p->scope; /* cloudabi_scope_t */
*n_args = 2;
break;
}
@@ -514,9 +514,9 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct cloudabi64_sys_poll_fd_args *p = params;
iarg[0] = p->fd; /* cloudabi_fd_t */
uarg[1] = (intptr_t) p->in; /* const cloudabi64_subscription_t * */
- iarg[2] = p->nin; /* cloudabi64_size_t */
+ uarg[2] = p->nin; /* size_t */
uarg[3] = (intptr_t) p->out; /* cloudabi64_event_t * */
- iarg[4] = p->nout; /* cloudabi64_size_t */
+ uarg[4] = p->nout; /* size_t */
uarg[5] = (intptr_t) p->timeout; /* const cloudabi64_subscription_t * */
*n_args = 6;
break;
@@ -561,7 +561,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "cloudabi_condvar_t *";
break;
case 1:
- p = "cloudabi_mflags_t";
+ p = "cloudabi_scope_t";
break;
case 2:
p = "cloudabi_nthreads_t";
@@ -630,7 +630,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "const cloudabi64_iovec_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
case 3:
p = "cloudabi_filesize_t";
@@ -649,7 +649,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "const cloudabi64_ciovec_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
case 3:
p = "cloudabi_filesize_t";
@@ -668,7 +668,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "const cloudabi64_iovec_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
default:
break;
@@ -752,7 +752,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "const cloudabi64_ciovec_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
default:
break;
@@ -891,7 +891,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "size_t";
break;
case 3:
- p = "void *";
+ p = "char *";
break;
case 4:
p = "size_t";
@@ -1043,7 +1043,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "cloudabi_lock_t *";
break;
case 1:
- p = "cloudabi_mflags_t";
+ p = "cloudabi_scope_t";
break;
default:
break;
@@ -1171,7 +1171,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "cloudabi64_event_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
default:
break;
@@ -1377,7 +1377,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "cloudabi_lock_t *";
break;
case 1:
- p = "cloudabi_mflags_t";
+ p = "cloudabi_scope_t";
break;
default:
break;
@@ -1406,13 +1406,13 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "const cloudabi64_subscription_t *";
break;
case 2:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
case 3:
p = "cloudabi64_event_t *";
break;
case 4:
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
case 5:
p = "const cloudabi64_subscription_t *";
@@ -1475,17 +1475,17 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* cloudabi64_sys_fd_pread */
case 8:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
/* cloudabi64_sys_fd_pwrite */
case 9:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
/* cloudabi64_sys_fd_read */
case 10:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
/* cloudabi_sys_fd_replace */
case 11:
@@ -1515,7 +1515,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* cloudabi64_sys_fd_write */
case 16:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
/* cloudabi_sys_file_advise */
case 17:
@@ -1630,7 +1630,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* cloudabi64_sys_poll */
case 39:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
/* cloudabi_sys_proc_exec */
case 40:
@@ -1677,12 +1677,12 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* cloudabi64_sys_sock_recv */
case 49:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "void";
break;
/* cloudabi64_sys_sock_send */
case 50:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "void";
break;
/* cloudabi_sys_sock_shutdown */
case 51:
@@ -1714,7 +1714,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* cloudabi64_sys_poll_fd */
case 57:
if (ndx == 0 || ndx == 1)
- p = "cloudabi64_size_t";
+ p = "size_t";
break;
default:
break;
diff --git a/sys/compat/cloudabi64/cloudabi64_thread.c b/sys/compat/cloudabi64/cloudabi64_thread.c
index 04b1782..51961f8 100644
--- a/sys/compat/cloudabi64/cloudabi64_thread.c
+++ b/sys/compat/cloudabi64/cloudabi64_thread.c
@@ -30,7 +30,8 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/systm.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi64/cloudabi64_proto.h>
#include <compat/cloudabi64/cloudabi64_util.h>
diff --git a/sys/compat/cloudabi64/cloudabi64_util.h b/sys/compat/cloudabi64/cloudabi64_util.h
index 180a01e..dcec70e 100644
--- a/sys/compat/cloudabi64/cloudabi64_util.h
+++ b/sys/compat/cloudabi64/cloudabi64_util.h
@@ -31,7 +31,7 @@
#include <sys/types.h>
#include <sys/imgact_elf.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
struct image_params;
struct thread;
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index bdcdf6f..598bdc5 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1653,6 +1653,19 @@ freebsd32_do_sendfile(struct thread *td,
hdtr32.hdr_cnt, &hdr_uio);
if (error)
goto out;
+#ifdef COMPAT_FREEBSD4
+ /*
+ * In FreeBSD < 5.0 the nbytes to send also included
+ * the header. If compat is specified subtract the
+ * header size from nbytes.
+ */
+ if (compat) {
+ if (uap->nbytes > hdr_uio->uio_resid)
+ uap->nbytes -= hdr_uio->uio_resid;
+ else
+ uap->nbytes = 0;
+ }
+#endif
}
if (hdtr.trailers != NULL) {
iov32 = PTRIN(hdtr32.trailers);
@@ -1670,7 +1683,7 @@ freebsd32_do_sendfile(struct thread *td,
goto out;
error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset,
- uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
+ uap->nbytes, &sbytes, uap->flags, td);
fdrop(fp, td);
if (uap->sbytes != NULL)
diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c
index b1ceadf..3e5a15c 100644
--- a/sys/compat/linux/linux_event.c
+++ b/sys/compat/linux/linux_event.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/user.h>
#include <sys/file.h>
#include <sys/filedesc.h>
+#include <sys/filio.h>
#include <sys/errno.h>
#include <sys/event.h>
#include <sys/poll.h>
@@ -750,6 +751,8 @@ retry:
if (UINT64_MAX - efd->efd_count <= count) {
if ((efd->efd_flags & LINUX_O_NONBLOCK) != 0) {
mtx_unlock(&efd->efd_lock);
+ /* Do not not return the number of bytes written */
+ uio->uio_resid += sizeof(eventfd_t);
return (EAGAIN);
}
error = mtx_sleep(&efd->efd_count, &efd->efd_lock,
@@ -871,8 +874,24 @@ static int
eventfd_ioctl(struct file *fp, u_long cmd, void *data,
struct ucred *active_cred, struct thread *td)
{
+ struct eventfd *efd;
- return (ENXIO);
+ efd = fp->f_data;
+ if (fp->f_type != DTYPE_LINUXEFD || efd == NULL)
+ return (EINVAL);
+
+ switch (cmd)
+ {
+ case FIONBIO:
+ if (*(int *)data)
+ efd->efd_flags |= LINUX_O_NONBLOCK;
+ else
+ efd->efd_flags &= ~LINUX_O_NONBLOCK;
+ case FIOASYNC:
+ return (0);
+ default:
+ return (ENXIO);
+ }
}
/*ARGSUSED*/
diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c
index 396344b..a66ed80 100644
--- a/sys/compat/linux/linux_mib.c
+++ b/sys/compat/linux/linux_mib.c
@@ -168,9 +168,6 @@ linux_find_prison(struct prison *spr, struct prison **prp)
struct prison *pr;
struct linux_prison *lpr;
- if (!linux_osd_jail_slot)
- /* In case osd_register failed. */
- spr = &prison0;
for (pr = spr;; pr = pr->pr_parent) {
mtx_lock(&pr->pr_mtx);
lpr = (pr == &prison0)
@@ -189,15 +186,14 @@ linux_find_prison(struct prison *spr, struct prison **prp)
* Ensure a prison has its own Linux info. If lprp is non-null, point it to
* the Linux info and lock the prison.
*/
-static int
+static void
linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
{
struct prison *ppr;
struct linux_prison *lpr, *nlpr;
- int error;
+ void *rsv;
/* If this prison already has Linux info, return that. */
- error = 0;
lpr = linux_find_prison(pr, &ppr);
if (ppr == pr)
goto done;
@@ -207,29 +203,24 @@ linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
*/
mtx_unlock(&ppr->pr_mtx);
nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK);
+ rsv = osd_reserve(linux_osd_jail_slot);
lpr = linux_find_prison(pr, &ppr);
if (ppr == pr) {
free(nlpr, M_PRISON);
+ osd_free_reserved(rsv);
goto done;
}
/* Inherit the initial values from the ancestor. */
mtx_lock(&pr->pr_mtx);
- error = osd_jail_set(pr, linux_osd_jail_slot, nlpr);
- if (error == 0) {
- bcopy(lpr, nlpr, sizeof(*lpr));
- lpr = nlpr;
- } else {
- free(nlpr, M_PRISON);
- lpr = NULL;
- }
+ (void)osd_jail_set_reserved(pr, linux_osd_jail_slot, rsv, nlpr);
+ bcopy(lpr, nlpr, sizeof(*lpr));
+ lpr = nlpr;
mtx_unlock(&ppr->pr_mtx);
done:
if (lprp != NULL)
*lprp = lpr;
else
mtx_unlock(&pr->pr_mtx);
-
- return (error);
}
/*
@@ -249,7 +240,8 @@ linux_prison_create(void *obj, void *data)
* Inherit a prison's initial values from its parent
* (different from JAIL_SYS_INHERIT which also inherits changes).
*/
- return (linux_alloc_prison(pr, NULL));
+ linux_alloc_prison(pr, NULL);
+ return (0);
}
static int
@@ -345,11 +337,7 @@ linux_prison_set(void *obj, void *data)
* "linux=new" or "linux.*":
* the prison gets its own Linux info.
*/
- error = linux_alloc_prison(pr, &lpr);
- if (error) {
- mtx_unlock(&pr->pr_mtx);
- return (error);
- }
+ linux_alloc_prison(pr, &lpr);
if (osrelease) {
error = linux_map_osrel(osrelease, &lpr->pr_osrel);
if (error) {
@@ -449,21 +437,18 @@ linux_osd_jail_register(void)
linux_osd_jail_slot =
osd_jail_register(linux_prison_destructor, methods);
- if (linux_osd_jail_slot > 0) {
- /* Copy the system linux info to any current prisons. */
- sx_xlock(&allprison_lock);
- TAILQ_FOREACH(pr, &allprison, pr_list)
- (void)linux_alloc_prison(pr, NULL);
- sx_xunlock(&allprison_lock);
- }
+ /* Copy the system linux info to any current prisons. */
+ sx_slock(&allprison_lock);
+ TAILQ_FOREACH(pr, &allprison, pr_list)
+ linux_alloc_prison(pr, NULL);
+ sx_sunlock(&allprison_lock);
}
void
linux_osd_jail_deregister(void)
{
- if (linux_osd_jail_slot)
- osd_jail_deregister(linux_osd_jail_slot);
+ osd_jail_deregister(linux_osd_jail_slot);
}
void
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 7e9a0d5..98a842c 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -191,32 +191,33 @@ linux_alarm(struct thread *td, struct linux_alarm_args *args)
{
struct itimerval it, old_it;
u_int secs;
+ int error;
#ifdef DEBUG
if (ldebug(alarm))
printf(ARGS(alarm, "%u"), args->secs);
#endif
-
secs = args->secs;
-
- if (secs > INT_MAX)
- secs = INT_MAX;
-
- it.it_value.tv_sec = (long) secs;
- it.it_value.tv_usec = 0;
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 0;
/*
- * According to POSIX and Linux implementation
- * the alarm() system call is always successfull.
- * Ignore errors and return 0 as a Linux does.
+ * Linux alarm() is always successfull. Limit secs to INT32_MAX / 2
+ * to match kern_setitimer()'s limit to avoid error from it.
+ *
+ * XXX. Linux limit secs to INT_MAX on 32 and does not limit on 64-bit
+ * platforms.
*/
- kern_setitimer(td, ITIMER_REAL, &it, &old_it);
- if (timevalisset(&old_it.it_value)) {
- if (old_it.it_value.tv_usec != 0)
- old_it.it_value.tv_sec++;
- td->td_retval[0] = old_it.it_value.tv_sec;
- }
+ if (secs > INT32_MAX / 2)
+ secs = INT32_MAX / 2;
+
+ it.it_value.tv_sec = secs;
+ it.it_value.tv_usec = 0;
+ timevalclear(&it.it_interval);
+ error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
+ KASSERT(error == 0, ("kern_setitimer returns %d", error));
+
+ if ((old_it.it_value.tv_sec == 0 && old_it.it_value.tv_usec > 0) ||
+ old_it.it_value.tv_usec >= 500000)
+ old_it.it_value.tv_sec++;
+ td->td_retval[0] = old_it.it_value.tv_sec;
return (0);
}
@@ -894,13 +895,14 @@ linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
break;
}
timesp = times;
- }
- if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
/* This breaks POSIX, but is what the Linux kernel does
* _on purpose_ (documented in the man page for utimensat(2)),
* so we must follow that behaviour. */
- return (0);
+ if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ }
if (args->pathname != NULL)
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 01b007c..741a45b 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -448,7 +448,7 @@ linux_to_bsd_msg_flags(int flags)
if (flags & LINUX_MSG_ERRQUEUE)
;
#endif
- return ret_flags;
+ return (ret_flags);
}
/*
@@ -463,15 +463,12 @@ bsd_to_linux_sockaddr(struct sockaddr *arg)
struct sockaddr sa;
size_t sa_len = sizeof(struct sockaddr);
int error;
-
+
if ((error = copyin(arg, &sa, sa_len)))
return (error);
-
+
*(u_short *)&sa = sa.sa_family;
-
- error = copyout(&sa, arg, sa_len);
-
- return (error);
+ return (copyout(&sa, arg, sa_len));
}
static int
@@ -486,10 +483,7 @@ linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
sa.sa_family = *(sa_family_t *)&sa;
sa.sa_len = len;
-
- error = copyout(&sa, arg, sa_len);
-
- return (error);
+ return (copyout(&sa, arg, sa_len));
}
static int
@@ -511,11 +505,7 @@ linux_sa_put(struct osockaddr *osa)
return (EINVAL);
sa.sa_family = bdom;
- error = copyout(&sa, osa, sizeof(sa.sa_family));
- if (error)
- return (error);
-
- return (0);
+ return (copyout(&sa, osa, sizeof(sa.sa_family)));
}
static int
@@ -912,10 +902,7 @@ linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
if (error)
return (error);
- error = linux_sa_put(PTRIN(args->addr));
- if (error)
- return (error);
- return (0);
+ return (linux_sa_put(PTRIN(args->addr)));
}
int
@@ -935,10 +922,7 @@ linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
if (error)
return (error);
- error = linux_sa_put(PTRIN(args->addr));
- if (error)
- return (error);
- return (0);
+ return (linux_sa_put(PTRIN(args->addr)));
}
int
@@ -1003,7 +987,7 @@ linux_send(struct thread *td, struct linux_send_args *args)
bsd_args.flags = args->flags;
bsd_args.to = NULL;
bsd_args.tolen = 0;
- return sys_sendto(td, &bsd_args);
+ return (sys_sendto(td, &bsd_args));
}
struct linux_recv_args {
@@ -1040,7 +1024,6 @@ linux_sendto(struct thread *td, struct linux_sendto_args *args)
{
struct msghdr msg;
struct iovec aiov;
- int error;
if (linux_check_hdrincl(td, args->s) == 0)
/* IP_HDRINCL set, tweak the packet before sending */
@@ -1054,9 +1037,8 @@ linux_sendto(struct thread *td, struct linux_sendto_args *args)
msg.msg_flags = 0;
aiov.iov_base = PTRIN(args->msg);
aiov.iov_len = args->len;
- error = linux_sendit(td, args->s, &msg, args->flags, NULL,
- UIO_USERSPACE);
- return (error);
+ return (linux_sendit(td, args->s, &msg, args->flags, NULL,
+ UIO_USERSPACE));
}
int
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index 84ade7b..3638c6b 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -257,7 +257,7 @@ static int
stat_copyout(struct stat *buf, void *ubuf)
{
struct l_stat lbuf;
-
+
bzero(&lbuf, sizeof(lbuf));
lbuf.st_dev = buf->st_dev;
lbuf.st_ino = buf->st_ino;
@@ -303,7 +303,7 @@ linux_stat(struct thread *td, struct linux_stat_args *args)
return (error);
}
LFREEPATH(path);
- return(stat_copyout(&buf, args->up));
+ return (stat_copyout(&buf, args->up));
}
int
@@ -325,7 +325,7 @@ linux_lstat(struct thread *td, struct linux_lstat_args *args)
return (error);
}
LFREEPATH(path);
- return(stat_copyout(&buf, args->up));
+ return (stat_copyout(&buf, args->up));
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -381,10 +381,22 @@ bsd_to_linux_ftype(const char *fstypename)
return (0L);
}
-static void
+static int
bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
{
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ uint64_t tmp;
+#define LINUX_HIBITS 0xffffffff00000000ULL
+
+ tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
+ bsd_statfs->f_bsize;
+ if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
+ (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
+ (tmp & LINUX_HIBITS))
+ return (EOVERFLOW);
+#undef LINUX_HIBITS
+#endif
linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
linux_statfs->f_bsize = bsd_statfs->f_bsize;
linux_statfs->f_blocks = bsd_statfs->f_blocks;
@@ -395,6 +407,8 @@ bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
linux_statfs->f_namelen = MAXNAMLEN;
+
+ return (0);
}
int
@@ -415,8 +429,10 @@ linux_statfs(struct thread *td, struct linux_statfs_args *args)
LFREEPATH(path);
if (error)
return (error);
- bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
- return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+ error = bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
+ if (error)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
@@ -458,7 +474,28 @@ linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
if (error)
return (error);
bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs);
- return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
+}
+
+int
+linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
+{
+ struct l_statfs64 linux_statfs;
+ struct statfs bsd_statfs;
+ int error;
+
+#ifdef DEBUG
+ if (ldebug(fstatfs64))
+ printf(ARGS(fstatfs64, "%d, *"), args->fd);
+#endif
+ if (args->bufsize != sizeof(struct l_statfs64))
+ return (EINVAL);
+
+ error = kern_fstatfs(td, args->fd, &bsd_statfs);
+ if (error)
+ return error;
+ bsd_to_linux_statfs64(&bsd_statfs, &linux_statfs);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -475,9 +512,11 @@ linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
#endif
error = kern_fstatfs(td, args->fd, &bsd_statfs);
if (error)
- return error;
- bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
- return copyout(&linux_statfs, args->buf, sizeof(linux_statfs));
+ return (error);
+ error = bsd_to_linux_statfs(&bsd_statfs, &linux_statfs);
+ if (error)
+ return (error);
+ return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
}
struct l_ustat
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
index 0dcdfe0..b12050a 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitops.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -147,11 +147,11 @@ find_last_bit(unsigned long *addr, unsigned long size)
if (mask)
return (bit + __flsl(mask));
}
- while (--pos) {
+ while (pos--) {
addr--;
bit -= BITS_PER_LONG;
if (*addr)
- return (bit + __flsl(mask));
+ return (bit + __flsl(*addr));
}
return (size);
}
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
index f7bc529..33629ec 100644
--- a/sys/compat/linuxkpi/common/include/linux/jiffies.h
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -95,4 +95,14 @@ get_jiffies_64(void)
return ((u64)(unsigned)ticks);
}
+static inline int
+linux_timer_jiffies_until(unsigned long expires)
+{
+ int delta = expires - jiffies;
+ /* guard against already expired values */
+ if (delta < 1)
+ delta = 1;
+ return (delta);
+}
+
#endif /* _LINUX_JIFFIES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h
index 63e8af5..1357555 100644
--- a/sys/compat/linuxkpi/common/include/linux/list.h
+++ b/sys/compat/linuxkpi/common/include/linux/list.h
@@ -61,6 +61,7 @@
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
+#include <netinet/tcp_lro.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index c62f735..8afea08 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -34,6 +34,7 @@
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/list.h>
+#include <linux/jiffies.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -113,6 +114,52 @@ do { \
-_error; \
})
+#define wait_event_interruptible_timeout(q, cond, timeout) \
+({ \
+ void *c = &(q).wchan; \
+ long end = jiffies + timeout; \
+ int __ret = 0; \
+ int __rc = 0; \
+ \
+ if (!(cond)) { \
+ for (; __rc == 0;) { \
+ sleepq_lock(c); \
+ if (cond) { \
+ sleepq_release(c); \
+ __ret = 1; \
+ break; \
+ } \
+ sleepq_add(c, NULL, "completion", \
+ SLEEPQ_SLEEP | SLEEPQ_INTERRUPTIBLE, 0); \
+ sleepq_set_timeout(c, linux_timer_jiffies_until(end));\
+ __rc = sleepq_timedwait_sig (c, 0); \
+ if (__rc != 0) { \
+ /* check for timeout or signal. \
+ * 0 if the condition evaluated to false\
+ * after the timeout elapsed, 1 if the \
+ * condition evaluated to true after the\
+ * timeout elapsed. \
+ */ \
+ if (__rc == EWOULDBLOCK) \
+ __ret = (cond); \
+ else \
+ __ret = -ERESTARTSYS; \
+ } \
+ \
+ } \
+ } else { \
+ /* return remaining jiffies (at least 1) if the \
+ * condition evaluated to true before the timeout \
+ * elapsed. \
+ */ \
+ __ret = (end - jiffies); \
+ if( __ret < 1 ) \
+ __ret = 1; \
+ } \
+ __ret; \
+})
+
+
static inline int
waitqueue_active(wait_queue_head_t *q)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index b8a0801..d85d4ad 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -894,16 +894,6 @@ kasprintf(gfp_t gfp, const char *fmt, ...)
return (p);
}
-static int
-linux_timer_jiffies_until(unsigned long expires)
-{
- int delta = expires - jiffies;
- /* guard against already expired values */
- if (delta < 1)
- delta = 1;
- return (delta);
-}
-
static void
linux_timer_callback_wrapper(void *context)
{
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 2ad1683..90e79b0 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -348,13 +348,13 @@ ndis_create_sysctls(arg)
ndis_add_sysctl(sc, "BusType", "Bus Type", buf, NDIS_FLAG_RDONLY);
if (sc->ndis_res_io != NULL) {
- sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
+ sprintf(buf, "0x%jx", rman_get_start(sc->ndis_res_io));
ndis_add_sysctl(sc, "IOBaseAddress",
"Base I/O Address", buf, NDIS_FLAG_RDONLY);
}
if (sc->ndis_irq != NULL) {
- sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
+ sprintf(buf, "%ju", rman_get_start(sc->ndis_irq));
ndis_add_sysctl(sc, "InterruptNumber",
"Interrupt Number", buf, NDIS_FLAG_RDONLY);
}
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 5a8014c..c9fce2e 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2792,9 +2792,6 @@ device urndis
# Realtek RTL8187B/L wireless driver
device urtw
#
-# Realtek RTL8188CU/RTL8192CU wireless driver
-device urtwn
-#
# ZyDas ZD1211/ZD1211B wireless driver
device zyd
#
diff --git a/sys/conf/files b/sys/conf/files
index 47b68b9..e2dbc67 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1413,12 +1413,20 @@ dev/exca/exca.c optional cbb
dev/extres/clk/clk.c optional ext_resources clk
dev/extres/clk/clkdev_if.m optional ext_resources clk
dev/extres/clk/clknode_if.m optional ext_resources clk
+dev/extres/clk/clk_bus.c optional ext_resources clk fdt
dev/extres/clk/clk_div.c optional ext_resources clk
dev/extres/clk/clk_fixed.c optional ext_resources clk
dev/extres/clk/clk_gate.c optional ext_resources clk
dev/extres/clk/clk_mux.c optional ext_resources clk
+dev/extres/phy/phy.c optional ext_resources phy
+dev/extres/phy/phy_if.m optional ext_resources phy
dev/extres/hwreset/hwreset.c optional ext_resources hwreset
dev/extres/hwreset/hwreset_if.m optional ext_resources hwreset
+dev/extres/regulator/regdev_if.m optional ext_resources regulator
+dev/extres/regulator/regnode_if.m optional ext_resources regulator
+dev/extres/regulator/regulator.c optional ext_resources regulator
+dev/extres/regulator/regulator_bus.c optional ext_resources regulator fdt
+dev/extres/regulator/regulator_fixed.c optional ext_resources regulator
dev/fatm/if_fatm.c optional fatm pci
dev/fb/fbd.c optional fbd | vt
dev/fb/fb_if.m standard
@@ -1560,10 +1568,10 @@ ipw_monitor.fw optional ipwmonitorfw | ipwfw \
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "ipw_monitor.fw"
-dev/iscsi/icl.c optional iscsi | ctl
-dev/iscsi/icl_conn_if.m optional iscsi | ctl
+dev/iscsi/icl.c optional iscsi | ctl
+dev/iscsi/icl_conn_if.m optional iscsi | ctl
dev/iscsi/icl_proxy.c optional iscsi | ctl
-dev/iscsi/icl_soft.c optional iscsi | ctl
+dev/iscsi/icl_soft.c optional iscsi | ctl
dev/iscsi/iscsi.c optional iscsi scbus
dev/iscsi_initiator/iscsi.c optional iscsi_initiator scbus
dev/iscsi_initiator/iscsi_subr.c optional iscsi_initiator scbus
@@ -2547,11 +2555,12 @@ dev/uart/uart_bus_puc.c optional uart puc
dev/uart/uart_bus_scc.c optional uart scc
dev/uart/uart_core.c optional uart
dev/uart/uart_dbg.c optional uart gdb
-dev/uart/uart_dev_ns8250.c optional uart uart_ns8250
+dev/uart/uart_dev_ns8250.c optional uart uart_ns8250 | uart uart_snps
dev/uart/uart_dev_pl011.c optional uart pl011
dev/uart/uart_dev_quicc.c optional uart quicc
dev/uart/uart_dev_sab82532.c optional uart uart_sab82532
dev/uart/uart_dev_sab82532.c optional uart scc
+dev/uart/uart_dev_snps.c optional uart uart_snps
dev/uart/uart_dev_z8530.c optional uart uart_z8530
dev/uart/uart_dev_z8530.c optional uart scc
dev/uart/uart_if.m optional uart
@@ -2670,50 +2679,6 @@ dev/usb/wlan/if_uath.c optional uath
dev/usb/wlan/if_upgt.c optional upgt
dev/usb/wlan/if_ural.c optional ural
dev/usb/wlan/if_urtw.c optional urtw
-dev/usb/wlan/if_urtwn.c optional urtwn
-urtwn-rtl8188eufw.c optional urtwn-rtl8188eufw | urtwnfw \
- compile-with "${AWK} -f $S/tools/fw_stub.awk urtwn-rtl8188eufw.fw:urtwn-rtl8188eufw:111 -murtwn-rtl8188eufw -c${.TARGET}" \
- no-implicit-rule before-depend local \
- clean "urtwn-rtl8188eufw.c"
-urtwn-rtl8188eufw.fwo optional urtwn-rtl8188eufw | urtwnfw \
- dependency "urtwn-rtl8188eufw.fw" \
- compile-with "${NORMAL_FWO}" \
- no-implicit-rule \
- clean "urtwn-rtl8188eufw.fwo"
-urtwn-rtl8188eufw.fw optional urtwn-rtl8188eufw | urtwnfw \
- dependency "$S/contrib/dev/urtwn/urtwn-rtl8188eufw.fw.uu" \
- compile-with "${NORMAL_FW}" \
- no-obj no-implicit-rule \
- clean "urtwn-rtl8188eufw.fw"
-urtwn-rtl8192cfwT.c optional urtwn-rtl8192cfwT | urtwnfw \
- compile-with "${AWK} -f $S/tools/fw_stub.awk urtwn-rtl8192cfwT.fw:urtwn-rtl8192cfwT:111 -murtwn-rtl8192cfwT -c${.TARGET}" \
- no-implicit-rule before-depend local \
- clean "urtwn-rtl8192cfwT.c"
-urtwn-rtl8192cfwT.fwo optional urtwn-rtl8192cfwT | urtwnfw \
- dependency "urtwn-rtl8192cfwT.fw" \
- compile-with "${NORMAL_FWO}" \
- no-implicit-rule \
- clean "urtwn-rtl8192cfwT.fwo"
-urtwn-rtl8192cfwT.fw optional urtwn-rtl8192cfwT | urtwnfw \
- dependency "$S/contrib/dev/urtwn/urtwn-rtl8192cfwT.fw.uu" \
- compile-with "${NORMAL_FW}" \
- no-obj no-implicit-rule \
- clean "urtwn-rtl8192cfwT.fw"
-urtwn-rtl8192cfwU.c optional urtwn-rtl8192cfwU | urtwnfw \
- compile-with "${AWK} -f $S/tools/fw_stub.awk urtwn-rtl8192cfwU.fw:urtwn-rtl8192cfwU:111 -murtwn-rtl8192cfwU -c${.TARGET}" \
- no-implicit-rule before-depend local \
- clean "urtwn-rtl8192cfwU.c"
-urtwn-rtl8192cfwU.fwo optional urtwn-rtl8192cfwU | urtwnfw \
- dependency "urtwn-rtl8192cfwU.fw" \
- compile-with "${NORMAL_FWO}" \
- no-implicit-rule \
- clean "urtwn-rtl8192cfwU.fwo"
-urtwn-rtl8192cfwU.fw optional urtwn-rtl8192cfwU | urtwnfw \
- dependency "$S/contrib/dev/urtwn/urtwn-rtl8192cfwU.fw.uu" \
- compile-with "${NORMAL_FW}" \
- no-obj no-implicit-rule \
- clean "urtwn-rtl8192cfwU.fw"
-
dev/usb/wlan/if_zyd.c optional zyd
#
# USB serial and parallel port drivers
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 97f2e37..85366fa 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -50,12 +50,12 @@ font.h optional sc_dflt_font \
clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8"
#
atkbdmap.h optional atkbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -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" \
+ 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 "/usr/sbin/kbdcontrol -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" \
+ 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"
#
@@ -104,7 +104,6 @@ acpi_wakedata.h optional acpi \
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
@@ -596,6 +595,7 @@ 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/autoconf.c standard
x86/x86/bus_machdep.c standard
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
diff --git a/sys/conf/files.arm b/sys/conf/files.arm
index 2407616..a9da11c 100644
--- a/sys/conf/files.arm
+++ b/sys/conf/files.arm
@@ -103,6 +103,8 @@ dev/hwpmc/hwpmc_arm.c optional hwpmc
dev/hwpmc/hwpmc_armv7.c optional hwpmc armv6
dev/iicbus/twsi/twsi.c optional twsi
dev/ofw/ofw_cpu.c optional fdt
+dev/ofw/ofwpci.c optional fdt pci
+dev/pci/pci_host_generic.c optional pci_host_generic pci fdt
dev/psci/psci.c optional psci
dev/psci/psci_arm.S optional psci
dev/syscons/scgfbrndr.c optional sc
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 8f5f10a..7bbe458 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -12,6 +12,7 @@ arm64/arm64/bus_machdep.c standard
arm64/arm64/bus_space_asm.S standard
arm64/arm64/busdma_bounce.c standard
arm64/arm64/busdma_machdep.c standard
+arm64/arm64/bzero.S standard
arm64/arm64/clock.c standard
arm64/arm64/copyinout.S standard
arm64/arm64/copystr.c standard
@@ -66,6 +67,7 @@ dev/hwpmc/hwpmc_arm64_md.c optional hwpmc
dev/mmc/host/dwmmc.c optional dwmmc
dev/mmc/host/dwmmc_hisi.c optional dwmmc soc_hisi_hi6220
dev/ofw/ofw_cpu.c optional fdt
+dev/ofw/ofwpci.c optional fdt pci
dev/pci/pci_host_generic.c optional pci fdt
dev/psci/psci.c optional psci
dev/psci/psci_arm64.S optional psci
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index b065165..4b6f158 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -49,12 +49,12 @@ font.h optional sc_dflt_font \
clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8"
#
atkbdmap.h optional atkbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -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" \
+ 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 "/usr/sbin/kbdcontrol -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" \
+ 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"
#
@@ -285,6 +285,7 @@ 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/ofw/ofwpci.c optional fdt pci
dev/pcf/pcf_isa.c optional pcf
dev/random/ivy.c optional rdrand_rng
dev/random/nehemiah.c optional padlock_rng
@@ -451,7 +452,6 @@ i386/bios/smapi_bios.S optional smapi
#i386/i386/apic_vector.s optional apic
i386/i386/atomic.c standard \
compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}"
-i386/i386/autoconf.c standard
i386/i386/bios.c standard
i386/i386/bioscall.s standard
i386/i386/bpf_jit_machdep.c optional bpf_jitter
@@ -590,6 +590,7 @@ 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/autoconf.c standard
x86/x86/bus_machdep.c standard
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
diff --git a/sys/conf/files.mips b/sys/conf/files.mips
index 91d53aa..4cacac4 100644
--- a/sys/conf/files.mips
+++ b/sys/conf/files.mips
@@ -92,3 +92,6 @@ dev/nvram2env/nvram2env.c optional nvram2env
dev/hwpmc/hwpmc_mips.c optional hwpmc
dev/hwpmc/hwpmc_mips24k.c optional hwpmc_mips24k
dev/hwpmc/hwpmc_mips74k.c optional hwpmc_mips74k
+
+# ofw support
+dev/ofw/ofwpci.c optional fdt pci
diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98
index 75269b4..9f0ef00 100644
--- a/sys/conf/files.pc98
+++ b/sys/conf/files.pc98
@@ -46,7 +46,7 @@ svr4_assym.h optional compat_svr4 \
clean "svr4_assym.h"
#
ukbdmap.h optional ukbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -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" \
+ 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"
#
@@ -147,7 +147,6 @@ i386/bios/apm.c optional apm
#i386/i386/apic_vector.s optional apic
i386/i386/atomic.c standard \
compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}"
-i386/i386/autoconf.c standard
i386/i386/bios.c standard
i386/i386/bioscall.s standard
i386/i386/bpf_jit_machdep.c optional bpf_jitter
@@ -258,6 +257,7 @@ x86/isa/atpic.c optional atpic
x86/isa/clock.c standard
x86/isa/isa.c optional isa
x86/pci/pci_bus.c optional pci
+x86/x86/autoconf.c standard
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
x86/x86/cpu_machdep.c standard
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 0a1e7c1..d2e8e3b 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -57,6 +57,7 @@ dev/ofw/ofw_console.c optional aim
dev/ofw/ofw_disk.c optional ofwd aim
dev/ofw/ofw_iicbus.c optional iicbus aim
dev/ofw/ofwbus.c optional aim | fdt
+dev/ofw/ofwpci.c optional pci
dev/ofw/ofw_standard.c optional aim powerpc
dev/ofw/ofw_subr.c optional aim powerpc
dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac
@@ -145,7 +146,6 @@ powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx | pci qoriq_dpaa
powerpc/mpc85xx/pci_mpc85xx_pcib.c optional pci mpc85xx | pci qoriq_dpaa
powerpc/mpc85xx/qoriq_gpio.c optional mpc85xx gpio | qoriq_dpaa gpio
powerpc/ofw/ofw_machdep.c standard
-powerpc/ofw/ofw_pci.c optional pci
powerpc/ofw/ofw_pcibus.c optional pci
powerpc/ofw/ofw_pcib_pci.c optional pci
powerpc/ofw/ofw_real.c optional aim
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64
index 84f23ff..a9643bd 100644
--- a/sys/conf/files.sparc64
+++ b/sys/conf/files.sparc64
@@ -8,17 +8,17 @@
# dependency lines other than the first are silently ignored.
#
atkbdmap.h optional atkbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -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" \
+ 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"
#
sunkbdmap.h optional sunkbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -L ${SUNKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > sunkbdmap.h" \
+ compile-with "kbdcontrol -P ${S:S/sys$/share/}/vt/keymaps -P ${S:S/sys$/share/}/syscons/keymaps -L ${SUNKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > sunkbdmap.h" \
no-obj no-implicit-rule before-depend \
clean "sunkbdmap.h"
#
ukbdmap.h optional ukbd_dflt_keymap \
- compile-with "/usr/sbin/kbdcontrol -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" \
+ 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"
#
diff --git a/sys/conf/kern.opts.mk b/sys/conf/kern.opts.mk
index d1d2d04..ad6ee72 100644
--- a/sys/conf/kern.opts.mk
+++ b/sys/conf/kern.opts.mk
@@ -30,7 +30,6 @@ __DEFAULT_YES_OPTIONS = \
CDDL \
CRYPT \
CUSE \
- FAST_DEPEND \
FORMAT_EXTENSIONS \
INET \
INET6 \
@@ -49,12 +48,6 @@ __DEFAULT_NO_OPTIONS = \
NAND \
OFED
-# Enable FAST_DEPEND by default for the meta build.
-.if !empty(.MAKE.MODE:Unormal:Mmeta)
-__DEFAULT_YES_OPTIONS+= FAST_DEPEND
-__DEFAULT_NO_OPTIONS:= ${__DEFAULT_NO_OPTIONS:NFAST_DEPEND}
-.endif
-
# Some options are totally broken on some architectures. We disable
# them. If you need to enable them on an experimental basis, you
# must change this code.
@@ -65,9 +58,8 @@ __DEFAULT_NO_OPTIONS:= ${__DEFAULT_NO_OPTIONS:NFAST_DEPEND}
# Things that don't work based on the CPU
.if ${MACHINE_CPUARCH} == "arm"
-BROKEN_OPTIONS+= ZFS
. if ${MACHINE_ARCH:Marmv6*} == ""
-BROKEN_OPTIONS+= CDDL
+BROKEN_OPTIONS+= CDDL ZFS
. endif
.endif
diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk
index d5047a8..d28e87b 100644
--- a/sys/conf/kern.post.mk
+++ b/sys/conf/kern.post.mk
@@ -145,10 +145,6 @@ ${FULLKERNEL}: ${SYSTEM_DEP} vers.o
OBJS_DEPEND_GUESS+= assym.s vnode_if.h ${BEFORE_DEPEND:M*.h} \
${MFILES:T:S/.m$/.h/}
-.if ${MK_FAST_DEPEND} == "no" && !exists(${.OBJDIR}/.depend)
-${SYSTEM_OBJS}: ${OBJS_DEPEND_GUESS}
-.endif
-
LNFILES= ${CFILES:T:S/.c$/.ln/}
.for mfile in ${MFILES}
@@ -189,23 +185,6 @@ genassym.o: $S/$M/$M/genassym.c
${SYSTEM_OBJS} genassym.o vers.o: opt_global.h
-# Normal files first
-CFILES_NORMAL= ${CFILES:N*/cddl/*:N*fs/nfsclient/nfs_clkdtrace*:N*/compat/linuxkpi/common/*:N*/ofed/*:N*/dev/mlx5/*}
-SFILES_NORMAL= ${SFILES:N*/cddl/*}
-
-# We have "special" -I include paths for zfs/dtrace files in 'depend'.
-CFILES_CDDL= ${CFILES:M*/cddl/*}
-SFILES_CDDL= ${SFILES:M*/cddl/*}
-
-# We have "special" -I include paths for LinuxKPI.
-CFILES_LINUXKPI=${CFILES:M*/compat/linuxkpi/common/*}
-
-# We have "special" -I include paths for OFED.
-CFILES_OFED=${CFILES:M*/ofed/*}
-
-# We have "special" -I include paths for MLX5.
-CFILES_MLX5=${CFILES:M*/dev/mlx5/*}
-
# Skip reading .depend when not needed to speed up tree-walks
# and simple lookups.
.if !empty(.MAKEFLAGS:M-V${_V_READ_DEPEND}) || make(obj) || make(clean*) || \
@@ -216,9 +195,6 @@ _SKIP_READ_DEPEND= 1
.endif
kernel-depend: .depend
-# The argument list can be very long, so use make -V and xargs to
-# pass it to mkdep.
-_MKDEPCC:= ${CC:N${CCACHE_BIN}}
SRCS= assym.s vnode_if.h ${BEFORE_DEPEND} ${CFILES} \
${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \
${MFILES:T:S/.m$/.h/}
@@ -228,7 +204,6 @@ DEPENDFILES= .depend .depend.*
.if !empty(.MAKE.MODE:Unormal:Mmeta) && empty(.MAKE.MODE:Unormal:Mnofilemon)
_meta_filemon= 1
.endif
-.if ${MK_FAST_DEPEND} == "yes"
DEPENDOBJS+= ${SYSTEM_OBJS} genassym.o
DEPENDFILES_OBJS= ${DEPENDOBJS:O:u:C/^/.depend./}
.if ${MAKE_VERSION} < 20160220
@@ -261,12 +236,10 @@ CFLAGS+= ${DEPEND_CFLAGS}
# all dependencies are correctly added or accounted for. This is mostly to
# ensure downstream uses of kernel-depend are handled.
beforebuild: kernel-depend
-.endif # ${MK_FAST_DEPEND} == "yes"
# Guess some dependencies for when no ${DEPENDFILE}.OBJ is generated yet.
# For meta+filemon the .meta file is checked for since it is the dependency
# file used.
-.if ${MK_FAST_DEPEND} == "yes"
.for __obj in ${DEPENDOBJS:O:u}
.if (defined(_meta_filemon) && !exists(${.OBJDIR}/${__obj}.meta)) || \
(!defined(_meta_filemon) && !exists(${.OBJDIR}/.depend.${__obj}))
@@ -276,32 +249,10 @@ ${__obj}: ${OBJS_DEPEND_GUESS}
${__obj}: ${OBJS_DEPEND_GUESS.${__obj}}
.endif
.endfor
-.endif
.NOPATH: .depend ${DEPENDFILES_OBJS}
.depend: .PRECIOUS ${SRCS}
-.if ${MK_FAST_DEPEND} == "no"
- rm -f ${.TARGET}.tmp
-# C files
- ${MAKE} -V CFILES_NORMAL -V SYSTEM_CFILES -V GEN_CFILES | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp ${CFLAGS}
- ${MAKE} -V CFILES_CDDL | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp ${ZFS_CFLAGS} \
- ${FBT_CFLAGS} ${DTRACE_CFLAGS}
- ${MAKE} -V CFILES_LINUXKPI | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp \
- ${CFLAGS} ${LINUXKPI_INCLUDES}
- ${MAKE} -V CFILES_OFED -V CFILES_MLX5 | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp \
- ${CFLAGS} ${OFEDINCLUDES}
-# Assembly files
- ${MAKE} -V SFILES_NORMAL | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp ${ASM_CFLAGS}
- ${MAKE} -V SFILES_CDDL | \
- CC="${_MKDEPCC}" xargs mkdep -a -f ${.TARGET}.tmp ${ZFS_ASM_CFLAGS}
- mv ${.TARGET}.tmp ${.TARGET}
-.endif
_ILINKS= machine
.if ${MACHINE} != ${MACHINE_CPUARCH} && ${MACHINE} != "arm64"
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index cf6ec10..591c988 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -64,29 +64,6 @@ NOSTDINC= -nostdinc
INCLUDES= ${NOSTDINC} ${INCLMAGIC} -I. -I$S
-.if ${MK_FAST_DEPEND} == "no" && (make(depend) || make(kernel-depend))
-
-# This hack lets us use the ipfilter code without spamming a new
-# include path into contrib'ed source files.
-INCLUDES+= -I$S/contrib/ipfilter
-
-# ... and the same for ath
-INCLUDES+= -I$S/dev/ath -I$S/dev/ath/ath_hal -I$S/contrib/dev/ath/ath_hal
-
-# ... and the same for the NgATM stuff
-INCLUDES+= -I$S/contrib/ngatm
-
-# ... and the same for vchiq
-INCLUDES+= -I$S/contrib/vchiq
-
-# ... and the same for twa
-INCLUDES+= -I$S/dev/twa
-
-# ... and the same for cxgb and cxgbe
-INCLUDES+= -I$S/dev/cxgb -I$S/dev/cxgbe
-
-.endif
-
CFLAGS= ${COPTFLAGS} ${DEBUG}
CFLAGS+= ${INCLUDES} -D_KERNEL -DHAVE_KERNEL_OPTION_HEADERS -include opt_global.h
CFLAGS_PARAM_INLINE_UNIT_GROWTH?=100
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
index 6a3e1eb..9e6b06c 100644
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -458,11 +458,6 @@ cleanilinks:
OBJS_DEPEND_GUESS+= ${SRCS:M*.h}
.include <bsd.dep.mk>
-
-.if ${MK_FAST_DEPEND} == "no" && !exists(${.OBJDIR}/${DEPENDFILE})
-${OBJS}: ${OBJS_DEPEND_GUESS}
-.endif
-
.include <bsd.clang-analyze.mk>
.include <bsd.obj.mk>
.include "kern.mk"
diff --git a/sys/contrib/cloudabi/cloudabi64_types.h b/sys/contrib/cloudabi/cloudabi64_types.h
new file mode 100644
index 0000000..88babaa
--- /dev/null
+++ b/sys/contrib/cloudabi/cloudabi64_types.h
@@ -0,0 +1,225 @@
+// Copyright (c) 2016 Nuxi (https://nuxi.nl/) and contributors.
+//
+// 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 AUTHOR 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 AUTHOR 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.
+//
+// This file is automatically generated. Do not edit.
+//
+// Source: https://github.com/NuxiNL/cloudabi
+
+#ifndef CLOUDABI64_TYPES_H
+#define CLOUDABI64_TYPES_H
+
+#include "cloudabi_types_common.h"
+
+typedef struct {
+ _Alignas(4) cloudabi_auxtype_t a_type;
+ union {
+ _Alignas(8) uint64_t a_val;
+ _Alignas(8) uint64_t a_ptr;
+ };
+} cloudabi64_auxv_t;
+_Static_assert(offsetof(cloudabi64_auxv_t, a_type) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_auxv_t, a_val) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_auxv_t, a_ptr) == 8, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_auxv_t) == 16, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_auxv_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) uint64_t iov_base;
+ _Alignas(8) uint64_t iov_len;
+} cloudabi64_ciovec_t;
+_Static_assert(offsetof(cloudabi64_ciovec_t, iov_base) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_ciovec_t, iov_len) == 8, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_ciovec_t) == 16, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_ciovec_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) cloudabi_userdata_t userdata;
+ _Alignas(2) cloudabi_errno_t error;
+ _Alignas(1) cloudabi_eventtype_t type;
+ union {
+ struct {
+ _Alignas(8) cloudabi_userdata_t identifier;
+ } clock;
+ struct {
+ _Alignas(8) uint64_t condvar;
+ } condvar;
+ struct {
+ _Alignas(8) cloudabi_filesize_t nbytes;
+ _Alignas(4) cloudabi_fd_t fd;
+ _Alignas(2) cloudabi_eventrwflags_t flags;
+ } fd_readwrite;
+ struct {
+ _Alignas(8) uint64_t lock;
+ } lock;
+ struct {
+ _Alignas(4) cloudabi_fd_t fd;
+ _Alignas(1) cloudabi_signal_t signal;
+ _Alignas(4) cloudabi_exitcode_t exitcode;
+ } proc_terminate;
+ };
+} cloudabi64_event_t;
+_Static_assert(offsetof(cloudabi64_event_t, userdata) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, error) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, type) == 10, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, clock.identifier) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, condvar.condvar) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, fd_readwrite.nbytes) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, fd_readwrite.fd) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, fd_readwrite.flags) == 28, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, lock.lock) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, proc_terminate.fd) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, proc_terminate.signal) == 20, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_event_t, proc_terminate.exitcode) == 24, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_event_t) == 32, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_event_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) uint64_t iov_base;
+ _Alignas(8) uint64_t iov_len;
+} cloudabi64_iovec_t;
+_Static_assert(offsetof(cloudabi64_iovec_t, iov_base) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_iovec_t, iov_len) == 8, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_iovec_t) == 16, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_iovec_t) == 8, "Incorrect layout");
+
+typedef void cloudabi64_processentry_t(uint64_t auxv);
+
+typedef struct {
+ _Alignas(8) uint64_t ri_data;
+ _Alignas(8) uint64_t ri_datalen;
+ _Alignas(8) uint64_t ri_fds;
+ _Alignas(8) uint64_t ri_fdslen;
+ _Alignas(2) cloudabi_msgflags_t ri_flags;
+} cloudabi64_recv_in_t;
+_Static_assert(offsetof(cloudabi64_recv_in_t, ri_data) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_in_t, ri_datalen) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_in_t, ri_fds) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_in_t, ri_fdslen) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_in_t, ri_flags) == 32, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_recv_in_t) == 40, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_recv_in_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) uint64_t si_data;
+ _Alignas(8) uint64_t si_datalen;
+ _Alignas(8) uint64_t si_fds;
+ _Alignas(8) uint64_t si_fdslen;
+ _Alignas(2) cloudabi_msgflags_t si_flags;
+} cloudabi64_send_in_t;
+_Static_assert(offsetof(cloudabi64_send_in_t, si_data) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_send_in_t, si_datalen) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_send_in_t, si_fds) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_send_in_t, si_fdslen) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_send_in_t, si_flags) == 32, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_send_in_t) == 40, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_send_in_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) uint64_t so_datalen;
+} cloudabi64_send_out_t;
+_Static_assert(offsetof(cloudabi64_send_out_t, so_datalen) == 0, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_send_out_t) == 8, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_send_out_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) cloudabi_userdata_t userdata;
+ _Alignas(2) cloudabi_subflags_t flags;
+ _Alignas(1) cloudabi_eventtype_t type;
+ union {
+ struct {
+ _Alignas(8) cloudabi_userdata_t identifier;
+ _Alignas(4) cloudabi_clockid_t clock_id;
+ _Alignas(8) cloudabi_timestamp_t timeout;
+ _Alignas(8) cloudabi_timestamp_t precision;
+ _Alignas(2) cloudabi_subclockflags_t flags;
+ } clock;
+ struct {
+ _Alignas(8) uint64_t condvar;
+ _Alignas(8) uint64_t lock;
+ _Alignas(1) cloudabi_scope_t condvar_scope;
+ _Alignas(1) cloudabi_scope_t lock_scope;
+ } condvar;
+ struct {
+ _Alignas(4) cloudabi_fd_t fd;
+ _Alignas(2) cloudabi_subrwflags_t flags;
+ } fd_readwrite;
+ struct {
+ _Alignas(8) uint64_t lock;
+ _Alignas(1) cloudabi_scope_t lock_scope;
+ } lock;
+ struct {
+ _Alignas(4) cloudabi_fd_t fd;
+ } proc_terminate;
+ };
+} cloudabi64_subscription_t;
+_Static_assert(offsetof(cloudabi64_subscription_t, userdata) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, flags) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, type) == 10, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, clock.identifier) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, clock.clock_id) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, clock.timeout) == 32, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, clock.precision) == 40, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, clock.flags) == 48, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, condvar.condvar) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, condvar.lock) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, condvar.condvar_scope) == 32, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, condvar.lock_scope) == 33, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, fd_readwrite.fd) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, fd_readwrite.flags) == 20, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, lock.lock) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, lock.lock_scope) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_subscription_t, proc_terminate.fd) == 16, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_subscription_t) == 56, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_subscription_t) == 8, "Incorrect layout");
+
+typedef void cloudabi64_threadentry_t(cloudabi_tid_t tid, uint64_t aux);
+
+typedef struct {
+ _Alignas(8) uint64_t ro_datalen;
+ _Alignas(8) uint64_t ro_fdslen;
+ _Alignas(2) cloudabi_sockaddr_t ro_sockname;
+ _Alignas(2) cloudabi_sockaddr_t ro_peername;
+ _Alignas(2) cloudabi_msgflags_t ro_flags;
+} cloudabi64_recv_out_t;
+_Static_assert(offsetof(cloudabi64_recv_out_t, ro_datalen) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_out_t, ro_fdslen) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_out_t, ro_sockname) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_out_t, ro_peername) == 36, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_recv_out_t, ro_flags) == 56, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_recv_out_t) == 64, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_recv_out_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) uint64_t entry_point;
+ _Alignas(8) uint64_t stack;
+ _Alignas(8) uint64_t stack_size;
+ _Alignas(8) uint64_t argument;
+} cloudabi64_threadattr_t;
+_Static_assert(offsetof(cloudabi64_threadattr_t, entry_point) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_threadattr_t, stack) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_threadattr_t, stack_size) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi64_threadattr_t, argument) == 24, "Incorrect layout");
+_Static_assert(sizeof(cloudabi64_threadattr_t) == 32, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi64_threadattr_t) == 8, "Incorrect layout");
+
+#endif
diff --git a/sys/contrib/cloudabi/cloudabi_types_common.h b/sys/contrib/cloudabi/cloudabi_types_common.h
new file mode 100644
index 0000000..83c61b9
--- /dev/null
+++ b/sys/contrib/cloudabi/cloudabi_types_common.h
@@ -0,0 +1,463 @@
+// Copyright (c) 2016 Nuxi (https://nuxi.nl/) and contributors.
+//
+// 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 AUTHOR 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 AUTHOR 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.
+//
+// This file is automatically generated. Do not edit.
+//
+// Source: https://github.com/NuxiNL/cloudabi
+
+#ifndef CLOUDABI_TYPES_COMMON_H
+#define CLOUDABI_TYPES_COMMON_H
+
+#if defined(__FreeBSD__) && defined(_KERNEL)
+#include <sys/stdint.h>
+#elif defined(__linux__) && defined(__KERNEL__)
+#include <linux/types.h>
+#else
+#include <stddef.h>
+#include <stdint.h>
+#endif
+
+typedef uint8_t cloudabi_advice_t;
+#define CLOUDABI_ADVICE_DONTNEED 1
+#define CLOUDABI_ADVICE_NOREUSE 2
+#define CLOUDABI_ADVICE_NORMAL 3
+#define CLOUDABI_ADVICE_RANDOM 4
+#define CLOUDABI_ADVICE_SEQUENTIAL 5
+#define CLOUDABI_ADVICE_WILLNEED 6
+
+typedef uint32_t cloudabi_auxtype_t;
+#define CLOUDABI_AT_ARGDATA 256
+#define CLOUDABI_AT_ARGDATALEN 257
+#define CLOUDABI_AT_BASE 7
+#define CLOUDABI_AT_CANARY 258
+#define CLOUDABI_AT_CANARYLEN 259
+#define CLOUDABI_AT_NCPUS 260
+#define CLOUDABI_AT_NULL 0
+#define CLOUDABI_AT_PAGESZ 6
+#define CLOUDABI_AT_PHDR 3
+#define CLOUDABI_AT_PHNUM 4
+#define CLOUDABI_AT_TID 261
+
+typedef uint32_t cloudabi_backlog_t;
+
+typedef uint32_t cloudabi_clockid_t;
+#define CLOUDABI_CLOCK_MONOTONIC 1
+#define CLOUDABI_CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOUDABI_CLOCK_REALTIME 3
+#define CLOUDABI_CLOCK_THREAD_CPUTIME_ID 4
+
+typedef uint32_t cloudabi_condvar_t;
+#define CLOUDABI_CONDVAR_HAS_NO_WAITERS 0
+
+typedef uint64_t cloudabi_device_t;
+
+typedef uint64_t cloudabi_dircookie_t;
+#define CLOUDABI_DIRCOOKIE_START 0
+
+typedef uint16_t cloudabi_errno_t;
+#define CLOUDABI_E2BIG 1
+#define CLOUDABI_EACCES 2
+#define CLOUDABI_EADDRINUSE 3
+#define CLOUDABI_EADDRNOTAVAIL 4
+#define CLOUDABI_EAFNOSUPPORT 5
+#define CLOUDABI_EAGAIN 6
+#define CLOUDABI_EALREADY 7
+#define CLOUDABI_EBADF 8
+#define CLOUDABI_EBADMSG 9
+#define CLOUDABI_EBUSY 10
+#define CLOUDABI_ECANCELED 11
+#define CLOUDABI_ECHILD 12
+#define CLOUDABI_ECONNABORTED 13
+#define CLOUDABI_ECONNREFUSED 14
+#define CLOUDABI_ECONNRESET 15
+#define CLOUDABI_EDEADLK 16
+#define CLOUDABI_EDESTADDRREQ 17
+#define CLOUDABI_EDOM 18
+#define CLOUDABI_EDQUOT 19
+#define CLOUDABI_EEXIST 20
+#define CLOUDABI_EFAULT 21
+#define CLOUDABI_EFBIG 22
+#define CLOUDABI_EHOSTUNREACH 23
+#define CLOUDABI_EIDRM 24
+#define CLOUDABI_EILSEQ 25
+#define CLOUDABI_EINPROGRESS 26
+#define CLOUDABI_EINTR 27
+#define CLOUDABI_EINVAL 28
+#define CLOUDABI_EIO 29
+#define CLOUDABI_EISCONN 30
+#define CLOUDABI_EISDIR 31
+#define CLOUDABI_ELOOP 32
+#define CLOUDABI_EMFILE 33
+#define CLOUDABI_EMLINK 34
+#define CLOUDABI_EMSGSIZE 35
+#define CLOUDABI_EMULTIHOP 36
+#define CLOUDABI_ENAMETOOLONG 37
+#define CLOUDABI_ENETDOWN 38
+#define CLOUDABI_ENETRESET 39
+#define CLOUDABI_ENETUNREACH 40
+#define CLOUDABI_ENFILE 41
+#define CLOUDABI_ENOBUFS 42
+#define CLOUDABI_ENODEV 43
+#define CLOUDABI_ENOENT 44
+#define CLOUDABI_ENOEXEC 45
+#define CLOUDABI_ENOLCK 46
+#define CLOUDABI_ENOLINK 47
+#define CLOUDABI_ENOMEM 48
+#define CLOUDABI_ENOMSG 49
+#define CLOUDABI_ENOPROTOOPT 50
+#define CLOUDABI_ENOSPC 51
+#define CLOUDABI_ENOSYS 52
+#define CLOUDABI_ENOTCONN 53
+#define CLOUDABI_ENOTDIR 54
+#define CLOUDABI_ENOTEMPTY 55
+#define CLOUDABI_ENOTRECOVERABLE 56
+#define CLOUDABI_ENOTSOCK 57
+#define CLOUDABI_ENOTSUP 58
+#define CLOUDABI_ENOTTY 59
+#define CLOUDABI_ENXIO 60
+#define CLOUDABI_EOVERFLOW 61
+#define CLOUDABI_EOWNERDEAD 62
+#define CLOUDABI_EPERM 63
+#define CLOUDABI_EPIPE 64
+#define CLOUDABI_EPROTO 65
+#define CLOUDABI_EPROTONOSUPPORT 66
+#define CLOUDABI_EPROTOTYPE 67
+#define CLOUDABI_ERANGE 68
+#define CLOUDABI_EROFS 69
+#define CLOUDABI_ESPIPE 70
+#define CLOUDABI_ESRCH 71
+#define CLOUDABI_ESTALE 72
+#define CLOUDABI_ETIMEDOUT 73
+#define CLOUDABI_ETXTBSY 74
+#define CLOUDABI_EXDEV 75
+#define CLOUDABI_ENOTCAPABLE 76
+
+typedef uint16_t cloudabi_eventrwflags_t;
+#define CLOUDABI_EVENT_FD_READWRITE_HANGUP 0x0001
+
+typedef uint8_t cloudabi_eventtype_t;
+#define CLOUDABI_EVENTTYPE_CLOCK 1
+#define CLOUDABI_EVENTTYPE_CONDVAR 2
+#define CLOUDABI_EVENTTYPE_FD_READ 3
+#define CLOUDABI_EVENTTYPE_FD_WRITE 4
+#define CLOUDABI_EVENTTYPE_LOCK_RDLOCK 5
+#define CLOUDABI_EVENTTYPE_LOCK_WRLOCK 6
+#define CLOUDABI_EVENTTYPE_PROC_TERMINATE 7
+
+typedef uint32_t cloudabi_exitcode_t;
+
+typedef uint32_t cloudabi_fd_t;
+#define CLOUDABI_PROCESS_CHILD 0xffffffff
+#define CLOUDABI_MAP_ANON_FD 0xffffffff
+
+typedef uint16_t cloudabi_fdflags_t;
+#define CLOUDABI_FDFLAG_APPEND 0x0001
+#define CLOUDABI_FDFLAG_DSYNC 0x0002
+#define CLOUDABI_FDFLAG_NONBLOCK 0x0004
+#define CLOUDABI_FDFLAG_RSYNC 0x0008
+#define CLOUDABI_FDFLAG_SYNC 0x0010
+
+typedef uint16_t cloudabi_fdsflags_t;
+#define CLOUDABI_FDSTAT_FLAGS 0x0001
+#define CLOUDABI_FDSTAT_RIGHTS 0x0002
+
+typedef int64_t cloudabi_filedelta_t;
+
+typedef uint64_t cloudabi_filesize_t;
+
+typedef uint8_t cloudabi_filetype_t;
+#define CLOUDABI_FILETYPE_UNKNOWN 0
+#define CLOUDABI_FILETYPE_BLOCK_DEVICE 16
+#define CLOUDABI_FILETYPE_CHARACTER_DEVICE 17
+#define CLOUDABI_FILETYPE_DIRECTORY 32
+#define CLOUDABI_FILETYPE_FIFO 48
+#define CLOUDABI_FILETYPE_POLL 64
+#define CLOUDABI_FILETYPE_PROCESS 80
+#define CLOUDABI_FILETYPE_REGULAR_FILE 96
+#define CLOUDABI_FILETYPE_SHARED_MEMORY 112
+#define CLOUDABI_FILETYPE_SOCKET_DGRAM 128
+#define CLOUDABI_FILETYPE_SOCKET_SEQPACKET 129
+#define CLOUDABI_FILETYPE_SOCKET_STREAM 130
+#define CLOUDABI_FILETYPE_SYMBOLIC_LINK 144
+
+typedef uint16_t cloudabi_fsflags_t;
+#define CLOUDABI_FILESTAT_ATIM 0x0001
+#define CLOUDABI_FILESTAT_ATIM_NOW 0x0002
+#define CLOUDABI_FILESTAT_MTIM 0x0004
+#define CLOUDABI_FILESTAT_MTIM_NOW 0x0008
+#define CLOUDABI_FILESTAT_SIZE 0x0010
+
+typedef uint64_t cloudabi_inode_t;
+
+typedef uint32_t cloudabi_linkcount_t;
+
+typedef uint32_t cloudabi_lock_t;
+#define CLOUDABI_LOCK_UNLOCKED 0x00000000
+#define CLOUDABI_LOCK_WRLOCKED 0x40000000
+#define CLOUDABI_LOCK_KERNEL_MANAGED 0x80000000
+#define CLOUDABI_LOCK_BOGUS 0x80000000
+
+typedef uint32_t cloudabi_lookupflags_t;
+#define CLOUDABI_LOOKUP_SYMLINK_FOLLOW 0x00000001
+
+typedef uint8_t cloudabi_mflags_t;
+#define CLOUDABI_MAP_ANON 0x01
+#define CLOUDABI_MAP_FIXED 0x02
+#define CLOUDABI_MAP_PRIVATE 0x04
+#define CLOUDABI_MAP_SHARED 0x08
+
+typedef uint8_t cloudabi_mprot_t;
+#define CLOUDABI_PROT_EXEC 0x01
+#define CLOUDABI_PROT_WRITE 0x02
+#define CLOUDABI_PROT_READ 0x04
+
+typedef uint8_t cloudabi_msflags_t;
+#define CLOUDABI_MS_ASYNC 0x01
+#define CLOUDABI_MS_INVALIDATE 0x02
+#define CLOUDABI_MS_SYNC 0x04
+
+typedef uint16_t cloudabi_msgflags_t;
+#define CLOUDABI_MSG_CTRUNC 0x0001
+#define CLOUDABI_MSG_EOR 0x0002
+#define CLOUDABI_MSG_PEEK 0x0004
+#define CLOUDABI_MSG_TRUNC 0x0008
+#define CLOUDABI_MSG_WAITALL 0x0010
+
+typedef uint32_t cloudabi_nthreads_t;
+
+typedef uint16_t cloudabi_oflags_t;
+#define CLOUDABI_O_CREAT 0x0001
+#define CLOUDABI_O_DIRECTORY 0x0002
+#define CLOUDABI_O_EXCL 0x0004
+#define CLOUDABI_O_TRUNC 0x0008
+
+typedef uint64_t cloudabi_rights_t;
+#define CLOUDABI_RIGHT_FD_DATASYNC 0x0000000000000001
+#define CLOUDABI_RIGHT_FD_READ 0x0000000000000002
+#define CLOUDABI_RIGHT_FD_SEEK 0x0000000000000004
+#define CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS 0x0000000000000008
+#define CLOUDABI_RIGHT_FD_SYNC 0x0000000000000010
+#define CLOUDABI_RIGHT_FD_TELL 0x0000000000000020
+#define CLOUDABI_RIGHT_FD_WRITE 0x0000000000000040
+#define CLOUDABI_RIGHT_FILE_ADVISE 0x0000000000000080
+#define CLOUDABI_RIGHT_FILE_ALLOCATE 0x0000000000000100
+#define CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY 0x0000000000000200
+#define CLOUDABI_RIGHT_FILE_CREATE_FILE 0x0000000000000400
+#define CLOUDABI_RIGHT_FILE_CREATE_FIFO 0x0000000000000800
+#define CLOUDABI_RIGHT_FILE_LINK_SOURCE 0x0000000000001000
+#define CLOUDABI_RIGHT_FILE_LINK_TARGET 0x0000000000002000
+#define CLOUDABI_RIGHT_FILE_OPEN 0x0000000000004000
+#define CLOUDABI_RIGHT_FILE_READDIR 0x0000000000008000
+#define CLOUDABI_RIGHT_FILE_READLINK 0x0000000000010000
+#define CLOUDABI_RIGHT_FILE_RENAME_SOURCE 0x0000000000020000
+#define CLOUDABI_RIGHT_FILE_RENAME_TARGET 0x0000000000040000
+#define CLOUDABI_RIGHT_FILE_STAT_FGET 0x0000000000080000
+#define CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE 0x0000000000100000
+#define CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES 0x0000000000200000
+#define CLOUDABI_RIGHT_FILE_STAT_GET 0x0000000000400000
+#define CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES 0x0000000000800000
+#define CLOUDABI_RIGHT_FILE_SYMLINK 0x0000000001000000
+#define CLOUDABI_RIGHT_FILE_UNLINK 0x0000000002000000
+#define CLOUDABI_RIGHT_MEM_MAP 0x0000000004000000
+#define CLOUDABI_RIGHT_MEM_MAP_EXEC 0x0000000008000000
+#define CLOUDABI_RIGHT_POLL_FD_READWRITE 0x0000000010000000
+#define CLOUDABI_RIGHT_POLL_MODIFY 0x0000000020000000
+#define CLOUDABI_RIGHT_POLL_PROC_TERMINATE 0x0000000040000000
+#define CLOUDABI_RIGHT_POLL_WAIT 0x0000000080000000
+#define CLOUDABI_RIGHT_PROC_EXEC 0x0000000100000000
+#define CLOUDABI_RIGHT_SOCK_ACCEPT 0x0000000200000000
+#define CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY 0x0000000400000000
+#define CLOUDABI_RIGHT_SOCK_BIND_SOCKET 0x0000000800000000
+#define CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY 0x0000001000000000
+#define CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET 0x0000002000000000
+#define CLOUDABI_RIGHT_SOCK_LISTEN 0x0000004000000000
+#define CLOUDABI_RIGHT_SOCK_SHUTDOWN 0x0000008000000000
+#define CLOUDABI_RIGHT_SOCK_STAT_GET 0x0000010000000000
+
+typedef uint8_t cloudabi_sa_family_t;
+#define CLOUDABI_AF_UNSPEC 0
+#define CLOUDABI_AF_INET 1
+#define CLOUDABI_AF_INET6 2
+#define CLOUDABI_AF_UNIX 3
+
+typedef uint8_t cloudabi_scope_t;
+#define CLOUDABI_SCOPE_PRIVATE 4
+#define CLOUDABI_SCOPE_SHARED 8
+
+typedef uint8_t cloudabi_sdflags_t;
+#define CLOUDABI_SHUT_RD 0x01
+#define CLOUDABI_SHUT_WR 0x02
+
+typedef uint8_t cloudabi_signal_t;
+#define CLOUDABI_SIGABRT 1
+#define CLOUDABI_SIGALRM 2
+#define CLOUDABI_SIGBUS 3
+#define CLOUDABI_SIGCHLD 4
+#define CLOUDABI_SIGCONT 5
+#define CLOUDABI_SIGFPE 6
+#define CLOUDABI_SIGHUP 7
+#define CLOUDABI_SIGILL 8
+#define CLOUDABI_SIGINT 9
+#define CLOUDABI_SIGKILL 10
+#define CLOUDABI_SIGPIPE 11
+#define CLOUDABI_SIGQUIT 12
+#define CLOUDABI_SIGSEGV 13
+#define CLOUDABI_SIGSTOP 14
+#define CLOUDABI_SIGSYS 15
+#define CLOUDABI_SIGTERM 16
+#define CLOUDABI_SIGTRAP 17
+#define CLOUDABI_SIGTSTP 18
+#define CLOUDABI_SIGTTIN 19
+#define CLOUDABI_SIGTTOU 20
+#define CLOUDABI_SIGURG 21
+#define CLOUDABI_SIGUSR1 22
+#define CLOUDABI_SIGUSR2 23
+#define CLOUDABI_SIGVTALRM 24
+#define CLOUDABI_SIGXCPU 25
+#define CLOUDABI_SIGXFSZ 26
+
+typedef uint8_t cloudabi_ssflags_t;
+#define CLOUDABI_SOCKSTAT_CLEAR_ERROR 0x01
+
+typedef uint32_t cloudabi_sstate_t;
+#define CLOUDABI_SOCKSTATE_ACCEPTCONN 0x00000001
+
+typedef uint16_t cloudabi_subclockflags_t;
+#define CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME 0x0001
+
+typedef uint16_t cloudabi_subflags_t;
+#define CLOUDABI_SUBSCRIPTION_ADD 0x0001
+#define CLOUDABI_SUBSCRIPTION_CLEAR 0x0002
+#define CLOUDABI_SUBSCRIPTION_DELETE 0x0004
+#define CLOUDABI_SUBSCRIPTION_DISABLE 0x0008
+#define CLOUDABI_SUBSCRIPTION_ENABLE 0x0010
+#define CLOUDABI_SUBSCRIPTION_ONESHOT 0x0020
+
+typedef uint16_t cloudabi_subrwflags_t;
+#define CLOUDABI_SUBSCRIPTION_FD_READWRITE_POLL 0x0001
+
+typedef uint32_t cloudabi_tid_t;
+
+typedef uint64_t cloudabi_timestamp_t;
+
+typedef uint8_t cloudabi_ulflags_t;
+#define CLOUDABI_UNLINK_REMOVEDIR 0x01
+
+typedef uint64_t cloudabi_userdata_t;
+
+typedef uint8_t cloudabi_whence_t;
+#define CLOUDABI_WHENCE_CUR 1
+#define CLOUDABI_WHENCE_END 2
+#define CLOUDABI_WHENCE_SET 3
+
+typedef struct {
+ _Alignas(8) cloudabi_dircookie_t d_next;
+ _Alignas(8) cloudabi_inode_t d_ino;
+ _Alignas(4) uint32_t d_namlen;
+ _Alignas(1) cloudabi_filetype_t d_type;
+} cloudabi_dirent_t;
+_Static_assert(offsetof(cloudabi_dirent_t, d_next) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_dirent_t, d_ino) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_dirent_t, d_namlen) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_dirent_t, d_type) == 20, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_dirent_t) == 24, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_dirent_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(1) cloudabi_filetype_t fs_filetype;
+ _Alignas(2) cloudabi_fdflags_t fs_flags;
+ _Alignas(8) cloudabi_rights_t fs_rights_base;
+ _Alignas(8) cloudabi_rights_t fs_rights_inheriting;
+} cloudabi_fdstat_t;
+_Static_assert(offsetof(cloudabi_fdstat_t, fs_filetype) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_fdstat_t, fs_flags) == 2, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_fdstat_t, fs_rights_base) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_fdstat_t, fs_rights_inheriting) == 16, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_fdstat_t) == 24, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_fdstat_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(8) cloudabi_device_t st_dev;
+ _Alignas(8) cloudabi_inode_t st_ino;
+ _Alignas(1) cloudabi_filetype_t st_filetype;
+ _Alignas(4) cloudabi_linkcount_t st_nlink;
+ _Alignas(8) cloudabi_filesize_t st_size;
+ _Alignas(8) cloudabi_timestamp_t st_atim;
+ _Alignas(8) cloudabi_timestamp_t st_mtim;
+ _Alignas(8) cloudabi_timestamp_t st_ctim;
+} cloudabi_filestat_t;
+_Static_assert(offsetof(cloudabi_filestat_t, st_dev) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_ino) == 8, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_filetype) == 16, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_nlink) == 20, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_size) == 24, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_atim) == 32, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_mtim) == 40, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_filestat_t, st_ctim) == 48, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_filestat_t) == 56, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_filestat_t) == 8, "Incorrect layout");
+
+typedef struct {
+ _Alignas(4) cloudabi_fd_t fd;
+ _Alignas(4) cloudabi_lookupflags_t flags;
+} cloudabi_lookup_t;
+_Static_assert(offsetof(cloudabi_lookup_t, fd) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_lookup_t, flags) == 4, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_lookup_t) == 8, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_lookup_t) == 4, "Incorrect layout");
+
+typedef struct {
+ _Alignas(1) cloudabi_sa_family_t sa_family;
+ union {
+ struct {
+ _Alignas(1) uint8_t addr[4];
+ _Alignas(2) uint16_t port;
+ } sa_inet;
+ struct {
+ _Alignas(1) uint8_t addr[16];
+ _Alignas(2) uint16_t port;
+ } sa_inet6;
+ };
+} cloudabi_sockaddr_t;
+_Static_assert(offsetof(cloudabi_sockaddr_t, sa_family) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockaddr_t, sa_inet.addr) == 2, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockaddr_t, sa_inet.port) == 6, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockaddr_t, sa_inet6.addr) == 2, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockaddr_t, sa_inet6.port) == 18, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_sockaddr_t) == 20, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_sockaddr_t) == 2, "Incorrect layout");
+
+typedef struct {
+ _Alignas(2) cloudabi_sockaddr_t ss_sockname;
+ _Alignas(2) cloudabi_sockaddr_t ss_peername;
+ _Alignas(2) cloudabi_errno_t ss_error;
+ _Alignas(4) cloudabi_sstate_t ss_state;
+} cloudabi_sockstat_t;
+_Static_assert(offsetof(cloudabi_sockstat_t, ss_sockname) == 0, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockstat_t, ss_peername) == 20, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockstat_t, ss_error) == 40, "Incorrect layout");
+_Static_assert(offsetof(cloudabi_sockstat_t, ss_state) == 44, "Incorrect layout");
+_Static_assert(sizeof(cloudabi_sockstat_t) == 48, "Incorrect layout");
+_Static_assert(_Alignof(cloudabi_sockstat_t) == 4, "Incorrect layout");
+
+#endif
diff --git a/sys/contrib/cloudabi/syscalldefs_md.h b/sys/contrib/cloudabi/syscalldefs_md.h
deleted file mode 100644
index f2e3705..0000000
--- a/sys/contrib/cloudabi/syscalldefs_md.h
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright (c) 2015 Nuxi, https://nuxi.nl/
-//
-// 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 AUTHOR 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 AUTHOR 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.
-
-// Machine dependent definitions.
-
-// Macro to force sane alignment rules.
-//
-// On x86-32 it is the case that 64-bit integers are 4-byte aligned when
-// embedded in structs, even though they are 8-byte aligned when not
-// embedded. Force 8-byte alignment explicitly.
-#define MEMBER(type) alignas(alignof(type)) type
-#define ASSERT_OFFSET(type, field, offset32, offset64) \
- static_assert((sizeof(PTR(void)) == 4 && \
- offsetof(IDENT(type), field) == (offset32)) || \
- (sizeof(PTR(void)) == 8 && \
- offsetof(IDENT(type), field) == (offset64)), \
- "Offset incorrect")
-#define ASSERT_SIZE(type, size32, size64) \
- static_assert( \
- (sizeof(PTR(void)) == 4 && sizeof(IDENT(type)) == (size32)) || \
- (sizeof(PTR(void)) == 8 && sizeof(IDENT(type)) == (size64)), \
- "Size incorrect")
-
-typedef void IDENT(threadentry_t)(cloudabi_tid_t, PTR(void));
-
-// Auxiliary vector entry, used to provide paramters on startup.
-typedef struct {
- uint32_t a_type;
- union {
- MEMBER(IDENT(size_t)) a_val;
- MEMBER(PTR(void)) a_ptr;
- };
-} IDENT(auxv_t);
-ASSERT_OFFSET(auxv_t, a_type, 0, 0);
-ASSERT_OFFSET(auxv_t, a_val, 4, 8);
-ASSERT_OFFSET(auxv_t, a_ptr, 4, 8);
-ASSERT_SIZE(auxv_t, 8, 16);
-
-typedef struct {
- MEMBER(PTR(const void)) iov_base;
- MEMBER(IDENT(size_t)) iov_len;
-} IDENT(ciovec_t);
-ASSERT_OFFSET(ciovec_t, iov_base, 0, 0);
-ASSERT_OFFSET(ciovec_t, iov_len, 4, 8);
-ASSERT_SIZE(ciovec_t, 8, 16);
-
-typedef struct {
- MEMBER(cloudabi_userdata_t) userdata;
- MEMBER(cloudabi_errno_t) error;
- MEMBER(cloudabi_eventtype_t) type;
- union {
- // CLOUDABI_EVENTTYPE_CLOCK: Wait until the value of a clock
- // exceeds a value.
- struct {
- MEMBER(cloudabi_userdata_t) identifier;
- } clock;
-
- // CLOUDABI_EVENTTYPE_CONDVAR: Release a lock and wait on a
- // condition variable.
- struct {
- MEMBER(PTR(_Atomic(cloudabi_condvar_t))) condvar;
- } condvar;
-
- // CLOUDABI_EVENTTYPE_FD_READ and CLOUDABI_EVENTTYPE_FD_WRITE:
- // Wait for a file descriptor to allow read() and write() to be
- // called without blocking.
- struct {
- MEMBER(cloudabi_filesize_t) nbytes;
- MEMBER(cloudabi_fd_t) fd;
- MEMBER(uint16_t) flags;
- } fd_readwrite;
-
- // CLOUDABI_EVENT_LOCK_RDLOCK and CLOUDABI_EVENT_LOCK_WRLOCK: Wait
- // and acquire a read or write lock.
- struct {
- MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
- } lock;
-
- // CLOUDABI_EVENTTYPE_PROC_TERMINATE: Wait for a process to terminate.
- struct {
- MEMBER(cloudabi_fd_t) fd;
- MEMBER(cloudabi_signal_t) signal; // Non-zero if process got killed.
- MEMBER(cloudabi_exitcode_t) exitcode; // Exit code.
- } proc_terminate;
- };
-} IDENT(event_t);
-ASSERT_OFFSET(event_t, userdata, 0, 0);
-ASSERT_OFFSET(event_t, error, 8, 8);
-ASSERT_OFFSET(event_t, type, 10, 10);
-ASSERT_OFFSET(event_t, clock.identifier, 16, 16);
-ASSERT_OFFSET(event_t, condvar.condvar, 16, 16);
-ASSERT_OFFSET(event_t, fd_readwrite.nbytes, 16, 16);
-ASSERT_OFFSET(event_t, fd_readwrite.fd, 24, 24);
-ASSERT_OFFSET(event_t, fd_readwrite.flags, 28, 28);
-ASSERT_OFFSET(event_t, lock.lock, 16, 16);
-ASSERT_OFFSET(event_t, proc_terminate.fd, 16, 16);
-ASSERT_OFFSET(event_t, proc_terminate.signal, 20, 20);
-ASSERT_OFFSET(event_t, proc_terminate.exitcode, 24, 24);
-ASSERT_SIZE(event_t, 32, 32);
-
-typedef struct {
- MEMBER(PTR(void)) iov_base;
- MEMBER(IDENT(size_t)) iov_len;
-} IDENT(iovec_t);
-ASSERT_OFFSET(iovec_t, iov_base, 0, 0);
-ASSERT_OFFSET(iovec_t, iov_len, 4, 8);
-ASSERT_SIZE(iovec_t, 8, 16);
-
-typedef struct {
- MEMBER(PTR(const IDENT(iovec_t))) ri_data; // Data I/O vectors.
- MEMBER(IDENT(size_t)) ri_datalen; // Number of data I/O vectors.
- MEMBER(PTR(cloudabi_fd_t)) ri_fds; // File descriptors.
- MEMBER(IDENT(size_t)) ri_fdslen; // Number of file descriptors.
- MEMBER(cloudabi_msgflags_t) ri_flags; // Input flags.
-} IDENT(recv_in_t);
-ASSERT_OFFSET(recv_in_t, ri_data, 0, 0);
-ASSERT_OFFSET(recv_in_t, ri_datalen, 4, 8);
-ASSERT_OFFSET(recv_in_t, ri_fds, 8, 16);
-ASSERT_OFFSET(recv_in_t, ri_fdslen, 12, 24);
-ASSERT_OFFSET(recv_in_t, ri_flags, 16, 32);
-ASSERT_SIZE(recv_in_t, 20, 40);
-
-typedef struct {
- MEMBER(IDENT(size_t)) ro_datalen; // Bytes of data received.
- MEMBER(IDENT(size_t)) ro_fdslen; // Number of file descriptors received.
- MEMBER(cloudabi_sockaddr_t) ro_sockname; // Address of receiver.
- MEMBER(cloudabi_sockaddr_t) ro_peername; // Address of sender.
- MEMBER(cloudabi_msgflags_t) ro_flags; // Output flags.
-} IDENT(recv_out_t);
-ASSERT_OFFSET(recv_out_t, ro_datalen, 0, 0);
-ASSERT_OFFSET(recv_out_t, ro_fdslen, 4, 8);
-ASSERT_OFFSET(recv_out_t, ro_sockname, 8, 16);
-ASSERT_OFFSET(recv_out_t, ro_peername, 28, 36);
-ASSERT_OFFSET(recv_out_t, ro_flags, 48, 56);
-ASSERT_SIZE(recv_out_t, 52, 64);
-
-typedef struct {
- MEMBER(PTR(const IDENT(ciovec_t))) si_data; // Data I/O vectors.
- MEMBER(IDENT(size_t)) si_datalen; // Number of data I/O vectors.
- MEMBER(PTR(const cloudabi_fd_t)) si_fds; // File descriptors.
- MEMBER(IDENT(size_t)) si_fdslen; // Number of file descriptors.
- MEMBER(cloudabi_msgflags_t) si_flags; // Input flags.
-} IDENT(send_in_t);
-ASSERT_OFFSET(send_in_t, si_data, 0, 0);
-ASSERT_OFFSET(send_in_t, si_datalen, 4, 8);
-ASSERT_OFFSET(send_in_t, si_fds, 8, 16);
-ASSERT_OFFSET(send_in_t, si_fdslen, 12, 24);
-ASSERT_OFFSET(send_in_t, si_flags, 16, 32);
-ASSERT_SIZE(send_in_t, 20, 40);
-
-typedef struct {
- MEMBER(IDENT(size_t)) so_datalen; // Bytes of data sent.
-} IDENT(send_out_t);
-ASSERT_OFFSET(send_out_t, so_datalen, 0, 0);
-ASSERT_SIZE(send_out_t, 4, 8);
-
-typedef struct {
- MEMBER(cloudabi_userdata_t) userdata;
- MEMBER(uint16_t) flags;
- MEMBER(cloudabi_eventtype_t) type;
- union {
- // CLOUDABI_EVENTTYPE_CLOCK: Wait until the value of a clock
- // exceeds a value.
- struct {
- MEMBER(cloudabi_userdata_t) identifier;
- MEMBER(cloudabi_clockid_t) clock_id;
- MEMBER(cloudabi_timestamp_t) timeout;
- MEMBER(cloudabi_timestamp_t) precision;
- MEMBER(uint16_t) flags;
- } clock;
-
- // CLOUDABI_EVENTTYPE_CONDVAR: Release a lock and wait on a
- // condition variable.
- struct {
- MEMBER(PTR(_Atomic(cloudabi_condvar_t))) condvar;
- MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
- MEMBER(cloudabi_mflags_t) condvar_scope;
- MEMBER(cloudabi_mflags_t) lock_scope;
- } condvar;
-
- // CLOUDABI_EVENTTYPE_FD_READ and CLOUDABI_EVENTTYPE_FD_WRITE:
- // Wait for a file descriptor to allow read() and write() to be
- // called without blocking.
- struct {
- MEMBER(cloudabi_fd_t) fd;
- MEMBER(uint16_t) flags;
- } fd_readwrite;
-
- // CLOUDABI_EVENT_LOCK_RDLOCK and CLOUDABI_EVENT_LOCK_WRLOCK: Wait
- // and acquire a read or write lock.
- struct {
- MEMBER(PTR(_Atomic(cloudabi_lock_t))) lock;
- MEMBER(cloudabi_mflags_t) lock_scope;
- } lock;
-
- // CLOUDABI_EVENTTYPE_PROC_TERMINATE: Wait for a process to terminate.
- struct {
- MEMBER(cloudabi_fd_t) fd;
- } proc_terminate;
- };
-} IDENT(subscription_t);
-ASSERT_OFFSET(subscription_t, userdata, 0, 0);
-ASSERT_OFFSET(subscription_t, flags, 8, 8);
-ASSERT_OFFSET(subscription_t, type, 10, 10);
-ASSERT_OFFSET(subscription_t, clock.identifier, 16, 16);
-ASSERT_OFFSET(subscription_t, clock.clock_id, 24, 24);
-ASSERT_OFFSET(subscription_t, clock.timeout, 32, 32);
-ASSERT_OFFSET(subscription_t, clock.precision, 40, 40);
-ASSERT_OFFSET(subscription_t, clock.flags, 48, 48);
-ASSERT_OFFSET(subscription_t, condvar.condvar, 16, 16);
-ASSERT_OFFSET(subscription_t, condvar.lock, 20, 24);
-ASSERT_OFFSET(subscription_t, condvar.condvar_scope, 24, 32);
-ASSERT_OFFSET(subscription_t, condvar.lock_scope, 25, 33);
-ASSERT_OFFSET(subscription_t, fd_readwrite.fd, 16, 16);
-ASSERT_OFFSET(subscription_t, fd_readwrite.flags, 20, 20);
-ASSERT_OFFSET(subscription_t, lock.lock, 16, 16);
-ASSERT_OFFSET(subscription_t, lock.lock_scope, 20, 24);
-ASSERT_OFFSET(subscription_t, proc_terminate.fd, 16, 16);
-ASSERT_SIZE(subscription_t, 56, 56);
-
-typedef struct {
- MEMBER(PTR(IDENT(threadentry_t))) entry_point; // Entry point.
- MEMBER(PTR(void)) stack; // Pointer to stack buffer.
- MEMBER(IDENT(size_t)) stack_size; // Size of stack buffer.
- MEMBER(PTR(void)) argument; // Argument to be passed to entry point.
-} IDENT(threadattr_t);
-ASSERT_OFFSET(threadattr_t, entry_point, 0, 0);
-ASSERT_OFFSET(threadattr_t, stack, 4, 8);
-ASSERT_OFFSET(threadattr_t, stack_size, 8, 16);
-ASSERT_OFFSET(threadattr_t, argument, 12, 24);
-ASSERT_SIZE(threadattr_t, 16, 32);
-
-#undef MEMBER
-#undef ASSERT_OFFSET
-#undef ASSERT_SIZE
diff --git a/sys/contrib/cloudabi/syscalldefs_mi.h b/sys/contrib/cloudabi/syscalldefs_mi.h
deleted file mode 100644
index adce208..0000000
--- a/sys/contrib/cloudabi/syscalldefs_mi.h
+++ /dev/null
@@ -1,476 +0,0 @@
-// Copyright (c) 2015 Nuxi, https://nuxi.nl/
-//
-// 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 AUTHOR 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 AUTHOR 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.
-
-#ifndef COMMON_SYSCALLDEFS_MI_H
-#define COMMON_SYSCALLDEFS_MI_H
-
-// Machine independent definitions.
-
-// Socket address families.
-#define CLOUDABI_AF_UNSPEC 0
-#define CLOUDABI_AF_INET 1
-#define CLOUDABI_AF_INET6 2
-#define CLOUDABI_AF_UNIX 3
-
-// File and memory I/O advice.
-#define CLOUDABI_ADVICE_DONTNEED 1
-#define CLOUDABI_ADVICE_NOREUSE 2
-#define CLOUDABI_ADVICE_NORMAL 3
-#define CLOUDABI_ADVICE_RANDOM 4
-#define CLOUDABI_ADVICE_SEQUENTIAL 5
-#define CLOUDABI_ADVICE_WILLNEED 6
-
-// Auxiliary vector entries. All entries that are also part of the
-// x86-64 ABI use the same number. All extensions start at 256.
-#define CLOUDABI_AT_ARGDATA 256
-#define CLOUDABI_AT_ARGDATALEN 257
-#define CLOUDABI_AT_CANARY 258
-#define CLOUDABI_AT_CANARYLEN 259
-#define CLOUDABI_AT_NCPUS 260
-#define CLOUDABI_AT_NULL 0
-#define CLOUDABI_AT_PAGESZ 6
-#define CLOUDABI_AT_PHDR 3
-#define CLOUDABI_AT_PHNUM 4
-#define CLOUDABI_AT_TID 261
-
-// Clocks.
-#define CLOUDABI_CLOCK_MONOTONIC 1
-#define CLOUDABI_CLOCK_PROCESS_CPUTIME_ID 2
-#define CLOUDABI_CLOCK_REALTIME 3
-#define CLOUDABI_CLOCK_THREAD_CPUTIME_ID 4
-
-// Condition variables.
-#define CLOUDABI_CONDVAR_HAS_NO_WAITERS 0
-
-// The start of a directory, to be passed to readdir().
-#define CLOUDABI_DIRCOOKIE_START 0
-
-// POSIX standard error numbers.
-#define CLOUDABI_E2BIG 1
-#define CLOUDABI_EACCES 2
-#define CLOUDABI_EADDRINUSE 3
-#define CLOUDABI_EADDRNOTAVAIL 4
-#define CLOUDABI_EAFNOSUPPORT 5
-#define CLOUDABI_EAGAIN 6
-#define CLOUDABI_EALREADY 7
-#define CLOUDABI_EBADF 8
-#define CLOUDABI_EBADMSG 9
-#define CLOUDABI_EBUSY 10
-#define CLOUDABI_ECANCELED 11
-#define CLOUDABI_ECHILD 12
-#define CLOUDABI_ECONNABORTED 13
-#define CLOUDABI_ECONNREFUSED 14
-#define CLOUDABI_ECONNRESET 15
-#define CLOUDABI_EDEADLK 16
-#define CLOUDABI_EDESTADDRREQ 17
-#define CLOUDABI_EDOM 18
-#define CLOUDABI_EDQUOT 19
-#define CLOUDABI_EEXIST 20
-#define CLOUDABI_EFAULT 21
-#define CLOUDABI_EFBIG 22
-#define CLOUDABI_EHOSTUNREACH 23
-#define CLOUDABI_EIDRM 24
-#define CLOUDABI_EILSEQ 25
-#define CLOUDABI_EINPROGRESS 26
-#define CLOUDABI_EINTR 27
-#define CLOUDABI_EINVAL 28
-#define CLOUDABI_EIO 29
-#define CLOUDABI_EISCONN 30
-#define CLOUDABI_EISDIR 31
-#define CLOUDABI_ELOOP 32
-#define CLOUDABI_EMFILE 33
-#define CLOUDABI_EMLINK 34
-#define CLOUDABI_EMSGSIZE 35
-#define CLOUDABI_EMULTIHOP 36
-#define CLOUDABI_ENAMETOOLONG 37
-#define CLOUDABI_ENETDOWN 38
-#define CLOUDABI_ENETRESET 39
-#define CLOUDABI_ENETUNREACH 40
-#define CLOUDABI_ENFILE 41
-#define CLOUDABI_ENOBUFS 42
-#define CLOUDABI_ENODEV 43
-#define CLOUDABI_ENOENT 44
-#define CLOUDABI_ENOEXEC 45
-#define CLOUDABI_ENOLCK 46
-#define CLOUDABI_ENOLINK 47
-#define CLOUDABI_ENOMEM 48
-#define CLOUDABI_ENOMSG 49
-#define CLOUDABI_ENOPROTOOPT 50
-#define CLOUDABI_ENOSPC 51
-#define CLOUDABI_ENOSYS 52
-#define CLOUDABI_ENOTCONN 53
-#define CLOUDABI_ENOTDIR 54
-#define CLOUDABI_ENOTEMPTY 55
-#define CLOUDABI_ENOTRECOVERABLE 56
-#define CLOUDABI_ENOTSOCK 57
-#define CLOUDABI_ENOTSUP 58
-#define CLOUDABI_ENOTTY 59
-#define CLOUDABI_ENXIO 60
-#define CLOUDABI_EOVERFLOW 61
-#define CLOUDABI_EOWNERDEAD 62
-#define CLOUDABI_EPERM 63
-#define CLOUDABI_EPIPE 64
-#define CLOUDABI_EPROTO 65
-#define CLOUDABI_EPROTONOSUPPORT 66
-#define CLOUDABI_EPROTOTYPE 67
-#define CLOUDABI_ERANGE 68
-#define CLOUDABI_EROFS 69
-#define CLOUDABI_ESPIPE 70
-#define CLOUDABI_ESRCH 71
-#define CLOUDABI_ESTALE 72
-#define CLOUDABI_ETIMEDOUT 73
-#define CLOUDABI_ETXTBSY 74
-#define CLOUDABI_EXDEV 75
-
-// Non-standard error numbers.
-#define CLOUDABI_ENOTCAPABLE 76
-
-#define CLOUDABI_EVENT_FD_READWRITE_HANGUP 0x1
-
-// Filter types for cloudabi_eventtype_t.
-#define CLOUDABI_EVENTTYPE_CLOCK 1
-#define CLOUDABI_EVENTTYPE_CONDVAR 2
-#define CLOUDABI_EVENTTYPE_FD_READ 3
-#define CLOUDABI_EVENTTYPE_FD_WRITE 4
-#define CLOUDABI_EVENTTYPE_LOCK_RDLOCK 5
-#define CLOUDABI_EVENTTYPE_LOCK_WRLOCK 6
-#define CLOUDABI_EVENTTYPE_PROC_TERMINATE 7
-
-// File descriptor behavior flags.
-#define CLOUDABI_FDFLAG_APPEND 0x1
-#define CLOUDABI_FDFLAG_DSYNC 0x2
-#define CLOUDABI_FDFLAG_NONBLOCK 0x4
-#define CLOUDABI_FDFLAG_RSYNC 0x8
-#define CLOUDABI_FDFLAG_SYNC 0x10
-
-// fdstat_put() flags.
-#define CLOUDABI_FDSTAT_FLAGS 0x1
-#define CLOUDABI_FDSTAT_RIGHTS 0x2
-
-// filestat_put() flags.
-#define CLOUDABI_FILESTAT_ATIM 0x1
-#define CLOUDABI_FILESTAT_ATIM_NOW 0x2
-#define CLOUDABI_FILESTAT_MTIM 0x4
-#define CLOUDABI_FILESTAT_MTIM_NOW 0x8
-#define CLOUDABI_FILESTAT_SIZE 0x10
-
-// File types returned through struct stat::st_mode.
-#define CLOUDABI_FILETYPE_UNKNOWN 0
-#define CLOUDABI_FILETYPE_BLOCK_DEVICE 0x10
-#define CLOUDABI_FILETYPE_CHARACTER_DEVICE 0x11
-#define CLOUDABI_FILETYPE_DIRECTORY 0x20
-#define CLOUDABI_FILETYPE_FIFO 0x30
-#define CLOUDABI_FILETYPE_POLL 0x40
-#define CLOUDABI_FILETYPE_PROCESS 0x50
-#define CLOUDABI_FILETYPE_REGULAR_FILE 0x60
-#define CLOUDABI_FILETYPE_SHARED_MEMORY 0x70
-#define CLOUDABI_FILETYPE_SOCKET_DGRAM 0x80
-#define CLOUDABI_FILETYPE_SOCKET_SEQPACKET 0x81
-#define CLOUDABI_FILETYPE_SOCKET_STREAM 0x82
-#define CLOUDABI_FILETYPE_SYMBOLIC_LINK 0x90
-
-// Read-write lock related constants.
-#define CLOUDABI_LOCK_UNLOCKED 0 // Lock is unlocked.
-#define CLOUDABI_LOCK_WRLOCKED 0x40000000 // Lock is write locked.
-#define CLOUDABI_LOCK_KERNEL_MANAGED 0x80000000 // Lock has waiters.
-#define CLOUDABI_LOCK_BOGUS 0x80000000 // Lock is broken.
-
-// Lookup properties for *at() functions.
-#define CLOUDABI_LOOKUP_SYMLINK_FOLLOW (UINT64_C(0x1) << 32)
-
-// Open flags for openat(), etc.
-#define CLOUDABI_O_CREAT 0x1
-#define CLOUDABI_O_DIRECTORY 0x2
-#define CLOUDABI_O_EXCL 0x4
-#define CLOUDABI_O_TRUNC 0x8
-
-// File descriptor returned to pdfork()'s child process.
-#define CLOUDABI_PROCESS_CHILD 0xffffffff
-
-// mmap() map flags.
-#define CLOUDABI_MAP_ANON 0x1
-#define CLOUDABI_MAP_FIXED 0x2
-#define CLOUDABI_MAP_PRIVATE 0x4
-#define CLOUDABI_MAP_SHARED 0x8
-
-// File descriptor that must be passed in when using CLOUDABI_MAP_ANON.
-#define CLOUDABI_MAP_ANON_FD 0xffffffff
-
-// msync() flags.
-#define CLOUDABI_MS_ASYNC 0x1
-#define CLOUDABI_MS_INVALIDATE 0x2
-#define CLOUDABI_MS_SYNC 0x4
-
-// send() and recv() flags.
-#define CLOUDABI_MSG_CTRUNC 0x1 // Control data truncated.
-#define CLOUDABI_MSG_EOR 0x2 // Terminates a record.
-#define CLOUDABI_MSG_PEEK 0x4 // Leave received data in queue.
-#define CLOUDABI_MSG_TRUNC 0x8 // Normal data truncated.
-#define CLOUDABI_MSG_WAITALL 0x10 // Attempt to fill the read buffer.
-
-// mmap()/mprotect() protection flags.
-#define CLOUDABI_PROT_EXEC 0x1
-#define CLOUDABI_PROT_WRITE 0x2
-#define CLOUDABI_PROT_READ 0x4
-
-// File descriptor capabilities/rights.
-#define CLOUDABI_RIGHT_BIT(bit) (UINT64_C(1) << (bit))
-#define CLOUDABI_RIGHT_FD_DATASYNC CLOUDABI_RIGHT_BIT(0)
-#define CLOUDABI_RIGHT_FD_READ CLOUDABI_RIGHT_BIT(1)
-#define CLOUDABI_RIGHT_FD_SEEK CLOUDABI_RIGHT_BIT(2)
-#define CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS CLOUDABI_RIGHT_BIT(3)
-#define CLOUDABI_RIGHT_FD_SYNC CLOUDABI_RIGHT_BIT(4)
-#define CLOUDABI_RIGHT_FD_TELL CLOUDABI_RIGHT_BIT(5)
-#define CLOUDABI_RIGHT_FD_WRITE CLOUDABI_RIGHT_BIT(6)
-#define CLOUDABI_RIGHT_FILE_ADVISE CLOUDABI_RIGHT_BIT(7)
-#define CLOUDABI_RIGHT_FILE_ALLOCATE CLOUDABI_RIGHT_BIT(8)
-#define CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY CLOUDABI_RIGHT_BIT(9)
-#define CLOUDABI_RIGHT_FILE_CREATE_FILE CLOUDABI_RIGHT_BIT(10)
-#define CLOUDABI_RIGHT_FILE_CREATE_FIFO CLOUDABI_RIGHT_BIT(11)
-#define CLOUDABI_RIGHT_FILE_LINK_SOURCE CLOUDABI_RIGHT_BIT(12)
-#define CLOUDABI_RIGHT_FILE_LINK_TARGET CLOUDABI_RIGHT_BIT(13)
-#define CLOUDABI_RIGHT_FILE_OPEN CLOUDABI_RIGHT_BIT(14)
-#define CLOUDABI_RIGHT_FILE_READDIR CLOUDABI_RIGHT_BIT(15)
-#define CLOUDABI_RIGHT_FILE_READLINK CLOUDABI_RIGHT_BIT(16)
-#define CLOUDABI_RIGHT_FILE_RENAME_SOURCE CLOUDABI_RIGHT_BIT(17)
-#define CLOUDABI_RIGHT_FILE_RENAME_TARGET CLOUDABI_RIGHT_BIT(18)
-#define CLOUDABI_RIGHT_FILE_STAT_FGET CLOUDABI_RIGHT_BIT(19)
-#define CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE CLOUDABI_RIGHT_BIT(20)
-#define CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES CLOUDABI_RIGHT_BIT(21)
-#define CLOUDABI_RIGHT_FILE_STAT_GET CLOUDABI_RIGHT_BIT(22)
-#define CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES CLOUDABI_RIGHT_BIT(23)
-#define CLOUDABI_RIGHT_FILE_SYMLINK CLOUDABI_RIGHT_BIT(24)
-#define CLOUDABI_RIGHT_FILE_UNLINK CLOUDABI_RIGHT_BIT(25)
-#define CLOUDABI_RIGHT_MEM_MAP CLOUDABI_RIGHT_BIT(26)
-#define CLOUDABI_RIGHT_MEM_MAP_EXEC CLOUDABI_RIGHT_BIT(27)
-#define CLOUDABI_RIGHT_POLL_FD_READWRITE CLOUDABI_RIGHT_BIT(28)
-#define CLOUDABI_RIGHT_POLL_MODIFY CLOUDABI_RIGHT_BIT(29)
-#define CLOUDABI_RIGHT_POLL_PROC_TERMINATE CLOUDABI_RIGHT_BIT(30)
-#define CLOUDABI_RIGHT_POLL_WAIT CLOUDABI_RIGHT_BIT(31)
-#define CLOUDABI_RIGHT_PROC_EXEC CLOUDABI_RIGHT_BIT(32)
-#define CLOUDABI_RIGHT_SOCK_ACCEPT CLOUDABI_RIGHT_BIT(33)
-#define CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY CLOUDABI_RIGHT_BIT(34)
-#define CLOUDABI_RIGHT_SOCK_BIND_SOCKET CLOUDABI_RIGHT_BIT(35)
-#define CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY CLOUDABI_RIGHT_BIT(36)
-#define CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET CLOUDABI_RIGHT_BIT(37)
-#define CLOUDABI_RIGHT_SOCK_LISTEN CLOUDABI_RIGHT_BIT(38)
-#define CLOUDABI_RIGHT_SOCK_SHUTDOWN CLOUDABI_RIGHT_BIT(39)
-#define CLOUDABI_RIGHT_SOCK_STAT_GET CLOUDABI_RIGHT_BIT(40)
-
-// Socket shutdown flags.
-#define CLOUDABI_SHUT_RD 0x1
-#define CLOUDABI_SHUT_WR 0x2
-
-// Signals.
-#define CLOUDABI_SIGABRT 1
-#define CLOUDABI_SIGALRM 2
-#define CLOUDABI_SIGBUS 3
-#define CLOUDABI_SIGCHLD 4
-#define CLOUDABI_SIGCONT 5
-#define CLOUDABI_SIGFPE 6
-#define CLOUDABI_SIGHUP 7
-#define CLOUDABI_SIGILL 8
-#define CLOUDABI_SIGINT 9
-#define CLOUDABI_SIGKILL 10
-#define CLOUDABI_SIGPIPE 11
-#define CLOUDABI_SIGQUIT 12
-#define CLOUDABI_SIGSEGV 13
-#define CLOUDABI_SIGSTOP 14
-#define CLOUDABI_SIGSYS 15
-#define CLOUDABI_SIGTERM 16
-#define CLOUDABI_SIGTRAP 17
-#define CLOUDABI_SIGTSTP 18
-#define CLOUDABI_SIGTTIN 19
-#define CLOUDABI_SIGTTOU 20
-#define CLOUDABI_SIGURG 21
-#define CLOUDABI_SIGUSR1 22
-#define CLOUDABI_SIGUSR2 23
-#define CLOUDABI_SIGVTALRM 24
-#define CLOUDABI_SIGXCPU 25
-#define CLOUDABI_SIGXFSZ 26
-
-// sockstat() flags.
-#define CLOUDABI_SOCKSTAT_CLEAR_ERROR 0x1
-
-// sockstat() state.
-#define CLOUDABI_SOCKSTAT_ACCEPTCONN 0x1
-
-// cloudabi_subscription_t flags.
-#define CLOUDABI_SUBSCRIPTION_ADD 0x1
-#define CLOUDABI_SUBSCRIPTION_CLEAR 0x2
-#define CLOUDABI_SUBSCRIPTION_DELETE 0x4
-#define CLOUDABI_SUBSCRIPTION_DISABLE 0x8
-#define CLOUDABI_SUBSCRIPTION_ENABLE 0x10
-#define CLOUDABI_SUBSCRIPTION_ONESHOT 0x20
-
-// cloudabi_subscription_t::clock.flags.
-#define CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME 0x1
-
-// cloudabi_subscription_t::fd_readwrite.flags.
-#define CLOUDABI_SUBSCRIPTION_FD_READWRITE_POLL 0x1
-
-// unlinkat().
-#define CLOUDABI_UNLINK_REMOVEDIR 0x1
-
-// Seeking.
-#define CLOUDABI_WHENCE_CUR 1
-#define CLOUDABI_WHENCE_END 2
-#define CLOUDABI_WHENCE_SET 3
-
-typedef uint8_t cloudabi_advice_t; // posix_fadvise() and posix_madvise().
-typedef uint32_t cloudabi_backlog_t; // listen().
-typedef uint32_t cloudabi_clockid_t; // clock_*().
-typedef uint32_t cloudabi_condvar_t; // pthread_cond_*().
-typedef uint64_t cloudabi_device_t; // struct stat::st_dev.
-typedef uint64_t cloudabi_dircookie_t; // readdir().
-typedef uint16_t cloudabi_errno_t; // errno.
-typedef uint8_t cloudabi_eventtype_t; // poll().
-typedef uint32_t cloudabi_exitcode_t; // _exit() and _Exit().
-typedef uint32_t cloudabi_fd_t; // File descriptors.
-typedef uint16_t cloudabi_fdflags_t; // cloudabi_fdstat_t.
-typedef uint16_t cloudabi_fdsflags_t; // fd_stat_put().
-typedef int64_t cloudabi_filedelta_t; // lseek().
-typedef uint64_t cloudabi_filesize_t; // ftruncate(), struct stat::st_size.
-typedef uint8_t cloudabi_filetype_t; // struct stat::st_mode.
-typedef uint16_t cloudabi_fsflags_t; // file_stat_put().
-typedef uint64_t cloudabi_inode_t; // struct stat::st_ino.
-typedef uint32_t cloudabi_linkcount_t; // struct stat::st_nlink.
-typedef uint32_t cloudabi_lock_t; // pthread_{mutex,rwlock}_*().
-typedef uint64_t cloudabi_lookup_t; // openat(), linkat(), etc.
-typedef uint8_t cloudabi_mflags_t; // mmap().
-typedef uint8_t cloudabi_mprot_t; // mmap().
-typedef uint8_t cloudabi_msflags_t; // msync().
-typedef uint16_t cloudabi_msgflags_t; // send() and recv().
-typedef uint32_t cloudabi_nthreads_t; // pthread_cond_*().
-typedef uint16_t cloudabi_oflags_t; // openat(), etc.
-typedef uint64_t cloudabi_rights_t; // File descriptor rights.
-typedef uint8_t cloudabi_sa_family_t; // Socket address family.
-typedef uint8_t cloudabi_sdflags_t; // shutdown().
-typedef uint8_t cloudabi_ssflags_t; // sockstat().
-typedef uint8_t cloudabi_signal_t; // raise().
-typedef uint32_t cloudabi_tid_t; // Thread ID.
-typedef uint64_t cloudabi_timestamp_t; // clock_*(), struct stat::st_*tim.
-typedef uint8_t cloudabi_ulflags_t; // unlinkat().
-typedef uint64_t cloudabi_userdata_t; // User-supplied data for callbacks.
-typedef uint8_t cloudabi_whence_t; // lseek().
-
-// Macro to force sane alignment rules.
-//
-// On x86-32 it is the case that 64-bit integers are 4-byte aligned when
-// embedded in structs, even though they are 8-byte aligned when not
-// embedded. Force 8-byte alignment explicitly.
-#define MEMBER(type) alignas(alignof(type)) type
-#define ASSERT_OFFSET(type, field, offset) \
- static_assert(offsetof(cloudabi_##type, field) == (offset), \
- "Offset incorrect")
-#define ASSERT_SIZE(type, size) \
- static_assert(sizeof(cloudabi_##type) == (size), "Size incorrect")
-
-// Directory entries.
-typedef struct {
- MEMBER(cloudabi_dircookie_t) d_next; // Cookie of the next entry.
- MEMBER(cloudabi_inode_t) d_ino; // Inode number of the current entry.
- MEMBER(uint32_t) d_namlen; // Length of the name of the current entry.
- MEMBER(cloudabi_filetype_t) d_type; // File type of the current entry.
-} cloudabi_dirent_t;
-ASSERT_OFFSET(dirent_t, d_next, 0);
-ASSERT_OFFSET(dirent_t, d_ino, 8);
-ASSERT_OFFSET(dirent_t, d_namlen, 16);
-ASSERT_OFFSET(dirent_t, d_type, 20);
-ASSERT_SIZE(dirent_t, 24);
-
-// File descriptor status.
-typedef struct {
- MEMBER(cloudabi_filetype_t) fs_filetype; // File descriptor type.
- MEMBER(cloudabi_fdflags_t) fs_flags; // Non-blocking mode, etc.
- MEMBER(cloudabi_rights_t) fs_rights_base; // Base rights.
- MEMBER(cloudabi_rights_t) fs_rights_inheriting; // Inheriting rights.
-} cloudabi_fdstat_t;
-ASSERT_OFFSET(fdstat_t, fs_filetype, 0);
-ASSERT_OFFSET(fdstat_t, fs_flags, 2);
-ASSERT_OFFSET(fdstat_t, fs_rights_base, 8);
-ASSERT_OFFSET(fdstat_t, fs_rights_inheriting, 16);
-ASSERT_SIZE(fdstat_t, 24);
-
-// File status.
-typedef struct {
- MEMBER(cloudabi_device_t) st_dev; // Device storing the file.
- MEMBER(cloudabi_inode_t) st_ino; // Inode of the file.
- MEMBER(cloudabi_filetype_t) st_filetype; // File type.
- MEMBER(cloudabi_linkcount_t) st_nlink; // Number of hardlinks.
- MEMBER(cloudabi_filesize_t) st_size; // Size of the file.
- MEMBER(cloudabi_timestamp_t) st_atim; // Access time.
- MEMBER(cloudabi_timestamp_t) st_mtim; // Modification time.
- MEMBER(cloudabi_timestamp_t) st_ctim; // Change time.
-} cloudabi_filestat_t;
-ASSERT_OFFSET(filestat_t, st_dev, 0);
-ASSERT_OFFSET(filestat_t, st_ino, 8);
-ASSERT_OFFSET(filestat_t, st_filetype, 16);
-ASSERT_OFFSET(filestat_t, st_nlink, 20);
-ASSERT_OFFSET(filestat_t, st_size, 24);
-ASSERT_OFFSET(filestat_t, st_atim, 32);
-ASSERT_OFFSET(filestat_t, st_mtim, 40);
-ASSERT_OFFSET(filestat_t, st_ctim, 48);
-ASSERT_SIZE(filestat_t, 56);
-
-typedef struct {
- MEMBER(cloudabi_sa_family_t) sa_family;
- union {
- struct {
- // IPv4 address and port number.
- MEMBER(uint8_t) addr[4];
- MEMBER(uint16_t) port;
- } sa_inet;
- struct {
- // IPv6 address and port number.
- // TODO(ed): What about the flow info and scope ID?
- MEMBER(uint8_t) addr[16];
- MEMBER(uint16_t) port;
- } sa_inet6;
- };
-} cloudabi_sockaddr_t;
-ASSERT_OFFSET(sockaddr_t, sa_family, 0);
-ASSERT_OFFSET(sockaddr_t, sa_inet.addr, 2);
-ASSERT_OFFSET(sockaddr_t, sa_inet.port, 6);
-ASSERT_OFFSET(sockaddr_t, sa_inet6.addr, 2);
-ASSERT_OFFSET(sockaddr_t, sa_inet6.port, 18);
-ASSERT_SIZE(sockaddr_t, 20);
-
-// Socket status.
-typedef struct {
- MEMBER(cloudabi_sockaddr_t) ss_sockname; // Socket address.
- MEMBER(cloudabi_sockaddr_t) ss_peername; // Peer address.
- MEMBER(cloudabi_errno_t) ss_error; // Current error state.
- MEMBER(uint32_t) ss_state; // State flags.
-} cloudabi_sockstat_t;
-ASSERT_OFFSET(sockstat_t, ss_sockname, 0);
-ASSERT_OFFSET(sockstat_t, ss_peername, 20);
-ASSERT_OFFSET(sockstat_t, ss_error, 40);
-ASSERT_OFFSET(sockstat_t, ss_state, 44);
-ASSERT_SIZE(sockstat_t, 48);
-
-#undef MEMBER
-#undef ASSERT_OFFSET
-#undef ASSERT_SIZE
-
-#endif
diff --git a/sys/compat/cloudabi64/syscalls.master b/sys/contrib/cloudabi/syscalls.master
index 5fd6f7e..7da55c5 100644
--- a/sys/compat/cloudabi64/syscalls.master
+++ b/sys/contrib/cloudabi/syscalls.master
@@ -1,19 +1,43 @@
$FreeBSD$
-; System call table for CloudABI.
+; Copyright (c) 2016 Nuxi (https://nuxi.nl/) and contributors.
;
-; All system calls that do not use any machine-dependent data types are
-; prefixed with cloudabi_sys_. The others are called cloudabi64_sys_.
+; 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 AUTHOR 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 AUTHOR 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.
+;
+; This file is automatically generated. Do not edit.
+;
+; Source: https://github.com/NuxiNL/cloudabi
#include <sys/sysent.h>
#include <sys/sysproto.h>
-#include <compat/cloudabi64/cloudabi64_syscalldefs.h>
+#include <contrib/cloudabi/cloudabi64_types.h>
+
#include <compat/cloudabi64/cloudabi64_proto.h>
0 AUE_NULL STD { cloudabi_timestamp_t \
cloudabi_sys_clock_res_get( \
cloudabi_clockid_t clock_id); }
+
1 AUE_NULL STD { cloudabi_timestamp_t \
cloudabi_sys_clock_time_get( \
cloudabi_clockid_t clock_id, \
@@ -21,200 +45,274 @@
2 AUE_NULL STD { void cloudabi_sys_condvar_signal( \
cloudabi_condvar_t *condvar, \
- cloudabi_mflags_t scope, \
+ cloudabi_scope_t scope, \
cloudabi_nthreads_t nwaiters); }
3 AUE_NULL STD { void cloudabi_sys_fd_close( \
cloudabi_fd_t fd); }
+
4 AUE_NULL STD { cloudabi_fd_t cloudabi_sys_fd_create1( \
cloudabi_filetype_t type); }
+
5 AUE_NULL STD { void cloudabi_sys_fd_create2( \
cloudabi_filetype_t type); }
+
6 AUE_NULL STD { void cloudabi_sys_fd_datasync( \
cloudabi_fd_t fd); }
+
7 AUE_NULL STD { cloudabi_fd_t cloudabi_sys_fd_dup( \
cloudabi_fd_t from); }
-8 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_fd_pread( \
+
+8 AUE_NULL STD { size_t cloudabi64_sys_fd_pread( \
cloudabi_fd_t fd, \
const cloudabi64_iovec_t *iov, \
- cloudabi64_size_t iovcnt, \
+ size_t iovcnt, \
cloudabi_filesize_t offset); }
-9 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_fd_pwrite( \
+
+9 AUE_NULL STD { size_t cloudabi64_sys_fd_pwrite( \
cloudabi_fd_t fd, \
const cloudabi64_ciovec_t *iov, \
- cloudabi64_size_t iovcnt, \
+ size_t iovcnt, \
cloudabi_filesize_t offset); }
-10 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_fd_read( \
+
+10 AUE_NULL STD { size_t cloudabi64_sys_fd_read( \
cloudabi_fd_t fd, \
const cloudabi64_iovec_t *iov, \
- cloudabi64_size_t iovcnt); }
+ size_t iovcnt); }
+
11 AUE_NULL STD { void cloudabi_sys_fd_replace( \
cloudabi_fd_t from, \
cloudabi_fd_t to); }
-12 AUE_NULL STD { cloudabi_filesize_t cloudabi_sys_fd_seek( \
+
+12 AUE_NULL STD { cloudabi_filesize_t \
+ cloudabi_sys_fd_seek( \
cloudabi_fd_t fd, \
cloudabi_filedelta_t offset, \
cloudabi_whence_t whence); }
+
13 AUE_NULL STD { void cloudabi_sys_fd_stat_get( \
cloudabi_fd_t fd, \
cloudabi_fdstat_t *buf); }
+
14 AUE_NULL STD { void cloudabi_sys_fd_stat_put( \
cloudabi_fd_t fd, \
const cloudabi_fdstat_t *buf, \
cloudabi_fdsflags_t flags); }
+
15 AUE_NULL STD { void cloudabi_sys_fd_sync( \
cloudabi_fd_t fd); }
-16 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_fd_write( \
+
+16 AUE_NULL STD { size_t cloudabi64_sys_fd_write( \
cloudabi_fd_t fd, \
const cloudabi64_ciovec_t *iov, \
- cloudabi64_size_t iovcnt); }
+ size_t iovcnt); }
17 AUE_NULL STD { void cloudabi_sys_file_advise( \
cloudabi_fd_t fd, \
cloudabi_filesize_t offset, \
cloudabi_filesize_t len, \
cloudabi_advice_t advice); }
+
18 AUE_NULL STD { void cloudabi_sys_file_allocate( \
cloudabi_fd_t fd, \
cloudabi_filesize_t offset, \
cloudabi_filesize_t len); }
+
19 AUE_NULL STD { void cloudabi_sys_file_create( \
cloudabi_fd_t fd, \
- const char *path, size_t pathlen, \
+ const char *path, \
+ size_t pathlen, \
cloudabi_filetype_t type); }
+
20 AUE_NULL STD { void cloudabi_sys_file_link( \
cloudabi_lookup_t fd1, \
- const char *path1, size_t path1len, \
+ const char *path1, \
+ size_t path1len, \
cloudabi_fd_t fd2, \
- const char *path2, size_t path2len); }
+ const char *path2, \
+ size_t path2len); }
+
21 AUE_NULL STD { cloudabi_fd_t cloudabi_sys_file_open( \
- cloudabi_lookup_t fd, \
- const char *path, size_t pathlen, \
+ cloudabi_lookup_t dirfd, \
+ const char *path, \
+ size_t pathlen, \
cloudabi_oflags_t oflags, \
const cloudabi_fdstat_t *fds); }
+
22 AUE_NULL STD { size_t cloudabi_sys_file_readdir( \
cloudabi_fd_t fd, \
- void *buf, size_t nbyte, \
+ void *buf, \
+ size_t nbyte, \
cloudabi_dircookie_t cookie); }
+
23 AUE_NULL STD { size_t cloudabi_sys_file_readlink( \
cloudabi_fd_t fd, \
- const char *path, size_t pathlen, \
- void *buf, size_t bufsize); }
+ const char *path, \
+ size_t pathlen, \
+ char *buf, \
+ size_t bufsize); }
+
24 AUE_NULL STD { void cloudabi_sys_file_rename( \
cloudabi_fd_t oldfd, \
- const char *old, size_t oldlen, \
+ const char *old, \
+ size_t oldlen, \
cloudabi_fd_t newfd, \
- const char *new, size_t newlen); }
+ const char *new, \
+ size_t newlen); }
+
25 AUE_NULL STD { void cloudabi_sys_file_stat_fget( \
cloudabi_fd_t fd, \
cloudabi_filestat_t *buf); }
+
26 AUE_NULL STD { void cloudabi_sys_file_stat_fput( \
cloudabi_fd_t fd, \
const cloudabi_filestat_t *buf, \
cloudabi_fsflags_t flags); }
+
27 AUE_NULL STD { void cloudabi_sys_file_stat_get( \
cloudabi_lookup_t fd, \
- const char *path, size_t pathlen, \
+ const char *path, \
+ size_t pathlen, \
cloudabi_filestat_t *buf); }
+
28 AUE_NULL STD { void cloudabi_sys_file_stat_put( \
cloudabi_lookup_t fd, \
- const char *path, size_t pathlen, \
+ const char *path, \
+ size_t pathlen, \
const cloudabi_filestat_t *buf, \
cloudabi_fsflags_t flags); }
+
29 AUE_NULL STD { void cloudabi_sys_file_symlink( \
- const char *path1, size_t path1len, \
+ const char *path1, \
+ size_t path1len, \
cloudabi_fd_t fd, \
- const char *path2, size_t path2len); }
+ const char *path2, \
+ size_t path2len); }
+
30 AUE_NULL STD { void cloudabi_sys_file_unlink( \
cloudabi_fd_t fd, \
- const char *path, size_t pathlen, \
- cloudabi_ulflags_t flag); }
+ const char *path, \
+ size_t pathlen, \
+ cloudabi_ulflags_t flags); }
31 AUE_NULL STD { void cloudabi_sys_lock_unlock( \
cloudabi_lock_t *lock, \
- cloudabi_mflags_t scope); }
+ cloudabi_scope_t scope); }
32 AUE_NULL STD { void cloudabi_sys_mem_advise( \
- void *addr, size_t len, \
+ void *addr, \
+ size_t len, \
cloudabi_advice_t advice); }
+
33 AUE_NULL STD { void cloudabi_sys_mem_lock( \
- const void *addr, size_t len); }
+ const void *addr, \
+ size_t len); }
+
34 AUE_NULL STD { void cloudabi_sys_mem_map( \
- void *addr, size_t len, \
+ void *addr, \
+ size_t len, \
cloudabi_mprot_t prot, \
cloudabi_mflags_t flags, \
cloudabi_fd_t fd, \
cloudabi_filesize_t off); }
+
35 AUE_NULL STD { void cloudabi_sys_mem_protect( \
- void *addr, size_t len, \
+ void *addr, \
+ size_t len, \
cloudabi_mprot_t prot); }
+
36 AUE_NULL STD { void cloudabi_sys_mem_sync( \
- void *addr, size_t len, \
+ void *addr, \
+ size_t len, \
cloudabi_msflags_t flags); }
+
37 AUE_NULL STD { void cloudabi_sys_mem_unlock( \
- const void *addr, size_t len); }
+ const void *addr, \
+ size_t len); }
+
38 AUE_NULL STD { void cloudabi_sys_mem_unmap( \
- void * addr, size_t len); }
+ void *addr, \
+ size_t len); }
-39 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_poll( \
+39 AUE_NULL STD { size_t cloudabi64_sys_poll( \
const cloudabi64_subscription_t *in, \
cloudabi64_event_t *out, \
- cloudabi64_size_t nevents); }
+ size_t nsubscriptions); }
40 AUE_NULL STD { void cloudabi_sys_proc_exec( \
- cloudabi_fd_t fd, const void *data, \
+ cloudabi_fd_t fd, \
+ const void *data, \
size_t datalen, \
const cloudabi_fd_t *fds, \
size_t fdslen); }
+
41 AUE_NULL STD { void cloudabi_sys_proc_exit( \
cloudabi_exitcode_t rval); }
-42 AUE_NULL STD { cloudabi_fd_t cloudabi_sys_proc_fork(); }
+
+42 AUE_NULL STD { void cloudabi_sys_proc_fork(); }
+
43 AUE_NULL STD { void cloudabi_sys_proc_raise( \
cloudabi_signal_t sig); }
44 AUE_NULL STD { void cloudabi_sys_random_get( \
- void *buf, size_t nbyte); }
+ void *buf, \
+ size_t nbyte); }
45 AUE_NULL STD { cloudabi_fd_t cloudabi_sys_sock_accept( \
- cloudabi_fd_t s, \
+ cloudabi_fd_t sock, \
cloudabi_sockstat_t *buf); }
+
46 AUE_NULL STD { void cloudabi_sys_sock_bind( \
- cloudabi_fd_t s, cloudabi_fd_t fd, \
- const char *path, size_t pathlen); }
+ cloudabi_fd_t sock, \
+ cloudabi_fd_t fd, \
+ const char *path, \
+ size_t pathlen); }
+
47 AUE_NULL STD { void cloudabi_sys_sock_connect( \
- cloudabi_fd_t s, cloudabi_fd_t fd, \
- const char *path, size_t pathlen); }
+ cloudabi_fd_t sock, \
+ cloudabi_fd_t fd, \
+ const char *path, \
+ size_t pathlen); }
+
48 AUE_NULL STD { void cloudabi_sys_sock_listen( \
- cloudabi_fd_t s, \
+ cloudabi_fd_t sock, \
cloudabi_backlog_t backlog); }
-49 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_sock_recv( \
- cloudabi_fd_t s, \
+
+49 AUE_NULL STD { void cloudabi64_sys_sock_recv( \
+ cloudabi_fd_t sock, \
const cloudabi64_recv_in_t *in, \
cloudabi64_recv_out_t *out); }
-50 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_sock_send( \
- cloudabi_fd_t s, \
+
+50 AUE_NULL STD { void cloudabi64_sys_sock_send( \
+ cloudabi_fd_t sock, \
const cloudabi64_send_in_t *in, \
cloudabi64_send_out_t *out); }
+
51 AUE_NULL STD { void cloudabi_sys_sock_shutdown( \
- cloudabi_fd_t fd, \
+ cloudabi_fd_t sock, \
cloudabi_sdflags_t how); }
+
52 AUE_NULL STD { void cloudabi_sys_sock_stat_get( \
- cloudabi_fd_t fd, \
+ cloudabi_fd_t sock, \
cloudabi_sockstat_t *buf, \
cloudabi_ssflags_t flags); }
53 AUE_NULL STD { cloudabi_tid_t cloudabi64_sys_thread_create( \
cloudabi64_threadattr_t *attr); }
+
54 AUE_NULL STD { void cloudabi_sys_thread_exit( \
cloudabi_lock_t *lock, \
- cloudabi_mflags_t scope); }
-55 AUE_NULL STD { void cloudabi_sys_thread_tcb_set(void *tcb); }
+ cloudabi_scope_t scope); }
+
+55 AUE_NULL STD { void cloudabi_sys_thread_tcb_set( \
+ void *tcb); }
+
56 AUE_NULL STD { void cloudabi_sys_thread_yield(); }
-57 AUE_NULL STD { cloudabi64_size_t cloudabi64_sys_poll_fd( \
+57 AUE_NULL STD { size_t cloudabi64_sys_poll_fd( \
cloudabi_fd_t fd, \
const cloudabi64_subscription_t *in, \
- cloudabi64_size_t nin, \
+ size_t nin, \
cloudabi64_event_t *out, \
- cloudabi64_size_t nout, \
+ size_t nout, \
const cloudabi64_subscription_t *timeout); }
diff --git a/sys/contrib/rdma/krping/krping.c b/sys/contrib/rdma/krping/krping.c
index 667af40..3ad881e 100644
--- a/sys/contrib/rdma/krping/krping.c
+++ b/sys/contrib/rdma/krping/krping.c
@@ -261,12 +261,18 @@ static int krping_cma_event_handler(struct rdma_cm_id *cma_id,
case RDMA_CM_EVENT_ROUTE_RESOLVED:
cb->state = ROUTE_RESOLVED;
+ cb->child_cm_id = cma_id;
wake_up_interruptible(&cb->sem);
break;
case RDMA_CM_EVENT_CONNECT_REQUEST:
- cb->state = CONNECT_REQUEST;
- cb->child_cm_id = cma_id;
+ if (cb->state == IDLE) {
+ cb->state = CONNECT_REQUEST;
+ cb->child_cm_id = cma_id;
+ } else {
+ PRINTF(cb, "Received connection request in wrong state"
+ " (%d)\n", cb->state);
+ }
DEBUG_LOG(cb, "child cma %p\n", cb->child_cm_id);
wake_up_interruptible(&cb->sem);
break;
diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c
index f38c89f..76ab2c5 100644
--- a/sys/ddb/db_ps.c
+++ b/sys/ddb/db_ps.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/cons.h>
#include <sys/jail.h>
#include <sys/kdb.h>
+#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/systm.h>
@@ -302,6 +303,7 @@ DB_SHOW_COMMAND(thread, db_show_thread)
struct thread *td;
struct lock_object *lock;
bool comma;
+ int delta;
/* Determine which thread to examine. */
if (have_addr)
@@ -376,6 +378,16 @@ DB_SHOW_COMMAND(thread, db_show_thread)
td->td_wchan);
db_printf(" priority: %d\n", td->td_priority);
db_printf(" container lock: %s (%p)\n", lock->lo_name, lock);
+ if (td->td_swvoltick != 0) {
+ delta = (u_int)ticks - (u_int)td->td_swvoltick;
+ db_printf(" last voluntary switch: %d ms ago\n",
+ 1000 * delta / hz);
+ }
+ if (td->td_swinvoltick != 0) {
+ delta = (u_int)ticks - (u_int)td->td_swinvoltick;
+ db_printf(" last involuntary switch: %d ms ago\n",
+ 1000 * delta / hz);
+ }
}
DB_SHOW_COMMAND(proc, db_show_proc)
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 70d4bce..6f5a11f 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -795,10 +795,10 @@ acpi_print_child(device_t bus, device_t child)
int retval = 0;
retval += bus_print_child_header(bus, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
- retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
+ retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd");
if (device_get_flags(child))
retval += printf(" flags %#x", device_get_flags(child));
retval += bus_print_child_domain(bus, child);
@@ -1156,7 +1156,7 @@ acpi_sysres_alloc(device_t dev)
rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
STAILQ_FOREACH(rle, rl, link) {
if (rle->res != NULL) {
- device_printf(dev, "duplicate resource for %lx\n", rle->start);
+ device_printf(dev, "duplicate resource for %jx\n", rle->start);
continue;
}
@@ -1179,7 +1179,7 @@ acpi_sysres_alloc(device_t dev)
rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
rle->res = res;
} else if (bootverbose)
- device_printf(dev, "reservation of %lx, %lx (%d) failed\n",
+ device_printf(dev, "reservation of %jx, %jx (%d) failed\n",
rle->start, rle->count, rle->type);
}
return (0);
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c
index 76fbd5a..da1e160e 100644
--- a/sys/dev/acpica/acpi_hpet.c
+++ b/sys/dev/acpica/acpi_hpet.c
@@ -453,7 +453,7 @@ hpet_attach(device_t dev)
/* Validate that we can access the whole region. */
if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH) {
- device_printf(dev, "memory region width %ld too small\n",
+ device_printf(dev, "memory region width %jd too small\n",
rman_get_size(sc->mem_res));
bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
return (ENXIO);
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c
index 2cdf908..34a8320 100644
--- a/sys/dev/acpica/acpi_timer.c
+++ b/sys/dev/acpica/acpi_timer.c
@@ -152,7 +152,7 @@ acpi_timer_identify(driver_t *driver, device_t parent)
rlen = AcpiGbl_FADT.PmTimerLength;
rstart = AcpiGbl_FADT.XPmTimerBlock.Address;
if (bus_set_resource(dev, rtype, rid, rstart, rlen))
- device_printf(dev, "couldn't set resource (%s 0x%lx+0x%lx)\n",
+ device_printf(dev, "couldn't set resource (%s 0x%jx+0x%jx)\n",
(rtype == SYS_RES_IOPORT) ? "port" : "mem", rstart, rlen);
return_VOID;
}
diff --git a/sys/dev/advansys/adv_isa.c b/sys/dev/advansys/adv_isa.c
index 00381a3..3b3a45b 100644
--- a/sys/dev/advansys/adv_isa.c
+++ b/sys/dev/advansys/adv_isa.c
@@ -136,7 +136,7 @@ adv_isa_probe(device_t dev)
|| (iobase != adv_isa_ioports[port_index])) {
if (bootverbose)
device_printf(dev,
- "Invalid baseport of 0x%lx specified. "
+ "Invalid baseport of 0x%jx specified. "
"Nearest valid baseport is 0x%x. Failing "
"probe.\n", iobase,
(port_index <= max_port_index) ?
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index 25ebbf7..8341f66 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -527,7 +527,7 @@ ahci_alloc_resource(device_t dev, device_t child, int type, int *rid,
{
struct ahci_controller *ctlr = device_get_softc(dev);
struct resource *res;
- long st;
+ rman_res_t st;
int offset, size, unit;
unit = (intptr_t)device_get_ivars(child);
diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h
index 86bdf2b..868a376 100644
--- a/sys/dev/ahci/ahci.h
+++ b/sys/dev/ahci/ahci.h
@@ -597,6 +597,7 @@ enum ahci_err_type {
#define AHCI_Q_1MSI 0x00020000
#define AHCI_Q_FORCE_PI 0x00040000
#define AHCI_Q_RESTORE_CAP 0x00080000
+#define AHCI_Q_NOMSIX 0x00100000
#define AHCI_Q_BIT_STRING \
"\020" \
@@ -619,7 +620,8 @@ enum ahci_err_type {
"\021ABAR0" \
"\0221MSI" \
"\023FORCE_PI" \
- "\024RESTORE_CAP"
+ "\024RESTORE_CAP" \
+ "\025NOMSIX"
int ahci_attach(device_t dev);
int ahci_detach(device_t dev);
diff --git a/sys/dev/ahci/ahci_pci.c b/sys/dev/ahci/ahci_pci.c
index 5c236ce..57f7ea9 100644
--- a/sys/dev/ahci/ahci_pci.c
+++ b/sys/dev/ahci/ahci_pci.c
@@ -293,7 +293,7 @@ static const struct {
{0x11851039, 0x00, "SiS 968", 0},
{0x01861039, 0x00, "SiS 968", 0},
{0xa01c177d, 0x00, "ThunderX", AHCI_Q_ABAR0|AHCI_Q_1MSI},
- {0x00311c36, 0x00, "Annapurna", AHCI_Q_FORCE_PI|AHCI_Q_RESTORE_CAP},
+ {0x00311c36, 0x00, "Annapurna", AHCI_Q_FORCE_PI|AHCI_Q_RESTORE_CAP|AHCI_Q_NOMSIX},
{0x00000000, 0x00, NULL, 0}
};
@@ -437,6 +437,9 @@ ahci_pci_attach(device_t dev)
&ctlr->r_rid, RF_ACTIVE)))
return ENXIO;
+ if (ctlr->quirks & AHCI_Q_NOMSIX)
+ msix_count = 0;
+
/* Read MSI-x BAR IDs if supported */
if (msix_count > 0) {
error = ahci_pci_read_msix_bars(dev, &table_bar, &pba_bar);
diff --git a/sys/dev/amdsbwd/amdsbwd.c b/sys/dev/amdsbwd/amdsbwd.c
index 7221db4..207d0b9 100644
--- a/sys/dev/amdsbwd/amdsbwd.c
+++ b/sys/dev/amdsbwd/amdsbwd.c
@@ -106,6 +106,8 @@ __FBSDID("$FreeBSD$");
/* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1. */
#define AMDSB_SMBUS_DEVID 0x43851002
#define AMDSB8_SMBUS_REVID 0x40
+#define AMDHUDSON_SMBUS_DEVID 0x780b1022
+#define AMDKERNCZ_SMBUS_DEVID 0x790b1022
#define amdsbwd_verbose_printf(dev, ...) \
do { \
@@ -279,7 +281,9 @@ amdsbwd_identify(driver_t *driver, device_t parent)
smb_dev = pci_find_bsf(0, 20, 0);
if (smb_dev == NULL)
return;
- if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID)
+ if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
+ pci_get_devid(smb_dev) != AMDHUDSON_SMBUS_DEVID &&
+ pci_get_devid(smb_dev) != AMDKERNCZ_SMBUS_DEVID)
return;
child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
@@ -309,10 +313,12 @@ amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
*addr <<= 8;
*addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
}
+ *addr &= ~0x07u;
+
/* Set watchdog timer tick to 1s. */
val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
val &= ~AMDSB_WDT_RES_MASK;
- val |= AMDSB_WDT_RES_10MS;
+ val |= AMDSB_WDT_RES_1S;
pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
/* Enable watchdog device (in stopped state). */
@@ -372,7 +378,7 @@ amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val);
#endif
- device_set_desc(dev, "AMD SB8xx Watchdog Timer");
+ device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
}
static int
@@ -404,7 +410,8 @@ amdsbwd_probe(device_t dev)
smb_dev = pci_find_bsf(0, 20, 0);
KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
- if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
+ if (pci_get_devid(smb_dev) == AMDSB_SMBUS_DEVID &&
+ pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
amdsbwd_probe_sb7xx(dev, res, &addr);
else
amdsbwd_probe_sb8xx(dev, res, &addr);
@@ -440,10 +447,7 @@ amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
smb_dev = pci_find_bsf(0, 20, 0);
KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
- if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
- sc->ms_per_tick = 10;
- else
- sc->ms_per_tick = 1000;
+ sc->ms_per_tick = 1000;
sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->rid_ctrl, RF_ACTIVE);
diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c
index 3cf7fce..cabb99a 100644
--- a/sys/dev/arcmsr/arcmsr.c
+++ b/sys/dev/arcmsr/arcmsr.c
@@ -872,7 +872,7 @@ static void arcmsr_srb_timeout(void *arg)
ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
if(srb->srb_state == ARCMSR_SRB_START)
{
- cmd = srb->pccb->csio.cdb_io.cdb_bytes[0];
+ cmd = scsiio_cdb_ptr(&srb->pccb->csio)[0];
srb->srb_state = ARCMSR_SRB_TIMEOUT;
srb->pccb->ccb_h.status |= CAM_CMD_TIMEOUT;
arcmsr_srb_complete(srb, 1);
@@ -997,7 +997,7 @@ static void arcmsr_build_srb(struct CommandControlBlock *srb,
arcmsr_cdb->LUN = pccb->ccb_h.target_lun;
arcmsr_cdb->Function = 1;
arcmsr_cdb->CdbLength = (u_int8_t)pcsio->cdb_len;
- bcopy(pcsio->cdb_io.cdb_bytes, arcmsr_cdb->Cdb, pcsio->cdb_len);
+ bcopy(scsiio_cdb_ptr(pcsio), arcmsr_cdb->Cdb, pcsio->cdb_len);
if(nseg != 0) {
struct AdapterControlBlock *acb = srb->acb;
bus_dmasync_op_t op;
@@ -2453,10 +2453,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb *p
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
- u_int32_t controlcode = (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[5] << 24 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[6] << 16 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[7] << 8 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[8];
+ uint8_t *ptr = scsiio_cdb_ptr(&pccb->csio);
+ u_int32_t controlcode = (u_int32_t ) ptr[5] << 24 |
+ (u_int32_t ) ptr[6] << 16 |
+ (u_int32_t ) ptr[7] << 8 |
+ (u_int32_t ) ptr[8];
/* 4 bytes: Areca io control code */
if ((pccb->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
buffer = pccb->csio.data_ptr;
@@ -2683,7 +2684,7 @@ static void arcmsr_execute_srb(void *arg, bus_dma_segment_t *dm_segs, int nseg,
if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
u_int8_t block_cmd, cmd;
- cmd = pccb->csio.cdb_io.cdb_bytes[0];
+ cmd = scsiio_cdb_ptr(&pccb->csio)[0];
block_cmd = cmd & 0x0f;
if(block_cmd == 0x08 || block_cmd == 0x0a) {
printf("arcmsr%d:block 'read/write' command "
@@ -2800,7 +2801,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
return;
}
pccb->ccb_h.status |= CAM_REQ_CMP;
- switch (pccb->csio.cdb_io.cdb_bytes[0]) {
+ switch (scsiio_cdb_ptr(&pccb->csio)[0]) {
case INQUIRY: {
unsigned char inqdata[36];
char *buffer = pccb->csio.data_ptr;
@@ -2853,6 +2854,12 @@ static void arcmsr_action(struct cam_sim *psim, union ccb *pccb)
int target = pccb->ccb_h.target_id;
int error;
+ if (pccb->ccb_h.flags & CAM_CDB_PHYS) {
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ return;
+ }
+
if(target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, pccb);
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
index 6b825c0..1c81c6f 100644
--- a/sys/dev/ata/ata-lowlevel.c
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -851,7 +851,7 @@ ata_pio_read(struct ata_request *request, int length)
panic("ata_pio_read: Unsupported CAM data type %x\n",
(request->ccb->ccb_h.flags & CAM_DATA_MASK));
- /* We may have extra byte already red but not stored. */
+ /* We may have extra byte already read but not stored. */
if (resid) {
addr[0] = buf[1];
addr++;
diff --git a/sys/dev/ath/if_ath_lna_div.c b/sys/dev/ath/if_ath_lna_div.c
index f0a33a5..5c770c0 100644
--- a/sys/dev/ath/if_ath_lna_div.c
+++ b/sys/dev/ath/if_ath_lna_div.c
@@ -766,7 +766,7 @@ ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
/* Short scan check */
if (antcomb->scan && antcomb->alt_good) {
- if (time_after(ticks, antcomb->scan_start_time +
+ if (ieee80211_time_after(ticks, antcomb->scan_start_time +
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
short_scan = AH_TRUE;
else
diff --git a/sys/dev/atkbdc/atkbdc_subr.c b/sys/dev/atkbdc/atkbdc_subr.c
index 28730c6..436d97a 100644
--- a/sys/dev/atkbdc/atkbdc_subr.c
+++ b/sys/dev/atkbdc/atkbdc_subr.c
@@ -63,7 +63,7 @@ atkbdc_print_child(device_t bus, device_t dev)
retval += printf(" flags 0x%x", flags);
irq = bus_get_resource_start(dev, SYS_RES_IRQ, kbdcdev->rid);
if (irq != 0)
- retval += printf(" irq %ld", irq);
+ retval += printf(" irq %jd", irq);
retval += bus_print_child_footer(bus, dev);
return (retval);
diff --git a/sys/dev/bhnd/bhnd.c b/sys/dev/bhnd/bhnd.c
index 674094a..860d58d 100644
--- a/sys/dev/bhnd/bhnd.c
+++ b/sys/dev/bhnd/bhnd.c
@@ -451,7 +451,7 @@ bhnd_generic_print_child(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL) {
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
}
retval += printf(" at core %u", bhnd_get_core_index(child));
@@ -499,7 +499,7 @@ bhnd_generic_probe_nomatch(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL)
- resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
printf(" at core %u (no driver attached)\n",
bhnd_get_core_index(child));
diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c
index 238d4ee..43580b7 100644
--- a/sys/dev/bhnd/bhndb/bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhndb.c
@@ -143,9 +143,9 @@ bhndb_print_child(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL) {
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
}
retval += bus_print_child_domain(dev, child);
diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c
index 2f474d1..decef5f 100644
--- a/sys/dev/bwn/if_bwn.c
+++ b/sys/dev/bwn/if_bwn.c
@@ -2612,7 +2612,7 @@ bwn_phy_g_task_15s(struct bwn_mac *mac)
BWN_GETTIME(now);
if (bwn_has_hwpctl(mac)) {
expire = now - BWN_LO_PWRVEC_EXPIRE;
- if (time_before(lo->pwr_vec_read_time, expire)) {
+ if (ieee80211_time_before(lo->pwr_vec_read_time, expire)) {
bwn_lo_get_powervector(mac);
bwn_phy_g_dc_lookup_init(mac, 0);
}
@@ -2621,7 +2621,7 @@ bwn_phy_g_task_15s(struct bwn_mac *mac)
expire = now - BWN_LO_CALIB_EXPIRE;
TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
- if (!time_before(cal->calib_time, expire))
+ if (!ieee80211_time_before(cal->calib_time, expire))
continue;
if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
@@ -6149,7 +6149,7 @@ bwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
nanouptime(&ts);
- if (time_before(lo->txctl_measured_time,
+ if (ieee80211_time_before(lo->txctl_measured_time,
(ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
bwn_lo_measure_txctl_values(mac);
@@ -9365,7 +9365,7 @@ bwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
BWN_GETTIME(now);
- if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
+ if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime))
return;
phy->nexttime = now + 2 * 1000;
diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c
index d944395..53d8e97 100644
--- a/sys/dev/bxe/bxe.c
+++ b/sys/dev/bxe/bxe.c
@@ -3063,7 +3063,7 @@ bxe_tpa_stop(struct bxe_softc *sc,
#if __FreeBSD_version >= 800000
/* specify what RSS queue was used for this flow */
m->m_pkthdr.flowid = fp->index;
- M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+ BXE_SET_FLOWID(m);
#endif
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
@@ -3352,7 +3352,7 @@ bxe_rxeof(struct bxe_softc *sc,
#if __FreeBSD_version >= 800000
/* specify what RSS queue was used for this flow */
m->m_pkthdr.flowid = fp->index;
- M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+ BXE_SET_FLOWID(m);
#endif
next_rx:
@@ -4829,6 +4829,8 @@ bxe_dump_mbuf(struct bxe_softc *sc,
}
while (m) {
+
+#if __FreeBSD_version >= 1000000
BLOGD(sc, DBG_MBUF,
"%02d: mbuf=%p m_len=%d m_flags=0x%b m_data=%p\n",
i, m, m->m_len, m->m_flags, M_FLAG_BITS, m->m_data);
@@ -4839,6 +4841,26 @@ bxe_dump_mbuf(struct bxe_softc *sc,
i, m->m_pkthdr.len, m->m_flags, M_FLAG_BITS,
(int)m->m_pkthdr.csum_flags, CSUM_BITS);
}
+#else
+ BLOGD(sc, DBG_MBUF,
+ "%02d: mbuf=%p m_len=%d m_flags=0x%b m_data=%p\n",
+ i, m, m->m_len, m->m_flags,
+ "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY", m->m_data);
+
+ if (m->m_flags & M_PKTHDR) {
+ BLOGD(sc, DBG_MBUF,
+ "%02d: - m_pkthdr: tot_len=%d flags=0x%b csum_flags=%b\n",
+ i, m->m_pkthdr.len, m->m_flags,
+ "\20\12M_BCAST\13M_MCAST\14M_FRAG"
+ "\15M_FIRSTFRAG\16M_LASTFRAG\21M_VLANTAG"
+ "\22M_PROMISC\23M_NOFREE",
+ (int)m->m_pkthdr.csum_flags,
+ "\20\1CSUM_IP\2CSUM_TCP\3CSUM_UDP\4CSUM_IP_FRAGS"
+ "\5CSUM_FRAGMENT\6CSUM_TSO\11CSUM_IP_CHECKED"
+ "\12CSUM_IP_VALID\13CSUM_DATA_VALID"
+ "\14CSUM_PSEUDO_HDR");
+ }
+#endif /* #if __FreeBSD_version >= 1000000 */
if (m->m_flags & M_EXT) {
switch (m->m_ext.ext_type) {
@@ -5222,7 +5244,9 @@ bxe_tx_encap(struct bxe_fastpath *fp, struct mbuf **m_head)
sc = fp->sc;
+#if __FreeBSD_version >= 800000
M_ASSERTPKTHDR(*m_head);
+#endif /* #if __FreeBSD_version >= 800000 */
m0 = *m_head;
rc = defragged = nbds = ovlan = vlan_off = total_pkt_size = 0;
@@ -5741,7 +5765,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
if (!sc->link_vars.link_up ||
(if_getdrvflags(ifp) &
(IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) {
- rc = drbr_enqueue_drv(ifp, tx_br, m);
+ rc = drbr_enqueue(ifp, tx_br, m);
goto bxe_tx_mq_start_locked_exit;
}
@@ -5756,7 +5780,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
next = drbr_dequeue_drv(ifp, tx_br);
} else if (drbr_needs_enqueue_drv(ifp, tx_br)) {
/* have both new and pending work, maintain packet order */
- rc = drbr_enqueue_drv(ifp, tx_br, m);
+ rc = drbr_enqueue(ifp, tx_br, m);
if (rc != 0) {
fp->eth_q_stats.tx_soft_errors++;
goto bxe_tx_mq_start_locked_exit;
@@ -5785,7 +5809,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
/* mark the TX queue as full and save the frame */
if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
/* XXX this may reorder the frame */
- rc = drbr_enqueue_drv(ifp, tx_br, next);
+ rc = drbr_enqueue(ifp, tx_br, next);
fp->eth_q_stats.mbuf_alloc_tx--;
fp->eth_q_stats.tx_frames_deferred++;
}
@@ -5837,7 +5861,8 @@ bxe_tx_mq_start(struct ifnet *ifp,
fp_index = 0; /* default is the first queue */
/* check if flowid is set */
- if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
+
+ if (BXE_VALID_FLOWID(m))
fp_index = (m->m_pkthdr.flowid % sc->num_queues);
fp = &sc->fp[fp_index];
@@ -5846,7 +5871,7 @@ bxe_tx_mq_start(struct ifnet *ifp,
rc = bxe_tx_mq_start_locked(sc, ifp, fp, m);
BXE_FP_TX_UNLOCK(fp);
} else
- rc = drbr_enqueue_drv(ifp, fp->tx_br, m);
+ rc = drbr_enqueue(ifp, fp->tx_br, m);
return (rc);
}
@@ -12845,7 +12870,7 @@ bxe_allocate_bars(struct bxe_softc *sc)
sc->bar[i].handle = rman_get_bushandle(sc->bar[i].resource);
sc->bar[i].kva = (vm_offset_t)rman_get_virtual(sc->bar[i].resource);
- BLOGI(sc, "PCI BAR%d [%02x] memory allocated: %p-%p (%ld) -> %p\n",
+ BLOGI(sc, "PCI BAR%d [%02x] memory allocated: %p-%p (%jd) -> %p\n",
i, PCIR_BAR(i),
(void *)rman_get_start(sc->bar[i].resource),
(void *)rman_get_end(sc->bar[i].resource),
@@ -15677,18 +15702,11 @@ bxe_add_sysctls(struct bxe_softc *sc)
CTLFLAG_RD, BXE_DRIVER_VERSION, 0,
"version");
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
- CTLFLAG_RD, sc->devinfo.bc_ver_str, 0,
- "bootcode version");
-
snprintf(sc->fw_ver_str, sizeof(sc->fw_ver_str), "%d.%d.%d.%d",
BCM_5710_FW_MAJOR_VERSION,
BCM_5710_FW_MINOR_VERSION,
BCM_5710_FW_REVISION_VERSION,
BCM_5710_FW_ENGINEERING_VERSION);
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
- CTLFLAG_RD, sc->fw_ver_str, 0,
- "firmware version");
snprintf(sc->mf_mode_str, sizeof(sc->mf_mode_str), "%s",
((sc->devinfo.mf_info.mf_mode == SINGLE_FUNCTION) ? "Single" :
@@ -15696,32 +15714,58 @@ bxe_add_sysctls(struct bxe_softc *sc)
(sc->devinfo.mf_info.mf_mode == MULTI_FUNCTION_SI) ? "MF-SI" :
(sc->devinfo.mf_info.mf_mode == MULTI_FUNCTION_AFEX) ? "MF-AFEX" :
"Unknown"));
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
- CTLFLAG_RD, sc->mf_mode_str, 0,
- "multifunction mode");
-
SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "mf_vnics",
CTLFLAG_RD, &sc->devinfo.mf_info.vnics_per_port, 0,
"multifunction vnics per port");
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
- CTLFLAG_RD, sc->mac_addr_str, 0,
- "mac address");
-
snprintf(sc->pci_link_str, sizeof(sc->pci_link_str), "%s x%d",
((sc->devinfo.pcie_link_speed == 1) ? "2.5GT/s" :
(sc->devinfo.pcie_link_speed == 2) ? "5.0GT/s" :
(sc->devinfo.pcie_link_speed == 4) ? "8.0GT/s" :
"???GT/s"),
sc->devinfo.pcie_link_width);
+
+ sc->debug = bxe_debug;
+
+#if __FreeBSD_version >= 900000
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
+ CTLFLAG_RD, sc->devinfo.bc_ver_str, 0,
+ "bootcode version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
+ CTLFLAG_RD, sc->fw_ver_str, 0,
+ "firmware version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
+ CTLFLAG_RD, sc->mf_mode_str, 0,
+ "multifunction mode");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
+ CTLFLAG_RD, sc->mac_addr_str, 0,
+ "mac address");
SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pci_link",
CTLFLAG_RD, sc->pci_link_str, 0,
"pci link status");
-
- sc->debug = bxe_debug;
SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "debug",
CTLFLAG_RW, &sc->debug,
"debug logging mode");
+#else
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
+ CTLFLAG_RD, &sc->devinfo.bc_ver_str, 0,
+ "bootcode version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
+ CTLFLAG_RD, &sc->fw_ver_str, 0,
+ "firmware version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
+ CTLFLAG_RD, &sc->mf_mode_str, 0,
+ "multifunction mode");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
+ CTLFLAG_RD, &sc->mac_addr_str, 0,
+ "mac address");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pci_link",
+ CTLFLAG_RD, &sc->pci_link_str, 0,
+ "pci link status");
+ SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "debug",
+ CTLFLAG_RW, &sc->debug, 0,
+ "debug logging mode");
+#endif /* #if __FreeBSD_version >= 900000 */
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "trigger_grcdump",
CTLTYPE_UINT | CTLFLAG_RW, sc, 0,
diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h
index e87c65b..73f72ce 100644
--- a/sys/dev/bxe/bxe.h
+++ b/sys/dev/bxe/bxe.h
@@ -2271,6 +2271,17 @@ void bxe_dump_mem(struct bxe_softc *sc, char *tag,
void bxe_dump_mbuf_data(struct bxe_softc *sc, char *pTag,
struct mbuf *m, uint8_t contents);
+
+#if __FreeBSD_version >= 800000
+#if __FreeBSD_version >= 1000000
+#define BXE_SET_FLOWID(m) M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE)
+#define BXE_VALID_FLOWID(m) (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
+#else
+#define BXE_VALID_FLOWID(m) ((m->m_flags & M_FLOWID) != 0)
+#define BXE_SET_FLOWID(m) m->m_flags |= M_FLOWID
+#endif
+#endif /* #if __FreeBSD_version >= 800000 */
+
/***********/
/* INLINES */
/***********/
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c
index 5d7704a..f9f7816 100644
--- a/sys/dev/cardbus/cardbus_cis.c
+++ b/sys/dev/cardbus/cardbus_cis.c
@@ -485,7 +485,8 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
"to read CIS.\n");
return (NULL);
}
- DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
+ DEVPRINTF((cbdev, "CIS Mapped to %#jx\n",
+ rman_get_start(res)));
/* Flip to the right ROM image if CIS is in ROM */
if (space == PCIM_CIS_ASI_ROM) {
diff --git a/sys/dev/ctau/if_ct.c b/sys/dev/ctau/if_ct.c
index da8d32c..a3df2a8 100644
--- a/sys/dev/ctau/if_ct.c
+++ b/sys/dev/ctau/if_ct.c
@@ -459,7 +459,7 @@ static int ct_probe (device_t dev)
}
if (!ct_probe_board (iobase, -1, -1)) {
- printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
+ printf ("ct%d: probing for Tau-ISA at %jx faild\n", unit, iobase);
return ENXIO;
}
@@ -632,7 +632,7 @@ static int ct_attach (device_t dev)
ct_ln[2] = '0' + unit;
mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
if (! probe_irq (b, irq)) {
- printf ("ct%d: irq %ld not functional\n", unit, irq);
+ printf ("ct%d: irq %jd not functional\n", unit, irq);
bd->board = 0;
adapter [unit] = 0;
free (b, M_DEVBUF);
@@ -651,7 +651,7 @@ static int ct_attach (device_t dev)
if (bus_setup_intr (dev, bd->irq_res,
INTR_TYPE_NET|INTR_MPSAFE,
NULL, ct_intr, bd, &bd->intrhand)) {
- printf ("ct%d: Can't setup irq %ld\n", unit, irq);
+ printf ("ct%d: Can't setup irq %jd\n", unit, irq);
bd->board = 0;
adapter [unit] = 0;
free (b, M_DEVBUF);
diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c
index a622fcf..c83bd66 100644
--- a/sys/dev/cxgb/cxgb_sge.c
+++ b/sys/dev/cxgb/cxgb_sge.c
@@ -2976,11 +2976,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
#if defined(INET6) || defined(INET)
/* Flush LRO */
- while (!SLIST_EMPTY(&lro_ctrl->lro_active)) {
- struct lro_entry *queued = SLIST_FIRST(&lro_ctrl->lro_active);
- SLIST_REMOVE_HEAD(&lro_ctrl->lro_active, next);
- tcp_lro_flush(lro_ctrl, queued);
- }
+ tcp_lro_flush_all(lro_ctrl);
#endif
if (sleeping)
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h
index ee14712..2193142 100644
--- a/sys/dev/cxgbe/adapter.h
+++ b/sys/dev/cxgbe/adapter.h
@@ -246,12 +246,10 @@ struct vi_info {
int rsrv_noflowq; /* Reserve queue 0 for non-flowid packets */
int nrxq; /* # of rx queues */
int first_rxq; /* index of first rx queue */
-#ifdef TCP_OFFLOAD
int nofldtxq; /* # of offload tx queues */
int first_ofld_txq; /* index of first offload tx queue */
int nofldrxq; /* # of offload rx queues */
int first_ofld_rxq; /* index of first offload rx queue */
-#endif
int tmr_idx;
int pktc_idx;
int qsize_rxq;
@@ -311,9 +309,7 @@ struct cluster_layout {
struct cluster_metadata {
u_int refcount;
-#ifdef INVARIANTS
struct fl_sdesc *sd; /* For debug only. Could easily be stale */
-#endif
};
struct fl_sdesc {
@@ -571,7 +567,6 @@ iq_to_rxq(struct sge_iq *iq)
}
-#ifdef TCP_OFFLOAD
/* ofld_rxq: SGE ingress queue + SGE free list + miscellaneous items */
struct sge_ofld_rxq {
struct sge_iq iq; /* MUST be first */
@@ -584,7 +579,6 @@ iq_to_ofld_rxq(struct sge_iq *iq)
return (__containerof(iq, struct sge_ofld_rxq, iq));
}
-#endif
struct wrqe {
STAILQ_ENTRY(wrqe) link;
@@ -636,7 +630,6 @@ struct sge_wrq {
} __aligned(CACHE_LINE_SIZE);
-#ifdef DEV_NETMAP
struct sge_nm_rxq {
struct vi_info *vi;
@@ -691,19 +684,14 @@ struct sge_nm_txq {
bus_addr_t ba;
int iqidx;
} __aligned(CACHE_LINE_SIZE);
-#endif
struct sge {
int nrxq; /* total # of Ethernet rx queues */
int ntxq; /* total # of Ethernet tx tx queues */
-#ifdef TCP_OFFLOAD
int nofldrxq; /* total # of TOE rx queues */
int nofldtxq; /* total # of TOE tx queues */
-#endif
-#ifdef DEV_NETMAP
int nnmrxq; /* total # of netmap rx queues */
int nnmtxq; /* total # of netmap tx queues */
-#endif
int niq; /* total # of ingress queues */
int neq; /* total # of egress queues */
@@ -712,14 +700,10 @@ struct sge {
struct sge_wrq *ctrlq; /* Control queues */
struct sge_txq *txq; /* NIC tx queues */
struct sge_rxq *rxq; /* NIC rx queues */
-#ifdef TCP_OFFLOAD
struct sge_wrq *ofld_txq; /* TOE tx queues */
struct sge_ofld_rxq *ofld_rxq; /* TOE rx queues */
-#endif
-#ifdef DEV_NETMAP
struct sge_nm_txq *nm_txq; /* netmap tx queues */
struct sge_nm_rxq *nm_rxq; /* netmap rx queues */
-#endif
uint16_t iq_start;
int eq_start;
@@ -778,20 +762,16 @@ struct adapter {
struct port_info *port[MAX_NPORTS];
uint8_t chan_map[MAX_NCHAN];
-#ifdef TCP_OFFLOAD
void *tom_softc; /* (struct tom_data *) */
struct tom_tunables tt;
void *iwarp_softc; /* (struct c4iw_dev *) */
void *iscsi_ulp_softc; /* (struct cxgbei_data *) */
-#endif
struct l2t_data *l2t; /* L2 table */
struct tid_info tids;
uint16_t doorbells;
-#ifdef TCP_OFFLOAD
int offload_map; /* ports with IFCAP_TOE enabled */
int active_ulds; /* ULDs activated on this adapter */
-#endif
int flags;
int debug_flags;
@@ -840,11 +820,9 @@ struct adapter {
fw_msg_handler_t fw_msg_handler[7]; /* NUM_FW6_TYPES */
cpl_handler_t cpl_handler[0xef]; /* NUM_CPL_CMDS */
-#ifdef INVARIANTS
const char *last_op;
const void *last_op_thr;
int last_op_flags;
-#endif
int sc_do_rxcopy;
};
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c
index 92104c8..588f6fd 100644
--- a/sys/dev/cxgbe/common/t4_hw.c
+++ b/sys/dev/cxgbe/common/t4_hw.c
@@ -5615,6 +5615,7 @@ void t4_get_port_stats_offset(struct adapter *adap, int idx,
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
+ u32 stat_ctl;
#define GET_STAT(name) \
t4_read_reg64(adap, \
@@ -5622,6 +5623,8 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L)))
#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
+ stat_ctl = t4_read_reg(adap, A_MPS_STAT_CTL);
+
p->tx_pause = GET_STAT(TX_PORT_PAUSE);
p->tx_octets = GET_STAT(TX_PORT_BYTES);
p->tx_frames = GET_STAT(TX_PORT_FRAMES);
@@ -5646,6 +5649,12 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
p->tx_ppp6 = GET_STAT(TX_PORT_PPP6);
p->tx_ppp7 = GET_STAT(TX_PORT_PPP7);
+ if (stat_ctl & F_COUNTPAUSESTATTX) {
+ p->tx_frames -= p->tx_pause;
+ p->tx_octets -= p->tx_pause * 64;
+ p->tx_mcast_frames -= p->tx_pause;
+ }
+
p->rx_pause = GET_STAT(RX_PORT_PAUSE);
p->rx_octets = GET_STAT(RX_PORT_BYTES);
p->rx_frames = GET_STAT(RX_PORT_FRAMES);
@@ -5674,6 +5683,12 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
p->rx_ppp6 = GET_STAT(RX_PORT_PPP6);
p->rx_ppp7 = GET_STAT(RX_PORT_PPP7);
+ if (stat_ctl & F_COUNTPAUSESTATRX) {
+ p->rx_frames -= p->rx_pause;
+ p->rx_octets -= p->rx_pause * 64;
+ p->rx_mcast_frames -= p->rx_pause;
+ }
+
p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
diff --git a/sys/dev/cxgbe/firmware/t4fw_cfg.txt b/sys/dev/cxgbe/firmware/t4fw_cfg.txt
index 0e13122..43820a0 100644
--- a/sys/dev/cxgbe/firmware/t4fw_cfg.txt
+++ b/sys/dev/cxgbe/firmware/t4fw_cfg.txt
@@ -10,7 +10,7 @@
[global]
rss_glb_config_mode = basicvirtual
- rss_glb_config_options = tnlmapen, hashtoeplitz, tnlalllkp
+ rss_glb_config_options = tnlmapen,hashtoeplitz,tnlalllkp
sge_timer_value = 1, 5, 10, 50, 100, 200 # usecs
@@ -20,61 +20,82 @@
# disable TP_PARA_REG3.RxFragEn
reg[0x7d6c] = 0x00000000/0x00007000
- # TP_SHIFT_CNT
- reg[0x7dc0] = 0x62f8849
+ reg[0x7dc0] = 0x0e2f8849 # TP_SHIFT_CNT
filterMode = fragmentation, mpshittype, protocol, vlan, port, fcoe
filterMask = protocol, fcoe
- # TP rx and tx channels (0 = auto).
+ tp_pmrx = 36, 512
+ tp_pmrx_pagesize = 64K
+
+ # TP number of RX channels (0 = auto)
tp_nrxch = 0
- tp_ntxch = 0
- # TP rx and tx payload memory (% of the total EDRAM + DDR3).
- tp_pmrx = 38, 512
- tp_pmtx = 60, 512
- tp_pmrx_pagesize = 64K
+ tp_pmtx = 46, 512
tp_pmtx_pagesize = 64K
- # cluster, lan, or wan.
- tp_tcptuning = lan
+ # TP number of TX channels (0 = auto)
+ tp_ntxch = 0
# TP OFLD MTUs
tp_mtus = 88, 256, 512, 576, 808, 1024, 1280, 1488, 1500, 2002, 2048, 4096, 4352, 8192, 9000, 9600
+ # cluster, lan, or wan.
+ tp_tcptuning = lan
+
# PFs 0-3. These get 8 MSI/8 MSI-X vectors each. VFs are supported by
-# these 4 PFs only. Not used here at all.
+# these 4 PFs only.
[function "0"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "0/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x1
[function "1"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "1/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x2
[function "2"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "2/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x4
[function "3"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "3/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x8
# PF4 is the resource-rich PF that the bus/nexus driver attaches to.
# It gets 32 MSI/128 MSI-X vectors.
@@ -86,15 +107,19 @@
niqflint = 512
nethctrl = 1024
neq = 2048
- nexactf = 328
+ nexactf = 280
cmask = all
pmask = all
# driver will mask off features it won't use
- protocol = ofld
+ protocol = ofld, rddp, rdmac, iscsi_initiator_pdu, iscsi_target_pdu
tp_l2t = 4096
tp_ddp = 2
+ tp_ddp_iscsi = 2
+ tp_stag = 2
+ tp_pbl = 5
+ tp_rq = 7
# TCAM has 8K cells; each region must start at a multiple of 128 cell.
# Each entry in these categories takes 4 cells each. nhash will use the
@@ -130,6 +155,60 @@
nexactf = 8
nfilter = 16
+# For Virtual functions, we only allow NIC functionality and we only allow
+# access to one port (1 << PF). Note that because of limitations in the
+# Scatter Gather Engine (SGE) hardware which checks writes to VF KDOORBELL
+# and GTS registers, the number of Ingress and Egress Queues must be a power
+# of 2.
+#
+[function "0/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x1
+
+[function "1/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x2
+
+[function "2/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x4
+
+[function "3/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x8
+
# MPS has 192K buffer space for ingress packets from the wire as well as
# loopback path of the L2 switch.
[port "0"]
@@ -166,7 +245,7 @@
[fini]
version = 0x1
- checksum = 0x98210e18
+ checksum = 0xbec0621
#
# $FreeBSD$
#
diff --git a/sys/dev/cxgbe/firmware/t5fw_cfg.txt b/sys/dev/cxgbe/firmware/t5fw_cfg.txt
index 4ae6c99..9e16da5 100644
--- a/sys/dev/cxgbe/firmware/t5fw_cfg.txt
+++ b/sys/dev/cxgbe/firmware/t5fw_cfg.txt
@@ -10,12 +10,33 @@
[global]
rss_glb_config_mode = basicvirtual
- rss_glb_config_options = tnlmapen, hashtoeplitz, tnlalllkp
+ rss_glb_config_options = tnlmapen,hashtoeplitz,tnlalllkp
# PL_TIMEOUT register
- pl_timeout_value = 200 # the timeout value in units of us
+ pl_timeout_value = 10000 # the timeout value in units of us
- sge_timer_value = 1, 5, 10, 50, 100, 200 # usecs
+ # SGE_THROTTLE_CONTROL
+ bar2throttlecount = 500 # bar2throttlecount in us
+
+ sge_timer_value = 1, 5, 10, 50, 100, 200 # SGE_TIMER_VALUE* in usecs
+
+ reg[0x1124] = 0x00000400/0x00000400 # SGE_CONTROL2, enable VFIFO; if
+ # SGE_VFIFO_SIZE is not set, then
+ # firmware will set it up in function
+ # of number of egress queues used
+
+ reg[0x1130] = 0x00d5ffeb # SGE_DBP_FETCH_THRESHOLD, fetch
+ # threshold set to queue depth
+ # minus 128-entries for FL and HP
+ # queues, and 0xfff for LP which
+ # prompts the firmware to set it up
+ # in function of egress queues
+ # used
+
+ reg[0x113c] = 0x0002ffc0 # SGE_VFIFO_SIZE, set to 0x2ffc0 which
+ # prompts the firmware to set it up in
+ # function of number of egress queues
+ # used
# enable TP_OUT_CONFIG.IPIDSPLITMODE
reg[0x7d04] = 0x00010000/0x00010000
@@ -26,34 +47,38 @@
# enable TP_PARA_REG6.EnableCSnd
reg[0x7d78] = 0x00000400/0x00000000
- # TP_SHIFT_CNT
- reg[0x7dc0] = 0x62f8849
-
- # TP_GLOBAL_CONFIG
- reg[0x7d08] = 0x00000800/0x00000800 # set IssFromCplEnable
-
- # TP_PARA_REG0
- reg[0x7d60] = 0x06000000/0x07000000 # set InitCWND to 6
+ reg[0x7dc0] = 0x0e2f8849 # TP_SHIFT_CNT
filterMode = fragmentation, mpshittype, protocol, vlan, port, fcoe
filterMask = protocol, fcoe
- # TP rx and tx channels (0 = auto).
+ tp_pmrx = 36, 512
+ tp_pmrx_pagesize = 64K
+
+ # TP number of RX channels (0 = auto)
tp_nrxch = 0
- tp_ntxch = 0
- # TP rx and tx payload memory (% of the total EDRAM + DDR3).
- tp_pmrx = 38, 512
- tp_pmtx = 60, 512
- tp_pmrx_pagesize = 64K
+ tp_pmtx = 46, 512
tp_pmtx_pagesize = 64K
- # cluster, lan, or wan.
- tp_tcptuning = lan
+ # TP number of TX channels (0 = auto)
+ tp_ntxch = 0
# TP OFLD MTUs
tp_mtus = 88, 256, 512, 576, 808, 1024, 1280, 1488, 1500, 2002, 2048, 4096, 4352, 8192, 9000, 9600
+ # TP_GLOBAL_CONFIG
+ reg[0x7d08] = 0x00000800/0x00000800 # set IssFromCplEnable
+
+ # TP_PC_CONFIG
+ reg[0x7d48] = 0x00000000/0x00000400 # clear EnableFLMError
+
+ # TP_PARA_REG0
+ reg[0x7d60] = 0x06000000/0x07000000 # set InitCWND to 6
+
+ # cluster, lan, or wan.
+ tp_tcptuning = lan
+
# MC configuration
mc_mode_brc[0] = 1 # mc0 - 1: enable BRC, 0: enable RBC
mc_mode_brc[1] = 1 # mc1 - 1: enable BRC, 0: enable RBC
@@ -63,38 +88,58 @@
# TPT error.
# PFs 0-3. These get 8 MSI/8 MSI-X vectors each. VFs are supported by
-# these 4 PFs only. Not used here at all.
+# these 4 PFs only.
[function "0"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "0/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x1
[function "1"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "1/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x2
[function "2"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "2/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x4
[function "3"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "3/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x8
# PF4 is the resource-rich PF that the bus/nexus driver attaches to.
# It gets 32 MSI/128 MSI-X vectors.
@@ -106,15 +151,19 @@
niqflint = 512
nethctrl = 1024
neq = 2048
- nexactf = 328
+ nexactf = 456
cmask = all
pmask = all
# driver will mask off features it won't use
- protocol = ofld
+ protocol = ofld, rddp, rdmac, iscsi_initiator_pdu, iscsi_target_pdu, iscsi_t10dif
tp_l2t = 4096
tp_ddp = 2
+ tp_ddp_iscsi = 2
+ tp_stag = 2
+ tp_pbl = 5
+ tp_rq = 7
# TCAM has 8K cells; each region must start at a multiple of 128 cell.
# Each entry in these categories takes 4 cells each. nhash will use the
@@ -150,6 +199,60 @@
nexactf = 8
nfilter = 16
+# For Virtual functions, we only allow NIC functionality and we only allow
+# access to one port (1 << PF). Note that because of limitations in the
+# Scatter Gather Engine (SGE) hardware which checks writes to VF KDOORBELL
+# and GTS registers, the number of Ingress and Egress Queues must be a power
+# of 2.
+#
+[function "0/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x1
+
+[function "1/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x2
+
+[function "2/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x4
+
+[function "3/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x8
+
# MPS has 192K buffer space for ingress packets from the wire as well as
# loopback path of the L2 switch.
[port "0"]
@@ -186,7 +289,7 @@
[fini]
version = 0x1
- checksum = 0x7044b7fd
+ checksum = 0x2d7417e5
#
# $FreeBSD$
#
diff --git a/sys/dev/cxgbe/iw_cxgbe/cm.c b/sys/dev/cxgbe/iw_cxgbe/cm.c
index c884f5a..c2b72fa 100644
--- a/sys/dev/cxgbe/iw_cxgbe/cm.c
+++ b/sys/dev/cxgbe/iw_cxgbe/cm.c
@@ -80,7 +80,7 @@ static spinlock_t timeout_lock;
static void process_req(struct work_struct *ctx);
static void start_ep_timer(struct c4iw_ep *ep);
-static void stop_ep_timer(struct c4iw_ep *ep);
+static int stop_ep_timer(struct c4iw_ep *ep);
static int set_tcpinfo(struct c4iw_ep *ep);
static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc);
static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate);
@@ -96,14 +96,14 @@ static void send_mpa_req(struct c4iw_ep *ep);
static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen);
static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen);
static void close_complete_upcall(struct c4iw_ep *ep, int status);
-static int abort_connection(struct c4iw_ep *ep);
+static int send_abort(struct c4iw_ep *ep);
static void peer_close_upcall(struct c4iw_ep *ep);
static void peer_abort_upcall(struct c4iw_ep *ep);
static void connect_reply_upcall(struct c4iw_ep *ep, int status);
static int connect_request_upcall(struct c4iw_ep *ep);
static void established_upcall(struct c4iw_ep *ep);
-static void process_mpa_reply(struct c4iw_ep *ep);
-static void process_mpa_request(struct c4iw_ep *ep);
+static int process_mpa_reply(struct c4iw_ep *ep);
+static int process_mpa_request(struct c4iw_ep *ep);
static void process_peer_close(struct c4iw_ep *ep);
static void process_conn_error(struct c4iw_ep *ep);
static void process_close_complete(struct c4iw_ep *ep);
@@ -123,11 +123,11 @@ static void release_ep_resources(struct c4iw_ep *ep);
} while (0)
#define STOP_EP_TIMER(ep) \
- do { \
+ ({ \
CTR3(KTR_IW_CXGBE, "stop_ep_timer (%s:%d) ep %p", \
__func__, __LINE__, (ep)); \
stop_ep_timer(ep); \
- } while (0)
+ })
#ifdef KTR
static char *states[] = {
@@ -147,6 +147,34 @@ static char *states[] = {
};
#endif
+
+static void deref_cm_id(struct c4iw_ep_common *epc)
+{
+ epc->cm_id->rem_ref(epc->cm_id);
+ epc->cm_id = NULL;
+ set_bit(CM_ID_DEREFED, &epc->history);
+}
+
+static void ref_cm_id(struct c4iw_ep_common *epc)
+{
+ set_bit(CM_ID_REFED, &epc->history);
+ epc->cm_id->add_ref(epc->cm_id);
+}
+
+static void deref_qp(struct c4iw_ep *ep)
+{
+ c4iw_qp_rem_ref(&ep->com.qp->ibqp);
+ clear_bit(QP_REFERENCED, &ep->com.flags);
+ set_bit(QP_DEREFED, &ep->com.history);
+}
+
+static void ref_qp(struct c4iw_ep *ep)
+{
+ set_bit(QP_REFERENCED, &ep->com.flags);
+ set_bit(QP_REFED, &ep->com.history);
+ c4iw_qp_add_ref(&ep->com.qp->ibqp);
+}
+
static void
process_req(struct work_struct *ctx)
{
@@ -304,9 +332,7 @@ process_peer_close(struct c4iw_ep *ep)
disconnect = 0;
STOP_EP_TIMER(ep);
close_socket(&ep->com, 0);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
release = 1;
break;
@@ -490,6 +516,7 @@ process_close_complete(struct c4iw_ep *ep)
/* The cm_id may be null if we failed to connect */
mutex_lock(&ep->com.mutex);
+ set_bit(CLOSE_CON_RPL, &ep->com.history);
switch (ep->com.state) {
@@ -580,13 +607,14 @@ static void
process_data(struct c4iw_ep *ep)
{
struct sockaddr_in *local, *remote;
+ int disconnect = 0;
CTR5(KTR_IW_CXGBE, "%s: so %p, ep %p, state %s, sbused %d", __func__,
ep->com.so, ep, states[ep->com.state], sbused(&ep->com.so->so_rcv));
switch (state_read(&ep->com)) {
case MPA_REQ_SENT:
- process_mpa_reply(ep);
+ disconnect = process_mpa_reply(ep);
break;
case MPA_REQ_WAIT:
in_getsockaddr(ep->com.so, (struct sockaddr **)&local);
@@ -595,7 +623,7 @@ process_data(struct c4iw_ep *ep)
ep->com.remote_addr = *remote;
free(local, M_SONAME);
free(remote, M_SONAME);
- process_mpa_request(ep);
+ disconnect = process_mpa_request(ep);
break;
default:
if (sbused(&ep->com.so->so_rcv))
@@ -605,6 +633,9 @@ process_data(struct c4iw_ep *ep)
ep->com.so->so_state, sbused(&ep->com.so->so_rcv));
break;
}
+ if (disconnect)
+ c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
+
}
static void
@@ -749,9 +780,9 @@ int db_delay_usecs = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, db_delay_usecs, CTLFLAG_RWTUN, &db_delay_usecs, 0,
"Usecs to delay awaiting db fifo to drain");
-static int dack_mode = 1;
+static int dack_mode = 0;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, dack_mode, CTLFLAG_RWTUN, &dack_mode, 0,
- "Delayed ack mode (default = 1)");
+ "Delayed ack mode (default = 0)");
int c4iw_max_read_depth = 8;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_max_read_depth, CTLFLAG_RWTUN, &c4iw_max_read_depth, 0,
@@ -773,9 +804,9 @@ int c4iw_debug = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_debug, CTLFLAG_RWTUN, &c4iw_debug, 0,
"Enable debug logging (default = 0)");
-static int peer2peer;
+static int peer2peer = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, peer2peer, CTLFLAG_RWTUN, &peer2peer, 0,
- "Support peer2peer ULPs (default = 0)");
+ "Support peer2peer ULPs (default = 1)");
static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, p2p_type, CTLFLAG_RWTUN, &p2p_type, 0,
@@ -827,14 +858,16 @@ start_ep_timer(struct c4iw_ep *ep)
add_timer(&ep->timer);
}
-static void
+static int
stop_ep_timer(struct c4iw_ep *ep)
{
del_timer_sync(&ep->timer);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
c4iw_put_ep(&ep->com);
+ return 0;
}
+ return 1;
}
static enum
@@ -900,6 +933,8 @@ void _c4iw_free_ep(struct kref *kref)
epc = &ep->com;
KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list",
__func__, epc));
+ if (test_bit(QP_REFERENCED, &ep->com.flags))
+ deref_qp(ep);
kfree(ep);
}
@@ -1175,20 +1210,17 @@ static void close_complete_upcall(struct c4iw_ep *ep, int status)
CTR2(KTR_IW_CXGBE, "%s:ccu1 %1", __func__, ep);
ep->com.cm_id->event_handler(ep->com.cm_id, &event);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
set_bit(CLOSE_UPCALL, &ep->com.history);
}
CTR2(KTR_IW_CXGBE, "%s:ccuE %p", __func__, ep);
}
-static int abort_connection(struct c4iw_ep *ep)
+static int send_abort(struct c4iw_ep *ep)
{
int err;
CTR2(KTR_IW_CXGBE, "%s:abB %p", __func__, ep);
- state_set(&ep->com, ABORTING);
abort_socket(ep);
err = close_socket(&ep->com, 0);
set_bit(ABORT_CONN, &ep->com.history);
@@ -1226,9 +1258,7 @@ static void peer_abort_upcall(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pau1 %p", __func__, ep);
ep->com.cm_id->event_handler(ep->com.cm_id, &event);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
set_bit(ABORT_UPCALL, &ep->com.history);
}
CTR2(KTR_IW_CXGBE, "%s:pauE %p", __func__, ep);
@@ -1282,9 +1312,7 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
if (status < 0) {
CTR3(KTR_IW_CXGBE, "%s:cru4 %p %d", __func__, ep, status);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
}
CTR2(KTR_IW_CXGBE, "%s:cruE %p", __func__, ep);
@@ -1353,8 +1381,19 @@ static void established_upcall(struct c4iw_ep *ep)
}
-
-static void process_mpa_reply(struct c4iw_ep *ep)
+/*
+ * process_mpa_reply - process streaming mode MPA reply
+ *
+ * Returns:
+ *
+ * 0 upon success indicating a connect request was delivered to the ULP
+ * or the mpa request is incomplete but valid so far.
+ *
+ * 1 if a failure requires the caller to close the connection.
+ *
+ * 2 if a failure requires the caller to abort the connection.
+ */
+static int process_mpa_reply(struct c4iw_ep *ep)
{
struct mpa_message *mpa;
struct mpa_v2_conn_params *mpa_v2_params;
@@ -1367,17 +1406,17 @@ static void process_mpa_reply(struct c4iw_ep *ep)
struct mbuf *top, *m;
int flags = MSG_DONTWAIT;
struct uio uio;
+ int disconnect = 0;
CTR2(KTR_IW_CXGBE, "%s:pmrB %p", __func__, ep);
/*
- * Stop mpa timer. If it expired, then the state has
- * changed and we bail since ep_timeout already aborted
- * the connection.
+ * Stop mpa timer. If it expired, then
+ * we ignore the MPA reply. process_timeout()
+ * will abort the connection.
*/
- STOP_EP_TIMER(ep);
- if (state_read(&ep->com) != MPA_REQ_SENT)
- return;
+ if (STOP_EP_TIMER(ep))
+ return 0;
uio.uio_resid = 1000000;
uio.uio_td = ep->com.thread;
@@ -1389,7 +1428,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pmr1 %p", __func__, ep);
START_EP_TIMER(ep);
- return;
+ return 0;
}
err = -err;
CTR2(KTR_IW_CXGBE, "%s:pmr2 %p", __func__, ep);
@@ -1417,7 +1456,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR3(KTR_IW_CXGBE, "%s:pmr5 %p %d", __func__, ep,
ep->mpa_pkt_len + m->m_len);
err = (-EINVAL);
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1435,8 +1474,9 @@ static void process_mpa_reply(struct c4iw_ep *ep)
/*
* if we don't even have the mpa message, then bail.
*/
- if (ep->mpa_pkt_len < sizeof(*mpa))
- return;
+ if (ep->mpa_pkt_len < sizeof(*mpa)) {
+ return 0;
+ }
mpa = (struct mpa_message *) ep->mpa_pkt;
/* Validate MPA header. */
@@ -1447,14 +1487,14 @@ static void process_mpa_reply(struct c4iw_ep *ep)
printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d, "
" Received = %d\n", __func__, mpa_rev, mpa->revision);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {
CTR2(KTR_IW_CXGBE, "%s:pmr7 %p", __func__, ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
plen = ntohs(mpa->private_data_size);
@@ -1466,7 +1506,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pmr8 %p", __func__, ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1475,8 +1515,9 @@ static void process_mpa_reply(struct c4iw_ep *ep)
if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
CTR2(KTR_IW_CXGBE, "%s:pmr9 %p", __func__, ep);
+ STOP_EP_TIMER(ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
ep->plen = (u8) plen;
@@ -1488,14 +1529,14 @@ static void process_mpa_reply(struct c4iw_ep *ep)
if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) {
CTR2(KTR_IW_CXGBE, "%s:pmra %p", __func__, ep);
- return;
+ return 0;
}
if (mpa->flags & MPA_REJECT) {
CTR2(KTR_IW_CXGBE, "%s:pmrb %p", __func__, ep);
err = -ECONNREFUSED;
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1638,6 +1679,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
err = -ENOMEM;
+ disconnect = 1;
goto out;
}
@@ -1658,19 +1700,33 @@ static void process_mpa_reply(struct c4iw_ep *ep)
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
err = -ENOMEM;
+ disconnect = 1;
goto out;
}
goto out;
+err_stop_timer:
+ STOP_EP_TIMER(ep);
err:
- state_set(&ep->com, ABORTING);
- abort_connection(ep);
+ disconnect = 2;
out:
connect_reply_upcall(ep, err);
CTR2(KTR_IW_CXGBE, "%s:pmrE %p", __func__, ep);
- return;
+ return disconnect;
}
-static void
+/*
+ * process_mpa_request - process streaming mode MPA request
+ *
+ * Returns:
+ *
+ * 0 upon success indicating a connect request was delivered to the ULP
+ * or the mpa request is incomplete but valid so far.
+ *
+ * 1 if a failure requires the caller to close the connection.
+ *
+ * 2 if a failure requires the caller to abort the connection.
+ */
+static int
process_mpa_request(struct c4iw_ep *ep)
{
struct mpa_message *mpa;
@@ -1684,7 +1740,7 @@ process_mpa_request(struct c4iw_ep *ep)
CTR3(KTR_IW_CXGBE, "%s: ep %p, state %s", __func__, ep, states[state]);
if (state != MPA_REQ_WAIT)
- return;
+ return 0;
iov.iov_base = &ep->mpa_pkt[ep->mpa_pkt_len];
iov.iov_len = sizeof(ep->mpa_pkt) - ep->mpa_pkt_len;
@@ -1698,13 +1754,10 @@ process_mpa_request(struct c4iw_ep *ep)
rc = soreceive(ep->com.so, NULL, &uio, NULL, NULL, &flags);
if (rc == EAGAIN)
- return;
- else if (rc) {
-abort:
- STOP_EP_TIMER(ep);
- abort_connection(ep);
- return;
- }
+ return 0;
+ else if (rc)
+ goto err_stop_timer;
+
KASSERT(uio.uio_offset > 0, ("%s: sorecieve on so %p read no data",
__func__, ep->com.so));
ep->mpa_pkt_len += uio.uio_offset;
@@ -1718,7 +1771,7 @@ abort:
/* Don't even have the MPA message. Wait for more data to arrive. */
if (ep->mpa_pkt_len < sizeof(*mpa))
- return;
+ return 0;
mpa = (struct mpa_message *) ep->mpa_pkt;
/*
@@ -1727,24 +1780,24 @@ abort:
if (mpa->revision > mpa_rev) {
log(LOG_ERR, "%s: MPA version mismatch. Local = %d,"
" Received = %d\n", __func__, mpa_rev, mpa->revision);
- goto abort;
+ goto err_stop_timer;
}
if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key)))
- goto abort;
+ goto err_stop_timer;
/*
* Fail if there's too much private data.
*/
plen = ntohs(mpa->private_data_size);
if (plen > MPA_MAX_PRIVATE_DATA)
- goto abort;
+ goto err_stop_timer;
/*
* If plen does not account for pkt size
*/
if (ep->mpa_pkt_len > (sizeof(*mpa) + plen))
- goto abort;
+ goto err_stop_timer;
ep->plen = (u8) plen;
@@ -1752,7 +1805,7 @@ abort:
* If we don't have all the pdata yet, then bail.
*/
if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
- return;
+ return 0;
/*
* If we get here we have accumulated the entire mpa
@@ -1794,7 +1847,7 @@ abort:
ep->mpa_attr.p2p_type = p2p_type;
if (set_tcpinfo(ep))
- goto abort;
+ goto err_stop_timer;
CTR5(KTR_IW_CXGBE, "%s: crc_enabled = %d, recv_marker_enabled = %d, "
"xmit_marker_enabled = %d, version = %d", __func__,
@@ -1807,12 +1860,18 @@ abort:
/* drive upcall */
mutex_lock(&ep->parent_ep->com.mutex);
if (ep->parent_ep->com.state != DEAD) {
- if(connect_request_upcall(ep)) {
- abort_connection(ep);
- }
- }else
- abort_connection(ep);
+ if(connect_request_upcall(ep))
+ goto err_out;
+ }else {
+ goto err_out;
+ }
mutex_unlock(&ep->parent_ep->com.mutex);
+ return 0;
+
+err_stop_timer:
+ STOP_EP_TIMER(ep);
+err_out:
+ return 2;
}
/*
@@ -1825,6 +1884,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
int err;
struct c4iw_ep *ep = to_ep(cm_id);
CTR2(KTR_IW_CXGBE, "%s:crcB %p", __func__, ep);
+ int disconnect = 0;
if (state_read(&ep->com) == DEAD) {
@@ -1838,7 +1898,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
if (mpa_rev == 0) {
CTR2(KTR_IW_CXGBE, "%s:crc2 %p", __func__, ep);
- abort_connection(ep);
+ disconnect = 2;
}
else {
@@ -1847,6 +1907,8 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
err = soshutdown(ep->com.so, 3);
}
c4iw_put_ep(&ep->com);
+ if (disconnect)
+ err = c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
CTR2(KTR_IW_CXGBE, "%s:crc4 %p", __func__, ep);
return 0;
}
@@ -1859,6 +1921,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct c4iw_ep *ep = to_ep(cm_id);
struct c4iw_dev *h = to_c4iw_dev(cm_id->device);
struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);
+ int abort = 0;
CTR2(KTR_IW_CXGBE, "%s:cacB %p", __func__, ep);
@@ -1866,7 +1929,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
CTR2(KTR_IW_CXGBE, "%s:cac1 %p", __func__, ep);
err = -ECONNRESET;
- goto err;
+ goto err_out;
}
BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
@@ -1878,9 +1941,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
(conn_param->ird > c4iw_max_read_depth)) {
CTR2(KTR_IW_CXGBE, "%s:cac2 %p", __func__, ep);
- abort_connection(ep);
err = -EINVAL;
- goto err;
+ goto err_abort;
}
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
@@ -1894,9 +1956,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->ord = conn_param->ord;
send_mpa_reject(ep, conn_param->private_data,
conn_param->private_data_len);
- abort_connection(ep);
err = -ENOMEM;
- goto err;
+ goto err_abort;
}
if (conn_param->ird > ep->ord) {
@@ -1910,9 +1971,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
}
else {
CTR2(KTR_IW_CXGBE, "%s:cac7 %p", __func__, ep);
- abort_connection(ep);
err = -ENOMEM;
- goto err;
+ goto err_abort;
}
}
@@ -1932,9 +1992,10 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
}
- cm_id->add_ref(cm_id);
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.qp = qp;
+ ref_qp(ep);
//ep->ofld_txq = TOEPCB(ep->com.so)->ofld_txq;
/* bind QP to EP and move to RTS */
@@ -1956,7 +2017,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err) {
CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep);
- goto err1;
+ goto err_defef_cm_id;
}
err = send_mpa_reply(ep, conn_param->private_data,
conn_param->private_data_len);
@@ -1964,7 +2025,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err) {
CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep);
- goto err1;
+ goto err_defef_cm_id;
}
state_set(&ep->com, FPDU_MODE);
@@ -1972,11 +2033,13 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
c4iw_put_ep(&ep->com);
CTR2(KTR_IW_CXGBE, "%s:cacE %p", __func__, ep);
return 0;
-err1:
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
- cm_id->rem_ref(cm_id);
-err:
+err_defef_cm_id:
+ deref_cm_id(&ep->com);
+err_abort:
+ abort = 1;
+err_out:
+ if (abort)
+ c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
c4iw_put_ep(&ep->com);
CTR2(KTR_IW_CXGBE, "%s:cacE err %p", __func__, ep);
return err;
@@ -2028,9 +2091,9 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->ord = 1;
}
- cm_id->add_ref(cm_id);
ep->com.dev = dev;
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.qp = get_qhp(dev, conn_param->qpn);
if (!ep->com.qp) {
@@ -2039,6 +2102,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
err = -EINVAL;
goto fail2;
}
+ ref_qp(ep);
ep->com.thread = curthread;
ep->com.so = cm_id->so;
@@ -2096,7 +2160,7 @@ fail3:
CTR2(KTR_IW_CXGBE, "%s:ccb %p", __func__, ep);
fib4_free_nh_ext(RT_DEFAULT_FIB, &nh4);
fail2:
- cm_id->rem_ref(cm_id);
+ deref_cm_id(&ep->com);
c4iw_put_ep(&ep->com);
out:
CTR2(KTR_IW_CXGBE, "%s:ccE %p", __func__, ep);
@@ -2124,8 +2188,8 @@ c4iw_create_listen_ep(struct iw_cm_id *cm_id, int backlog)
goto failed;
}
- cm_id->add_ref(cm_id);
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.dev = dev;
ep->backlog = backlog;
ep->com.local_addr = cm_id->local_addr;
@@ -2150,7 +2214,7 @@ c4iw_destroy_listen_ep(struct iw_cm_id *cm_id)
cm_id->so, states[ep->com.state]);
state_set(&ep->com, DEAD);
- cm_id->rem_ref(cm_id);
+ deref_cm_id(&ep->com);
c4iw_put_ep(&ep->com);
return;
@@ -2232,7 +2296,8 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
CTR2(KTR_IW_CXGBE, "%s:ced4 %p", __func__, ep);
set_bit(EP_DISC_ABORT, &ep->com.history);
- ret = abort_connection(ep);
+ close_complete_upcall(ep, -ECONNRESET);
+ ret = send_abort(ep);
} else {
CTR2(KTR_IW_CXGBE, "%s:ced5 %p", __func__, ep);
@@ -2250,8 +2315,25 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
}
if (fatal) {
+ set_bit(EP_DISC_FAIL, &ep->com.history);
+ if (!abrupt) {
+ STOP_EP_TIMER(ep);
+ close_complete_upcall(ep, -EIO);
+ }
+ if (ep->com.qp) {
+ struct c4iw_qp_attributes attrs;
+ attrs.next_state = C4IW_QP_STATE_ERROR;
+ ret = c4iw_modify_qp(ep->com.dev, ep->com.qp,
+ C4IW_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ if (ret) {
+ CTR2(KTR_IW_CXGBE, "%s:ced7 %p", __func__, ep);
+ printf("%s - qp <- error failed!\n", __func__);
+ }
+ }
release_ep_resources(ep);
+ ep->com.state = DEAD;
CTR2(KTR_IW_CXGBE, "%s:ced6 %p", __func__, ep);
}
CTR2(KTR_IW_CXGBE, "%s:cedE %p", __func__, ep);
@@ -2290,8 +2372,13 @@ static void ep_timeout(unsigned long arg)
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
- list_add_tail(&ep->entry, &timeout_list);
- kickit = 1;
+ /*
+ * Only insert if it is not already on the list.
+ */
+ if (!ep->entry.next) {
+ list_add_tail(&ep->entry, &timeout_list);
+ kickit = 1;
+ }
}
spin_unlock(&timeout_lock);
diff --git a/sys/dev/cxgbe/iw_cxgbe/cq.c b/sys/dev/cxgbe/iw_cxgbe/cq.c
index 8710e03..b40ffc7 100644
--- a/sys/dev/cxgbe/iw_cxgbe/cq.c
+++ b/sys/dev/cxgbe/iw_cxgbe/cq.c
@@ -724,7 +724,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
default:
printf("Unexpected cqe_status 0x%x for QPID = 0x%0x\n",
CQE_STATUS(&cqe), CQE_QPID(&cqe));
- ret = -EINVAL;
+ wc->status = IB_WC_FATAL_ERR;
}
}
out:
@@ -861,6 +861,7 @@ c4iw_create_cq(struct ib_device *ibdev, struct ib_cq_init_attr *attr,
if (!mm2)
goto err4;
+ memset(&uresp, 0, sizeof(uresp));
uresp.qid_mask = rhp->rdev.cqmask;
uresp.cqid = chp->cq.cqid;
uresp.size = chp->cq.size;
@@ -871,7 +872,8 @@ c4iw_create_cq(struct ib_device *ibdev, struct ib_cq_init_attr *attr,
uresp.gts_key = ucontext->key;
ucontext->key += PAGE_SIZE;
spin_unlock(&ucontext->mmap_lock);
- ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+ ret = ib_copy_to_udata(udata, &uresp,
+ sizeof(uresp) - sizeof(uresp.reserved));
if (ret)
goto err5;
diff --git a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
index c232f70..38a8af6 100644
--- a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
+++ b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
@@ -157,7 +157,7 @@ static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
{
- return min((int)T4_MAX_NUM_STAG, (int)(rdev->adap->vres.stag.size >> 5));
+ return (int)(rdev->adap->vres.stag.size >> 5);
}
#define C4IW_WR_TO (10*HZ)
@@ -435,6 +435,7 @@ struct c4iw_qp {
atomic_t refcnt;
wait_queue_head_t wait;
struct timer_list timer;
+ int sq_sig_all;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
@@ -712,7 +713,8 @@ enum c4iw_ep_flags {
ABORT_REQ_IN_PROGRESS = 1,
RELEASE_RESOURCES = 2,
CLOSE_SENT = 3,
- TIMEOUT = 4
+ TIMEOUT = 4,
+ QP_REFERENCED = 5
};
enum c4iw_ep_history {
@@ -737,7 +739,13 @@ enum c4iw_ep_history {
EP_DISC_ABORT = 18,
CONN_RPL_UPCALL = 19,
ACT_RETRY_NOMEM = 20,
- ACT_RETRY_INUSE = 21
+ ACT_RETRY_INUSE = 21,
+ CLOSE_CON_RPL = 22,
+ EP_DISC_FAIL = 24,
+ QP_REFED = 25,
+ QP_DEREFED = 26,
+ CM_ID_REFED = 27,
+ CM_ID_DEREFED = 28
};
struct c4iw_ep_common {
diff --git a/sys/dev/cxgbe/iw_cxgbe/mem.c b/sys/dev/cxgbe/iw_cxgbe/mem.c
index f7c460a..e42aa1a 100644
--- a/sys/dev/cxgbe/iw_cxgbe/mem.c
+++ b/sys/dev/cxgbe/iw_cxgbe/mem.c
@@ -46,6 +46,12 @@ __FBSDID("$FreeBSD$");
#define T4_ULPTX_MIN_IO 32
#define C4IW_MAX_INLINE_SIZE 96
+static int mr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
+{
+ return (is_t4(dev->rdev.adap) ||
+ is_t5(dev->rdev.adap)) &&
+ length >= 8*1024*1024*1024ULL;
+}
static int
write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
{
@@ -144,8 +150,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
- if (!stag_idx)
+ if (!stag_idx) {
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.stag.fail++;
+ mutex_unlock(&rdev->stats.lock);
return -ENOMEM;
+ }
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur += 32;
if (rdev->stats.stag.cur > rdev->stats.stag.max)
@@ -250,9 +260,9 @@ static int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
int ret;
ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, mhp->attr.pdid,
- FW_RI_STAG_NSMR, mhp->attr.perms,
+ FW_RI_STAG_NSMR, mhp->attr.len ? mhp->attr.perms : 0,
mhp->attr.mw_bind_enable, mhp->attr.zbva,
- mhp->attr.va_fbo, mhp->attr.len, shift - 12,
+ mhp->attr.va_fbo, mhp->attr.len ? mhp->attr.len : -1, shift - 12,
mhp->attr.pbl_size, mhp->attr.pbl_addr);
if (ret)
return ret;
@@ -381,7 +391,7 @@ int c4iw_reregister_phys_mem(struct ib_mr *mr, int mr_rereg_mask,
struct c4iw_dev *rhp;
__be64 *page_list = NULL;
int shift = 0;
- u64 total_size;
+ u64 total_size = 0;
int npages = 0;
int ret;
@@ -416,7 +426,10 @@ int c4iw_reregister_phys_mem(struct ib_mr *mr, int mr_rereg_mask,
if (ret)
return ret;
}
-
+ if (mr_exceeds_hw_limits(rhp, total_size)) {
+ kfree(page_list);
+ return -EINVAL;
+ }
ret = reregister_mem(rhp, php, &mh, shift, npages);
kfree(page_list);
if (ret)
@@ -477,10 +490,15 @@ struct ib_mr *c4iw_register_phys_mem(struct ib_pd *pd,
if (ret)
goto err;
+ if (mr_exceeds_hw_limits(rhp, total_size)) {
+ kfree(page_list);
+ ret = -EINVAL;
+ goto err;
+ }
ret = alloc_pbl(mhp, npages);
if (ret) {
kfree(page_list);
- goto err_pbl;
+ goto err;
}
ret = write_pbl(&mhp->rhp->rdev, page_list, mhp->attr.pbl_addr,
@@ -580,6 +598,10 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
php = to_c4iw_pd(pd);
rhp = php->rhp;
+
+ if (mr_exceeds_hw_limits(rhp, length))
+ return ERR_PTR(-EINVAL);
+
mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
if (!mhp)
return ERR_PTR(-ENOMEM);
diff --git a/sys/dev/cxgbe/iw_cxgbe/qp.c b/sys/dev/cxgbe/iw_cxgbe/qp.c
index 1c0381c..3ee16b1 100644
--- a/sys/dev/cxgbe/iw_cxgbe/qp.c
+++ b/sys/dev/cxgbe/iw_cxgbe/qp.c
@@ -615,7 +615,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
fw_flags = 0;
if (wr->send_flags & IB_SEND_SOLICITED)
fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
- if (wr->send_flags & IB_SEND_SIGNALED)
+ if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all)
fw_flags |= FW_RI_COMPLETION_FLAG;
swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
switch (wr->opcode) {
@@ -673,7 +673,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
swsqe->idx = qhp->wq.sq.pidx;
swsqe->complete = 0;
- swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED);
+ swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) ||
+ qhp->sq_sig_all;
swsqe->wr_id = wr->wr_id;
init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16);
@@ -952,7 +953,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, flag);
- if (flushed) {
+ if (flushed && rchp->ibcq.comp_handler) {
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
@@ -966,7 +967,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, flag);
- if (flushed) {
+ if (flushed && schp->ibcq.comp_handler) {
spin_lock_irqsave(&schp->comp_handler_lock, flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
@@ -1530,6 +1531,7 @@ c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
qhp->attr.enable_bind = 1;
qhp->attr.max_ord = 1;
qhp->attr.max_ird = 1;
+ qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR;
spin_lock_init(&qhp->lock);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
@@ -1702,6 +1704,12 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
memset(attr, 0, sizeof *attr);
memset(init_attr, 0, sizeof *init_attr);
attr->qp_state = to_ib_qp_state(qhp->attr.state);
+ init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
+ init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
+ init_attr->cap.max_send_sge = qhp->attr.sq_max_sges;
+ init_attr->cap.max_recv_sge = qhp->attr.sq_max_sges;
+ init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE;
+ init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
return 0;
}
#endif
diff --git a/sys/dev/cxgbe/iw_cxgbe/t4.h b/sys/dev/cxgbe/iw_cxgbe/t4.h
index 023c607..b0118f9 100644
--- a/sys/dev/cxgbe/iw_cxgbe/t4.h
+++ b/sys/dev/cxgbe/iw_cxgbe/t4.h
@@ -69,7 +69,6 @@
#define T4_MAX_SQ_SIZE (T4_MAX_EQ_SIZE - 1)
#define T4_MAX_QP_DEPTH (T4_MAX_RQ_SIZE - 1)
#define T4_MAX_CQ_DEPTH (T4_MAX_IQ_SIZE - 1)
-#define T4_MAX_NUM_STAG (1<<15)
#define T4_MAX_MR_SIZE (~0ULL - 1)
#define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
#define T4_STAG_UNSET 0xffffffff
@@ -524,7 +523,7 @@ static inline void t4_swcq_consume(struct t4_cq *cq)
static inline void t4_hwcq_consume(struct t4_cq *cq)
{
cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts;
- if (++cq->cidx_inc == (cq->size >> 4)) {
+ if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == M_CIDXINC) {
u32 val;
val = SEINTARM(0) | CIDXINC(cq->cidx_inc) | TIMERREG(7) |
diff --git a/sys/dev/cxgbe/iw_cxgbe/user.h b/sys/dev/cxgbe/iw_cxgbe/user.h
index 59a1f43..d42f659 100644
--- a/sys/dev/cxgbe/iw_cxgbe/user.h
+++ b/sys/dev/cxgbe/iw_cxgbe/user.h
@@ -50,6 +50,7 @@ struct c4iw_create_cq_resp {
__u32 cqid;
__u32 size;
__u32 qid_mask;
+ __u32 reserved; /* explicit padding (optional for i386) */
};
struct c4iw_create_qp_resp {
diff --git a/sys/dev/cxgbe/offload.h b/sys/dev/cxgbe/offload.h
index 2b5e4dc..992b4cd 100644
--- a/sys/dev/cxgbe/offload.h
+++ b/sys/dev/cxgbe/offload.h
@@ -125,7 +125,6 @@ struct t4_virt_res { /* virtualized HW resources */
struct t4_range l2t;
};
-#ifdef TCP_OFFLOAD
enum {
ULD_TOM = 0,
ULD_IWARP,
@@ -152,6 +151,7 @@ struct tom_tunables {
int tx_align;
};
+#ifdef TCP_OFFLOAD
int t4_register_uld(struct uld_info *);
int t4_unregister_uld(struct uld_info *);
int t4_activate_uld(struct adapter *, int);
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 77777f8..11d4253 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -334,7 +334,8 @@ TUNABLE_INT("hw.cxgbe.nbmcaps_allowed", &t4_nbmcaps_allowed);
static int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */
TUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed);
-static int t4_switchcaps_allowed = 0;
+static int t4_switchcaps_allowed = FW_CAPS_CONFIG_SWITCH_INGRESS |
+ FW_CAPS_CONFIG_SWITCH_EGRESS;
TUNABLE_INT("hw.cxgbe.switchcaps_allowed", &t4_switchcaps_allowed);
static int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC;
@@ -343,13 +344,13 @@ TUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed);
static int t4_toecaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed);
-static int t4_rdmacaps_allowed = 0;
+static int t4_rdmacaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed);
static int t4_tlscaps_allowed = 0;
TUNABLE_INT("hw.cxgbe.tlscaps_allowed", &t4_tlscaps_allowed);
-static int t4_iscsicaps_allowed = 0;
+static int t4_iscsicaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed);
static int t4_fcoecaps_allowed = 0;
@@ -1731,29 +1732,29 @@ cxgbe_get_counter(struct ifnet *ifp, ift_counter c)
switch (c) {
case IFCOUNTER_IPACKETS:
- return (s->rx_frames - s->rx_pause);
+ return (s->rx_frames);
case IFCOUNTER_IERRORS:
return (s->rx_jabber + s->rx_runt + s->rx_too_long +
s->rx_fcs_err + s->rx_len_err);
case IFCOUNTER_OPACKETS:
- return (s->tx_frames - s->tx_pause);
+ return (s->tx_frames);
case IFCOUNTER_OERRORS:
return (s->tx_error_frames);
case IFCOUNTER_IBYTES:
- return (s->rx_octets - s->rx_pause * 64);
+ return (s->rx_octets);
case IFCOUNTER_OBYTES:
- return (s->tx_octets - s->tx_pause * 64);
+ return (s->tx_octets);
case IFCOUNTER_IMCASTS:
- return (s->rx_mcast_frames - s->rx_pause);
+ return (s->rx_mcast_frames);
case IFCOUNTER_OMCASTS:
- return (s->tx_mcast_frames - s->tx_pause);
+ return (s->tx_mcast_frames);
case IFCOUNTER_IQDROPS:
return (s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
@@ -6287,6 +6288,9 @@ mem_region_show(struct sbuf *sb, const char *name, unsigned int from,
{
unsigned int size;
+ if (from == to)
+ return;
+
size = to - from + 1;
if (size == 0)
return;
@@ -6390,13 +6394,10 @@ sysctl_meminfo(SYSCTL_HANDLER_ARGS)
md++;
if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
- if (chip_id(sc) <= CHELSIO_T5) {
- hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
+ if (chip_id(sc) <= CHELSIO_T5)
md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
- } else {
- hi = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
+ else
md->base = t4_read_reg(sc, A_LE_DB_HASH_TBL_BASE_ADDR);
- }
md->limit = 0;
} else {
md->base = 0;
@@ -9103,9 +9104,26 @@ tweak_tunables(void)
if (t4_toecaps_allowed == -1)
t4_toecaps_allowed = FW_CAPS_CONFIG_TOE;
+
+ if (t4_rdmacaps_allowed == -1) {
+ t4_rdmacaps_allowed = FW_CAPS_CONFIG_RDMA_RDDP |
+ FW_CAPS_CONFIG_RDMA_RDMAC;
+ }
+
+ if (t4_iscsicaps_allowed == -1) {
+ t4_iscsicaps_allowed = FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU |
+ FW_CAPS_CONFIG_ISCSI_TARGET_PDU |
+ FW_CAPS_CONFIG_ISCSI_T10DIF;
+ }
#else
if (t4_toecaps_allowed == -1)
t4_toecaps_allowed = 0;
+
+ if (t4_rdmacaps_allowed == -1)
+ t4_rdmacaps_allowed = 0;
+
+ if (t4_iscsicaps_allowed == -1)
+ t4_iscsicaps_allowed = 0;
#endif
#ifdef DEV_NETMAP
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index 33d8d48..daf3b8a 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -1397,13 +1397,8 @@ process_iql:
#if defined(INET) || defined(INET6)
if (iq->flags & IQ_LRO_ENABLED) {
struct lro_ctrl *lro = &rxq->lro;
- struct lro_entry *l;
- while (!SLIST_EMPTY(&lro->lro_active)) {
- l = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, l);
- }
+ tcp_lro_flush_all(lro);
}
#endif
@@ -2343,8 +2338,8 @@ eth_tx(struct mp_ring *r, u_int cidx, u_int pidx)
} else {
total++;
remaining--;
- n = write_txpkt_wr(txq, (void *)wr, m0, available);
ETHER_BPF_MTAP(ifp, m0);
+ n = write_txpkt_wr(txq, (void *)wr, m0, available);
}
MPASS(n >= 1 && n <= available && n <= SGE_MAX_WR_NDESC);
diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c
index 7789e36..41ce74c 100644
--- a/sys/dev/drm2/i915/i915_gem.c
+++ b/sys/dev/drm2/i915/i915_gem.c
@@ -1481,7 +1481,7 @@ i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- vm_page_t page, oldpage;
+ vm_page_t page;
int ret = 0;
#ifdef FREEBSD_WIP
bool write = (prot & VM_PROT_WRITE) != 0;
@@ -1504,13 +1504,10 @@ i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
* progress.
*/
if (*mres != NULL) {
- oldpage = *mres;
- vm_page_lock(oldpage);
- vm_page_remove(oldpage);
- vm_page_unlock(oldpage);
- *mres = NULL;
- } else
- oldpage = NULL;
+ vm_page_lock(*mres);
+ vm_page_remove(*mres);
+ vm_page_unlock(*mres);
+ }
VM_OBJECT_WUNLOCK(vm_obj);
retry:
ret = 0;
@@ -1590,7 +1587,6 @@ retry:
}
page->valid = VM_PAGE_BITS_ALL;
have_page:
- *mres = page;
vm_page_xbusy(page);
CTR4(KTR_DRM, "fault %p %jx %x phys %x", gem_obj, offset, prot,
@@ -1603,11 +1599,13 @@ have_page:
i915_gem_object_unpin(obj);
}
DRM_UNLOCK(dev);
- if (oldpage != NULL) {
- vm_page_lock(oldpage);
- vm_page_free(oldpage);
- vm_page_unlock(oldpage);
+ if (*mres != NULL) {
+ KASSERT(*mres != page, ("loosing %p %p", *mres, page));
+ vm_page_lock(*mres);
+ vm_page_free(*mres);
+ vm_page_unlock(*mres);
}
+ *mres = page;
vm_object_pip_wakeup(vm_obj);
return (VM_PAGER_OK);
diff --git a/sys/dev/drm2/i915/intel_pm.c b/sys/dev/drm2/i915/intel_pm.c
index ab9eee4..ddab457 100644
--- a/sys/dev/drm2/i915/intel_pm.c
+++ b/sys/dev/drm2/i915/intel_pm.c
@@ -3672,9 +3672,39 @@ static void gen6_init_clock_gating(struct drm_device *dev)
ILK_DPARBUNIT_CLOCK_GATE_ENABLE |
ILK_DPFDUNIT_CLOCK_GATE_ENABLE);
+
+#ifdef FREEBSD_WIP
+ /* NOTE Linux<->FreeBSD: Disable GEN6_MBCTL write.
+ *
+ * This arrived in Linux 3.6 in commit
+ * b4ae3f22d238617ca11610b29fde16cf8c0bc6e0 and causes significantly
+ * increased power consumption after kldloading i915kms.ko on FreeBSD
+ * on (some) Sandy Bridge laptops. A Thinkpad X220 reported about 11W
+ * after booting while idle at the vt(4) console and about double that
+ * after loading the driver.
+ *
+ * There were reports in Linux of increased consumption after a suspend
+ * and resume cycle due to that change.
+ *
+ * Linux bug reports:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=54089
+ * https://bugzilla.kernel.org/show_bug.cgi?id=58971
+ *
+ * This suspend and resume issue is reportedly fixed in Linux with
+ * commits 7dcd2677ea912573d9ed4bcd629b0023b2d11505 and
+ * 7dcd2677ea912573d9ed4bcd629b0023b2d11505 (Linux 3.11). However, I
+ * found that those changes did not help on FreeBSD, where increased
+ * power consumption is observed after loading i915kms.ko without
+ * suspending and resuming.
+ *
+ * This workaround should be removed after updating to a future Linux
+ * i915 version and verifying normal power consumption on Sandy Bridge.
+ */
+
/* WaMbcDriverBootEnable */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
+#endif /* FREEBSD_WIP */
for_each_pipe(pipe) {
I915_WRITE(DSPCNTR(pipe),
diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c
index 5d72d97..96ebeca 100644
--- a/sys/dev/drm2/ttm/ttm_bo_vm.c
+++ b/sys/dev/drm2/ttm/ttm_bo_vm.c
@@ -106,21 +106,18 @@ ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset,
struct ttm_buffer_object *bo = vm_obj->handle;
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_tt *ttm = NULL;
- vm_page_t m, m1, oldm;
+ vm_page_t m, m1;
int ret;
int retval = VM_PAGER_OK;
struct ttm_mem_type_manager *man =
&bdev->man[bo->mem.mem_type];
vm_object_pip_add(vm_obj, 1);
- oldm = *mres;
- if (oldm != NULL) {
- vm_page_lock(oldm);
- vm_page_remove(oldm);
- vm_page_unlock(oldm);
- *mres = NULL;
- } else
- oldm = NULL;
+ if (*mres != NULL) {
+ vm_page_lock(*mres);
+ vm_page_remove(*mres);
+ vm_page_unlock(*mres);
+ }
retry:
VM_OBJECT_WUNLOCK(vm_obj);
m = NULL;
@@ -261,14 +258,14 @@ reserve:
bo, m, m1, (uintmax_t)offset));
}
m->valid = VM_PAGE_BITS_ALL;
- *mres = m;
vm_page_xbusy(m);
-
- if (oldm != NULL) {
- vm_page_lock(oldm);
- vm_page_free(oldm);
- vm_page_unlock(oldm);
+ if (*mres != NULL) {
+ KASSERT(*mres != m, ("loosing %p %p", *mres, m));
+ vm_page_lock(*mres);
+ vm_page_free(*mres);
+ vm_page_unlock(*mres);
}
+ *mres = m;
out_io_unlock1:
ttm_mem_io_unlock(man);
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index b1b2c4a..93b33ad 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -1184,10 +1184,27 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
}
#endif
+#if __FreeBSD_version >= 1000000
+ /* HW cannot turn these on/off separately */
+ if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
+ ifp->if_capenable ^= IFCAP_RXCSUM;
+ ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
+ reinit = 1;
+ }
+ if (mask & IFCAP_TXCSUM) {
+ ifp->if_capenable ^= IFCAP_TXCSUM;
+ reinit = 1;
+ }
+ if (mask & IFCAP_TXCSUM_IPV6) {
+ ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
+ reinit = 1;
+ }
+#else
if (mask & IFCAP_HWCSUM) {
ifp->if_capenable ^= IFCAP_HWCSUM;
reinit = 1;
}
+#endif
if (mask & IFCAP_TSO4) {
ifp->if_capenable ^= IFCAP_TSO4;
reinit = 1;
@@ -1266,14 +1283,26 @@ igb_init_locked(struct adapter *adapter)
/* Set hardware offload abilities */
ifp->if_hwassist = 0;
if (ifp->if_capenable & IFCAP_TXCSUM) {
+#if __FreeBSD_version >= 1000000
+ ifp->if_hwassist |= (CSUM_IP_TCP | CSUM_IP_UDP);
+ if (adapter->hw.mac.type != e1000_82575)
+ ifp->if_hwassist |= CSUM_IP_SCTP;
+#else
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
#if __FreeBSD_version >= 800000
- if ((adapter->hw.mac.type == e1000_82576) ||
- (adapter->hw.mac.type == e1000_82580))
+ if (adapter->hw.mac.type != e1000_82575)
ifp->if_hwassist |= CSUM_SCTP;
#endif
+#endif
}
+#if __FreeBSD_version >= 1000000
+ if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) {
+ ifp->if_hwassist |= (CSUM_IP6_TCP | CSUM_IP6_UDP);
+ if (adapter->hw.mac.type != e1000_82575)
+ ifp->if_hwassist |= CSUM_IP6_SCTP;
+ }
+#endif
if (ifp->if_capenable & IFCAP_TSO)
ifp->if_hwassist |= CSUM_TSO;
@@ -3160,6 +3189,9 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
+#if __FreeBSD_version >= 1000000
+ ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
+#endif
ifp->if_capabilities |= IFCAP_TSO;
ifp->if_capabilities |= IFCAP_JUMBO_MTU;
ifp->if_capenable = ifp->if_capabilities;
@@ -3933,17 +3965,29 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp,
switch (ipproto) {
case IPPROTO_TCP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_TCP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP;
break;
case IPPROTO_UDP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_UDP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP;
break;
#if __FreeBSD_version >= 800000
case IPPROTO_SCTP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_SCTP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP;
break;
#endif
@@ -4701,8 +4745,7 @@ igb_initialize_receive_units(struct adapter *adapter)
rxcsum |= E1000_RXCSUM_PCSD;
#if __FreeBSD_version >= 800000
/* For SCTP Offload */
- if (((hw->mac.type == e1000_82576) ||
- (hw->mac.type == e1000_82580)) &&
+ if ((hw->mac.type != e1000_82575) &&
(ifp->if_capenable & IFCAP_RXCSUM))
rxcsum |= E1000_RXCSUM_CRCOFL;
#endif
@@ -4711,8 +4754,7 @@ igb_initialize_receive_units(struct adapter *adapter)
if (ifp->if_capenable & IFCAP_RXCSUM) {
rxcsum |= E1000_RXCSUM_IPPCSE;
#if __FreeBSD_version >= 800000
- if ((adapter->hw.mac.type == e1000_82576) ||
- (adapter->hw.mac.type == e1000_82580))
+ if (adapter->hw.mac.type != e1000_82575)
rxcsum |= E1000_RXCSUM_CRCOFL;
#endif
} else
@@ -4932,7 +4974,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
struct rx_ring *rxr = que->rxr;
struct ifnet *ifp = adapter->ifp;
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
int i, processed = 0, rxdone = 0;
u32 ptype, staterr = 0;
union e1000_adv_rx_desc *cur;
@@ -5160,10 +5201,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
if (done != NULL)
*done += rxdone;
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index 98df1ec..a0c35be 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -291,7 +291,11 @@
#define ETH_ADDR_LEN 6
/* Offload bits in mbuf flag */
-#if __FreeBSD_version >= 800000
+#if __FreeBSD_version >= 1000000
+#define CSUM_OFFLOAD_IPV4 (CSUM_IP|CSUM_IP_TCP|CSUM_IP_UDP|CSUM_IP_SCTP)
+#define CSUM_OFFLOAD_IPV6 (CSUM_IP6_TCP|CSUM_IP6_UDP|CSUM_IP6_SCTP)
+#define CSUM_OFFLOAD (CSUM_OFFLOAD_IPV4|CSUM_OFFLOAD_IPV6)
+#elif __FreeBSD_version >= 800000
#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP)
#else
#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP)
diff --git a/sys/dev/ed/if_ed_3c503.c b/sys/dev/ed/if_ed_3c503.c
index 353fbbf..bcb9e44 100644
--- a/sys/dev/ed/if_ed_3c503.c
+++ b/sys/dev/ed/if_ed_3c503.c
@@ -324,7 +324,7 @@ ed_probe_3Com(device_t dev, int port_rid, int flags)
ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n",
+ device_printf(dev, "Invalid irq configuration (%jd) must be 3-5,9 for 3c503\n",
irq);
return (ENXIO);
}
diff --git a/sys/dev/ed/if_ed_cbus.c b/sys/dev/ed/if_ed_cbus.c
index f9672ac..7926fa8 100644
--- a/sys/dev/ed/if_ed_cbus.c
+++ b/sys/dev/ed/if_ed_cbus.c
@@ -1021,7 +1021,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
|| ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0x[a-f]3d0", "CNET98");
#endif
@@ -1032,7 +1032,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
/* Check window area address */
tmp_s = rman_get_start(sc->mem_res) >> 12;
if (tmp_s < 0x80) {
- device_printf(dev, "Please change window address(0x%lx)\n",
+ device_printf(dev, "Please change window address(0x%jx)\n",
rman_get_start(sc->mem_res));
return (ENXIO);
}
@@ -1040,8 +1040,8 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
tmp_s &= 0x0f;
tmp = rman_get_start(sc->port_res) >> 12;
if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
- device_printf(dev, "Please change iobase address(0x%lx) "
- "or window address(0x%lx)\n",
+ device_printf(dev, "Please change iobase address(0x%jx) "
+ "or window address(0x%jx)\n",
rman_get_start(sc->port_res),
rman_get_start(sc->mem_res));
return (ENXIO);
@@ -1128,7 +1128,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
tmp = ED_CNET98_INT_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
return (ENXIO);
}
@@ -1169,7 +1169,7 @@ ed_probe_CNET98EL(device_t dev, int port_rid, int flags)
/* Check I/O address. 0x[0-f]3d0 are allowed. */
if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0x?3d0", "CNET98E/L");
#endif
@@ -1223,7 +1223,7 @@ ed_probe_CNET98EL(device_t dev, int port_rid, int flags)
break;
#endif
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
return (ENXIO);
}
@@ -1285,7 +1285,7 @@ ed_probe_NEC77(device_t dev, int port_rid, int flags)
tmp = ED_NEC77_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
return (ENXIO);
}
@@ -1337,7 +1337,7 @@ ed_probe_NW98X(device_t dev, int port_rid, int flags)
tmp = ED_NW98X_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
return (ENXIO);
}
@@ -1439,7 +1439,7 @@ ed_probe_SB98(device_t dev, int port_rid, int flags)
/* Check I/O address. 00d[02468ace] are allowed. */
if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0xd?", "SB9801");
#endif
@@ -1475,7 +1475,7 @@ ed_probe_SB98(device_t dev, int port_rid, int flags)
tmp = ED_SB98_CFG_IRQ12;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
return (ENXIO);
}
diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c
index f1ed098..07cbd6b 100644
--- a/sys/dev/extres/clk/clk.c
+++ b/sys/dev/extres/clk/clk.c
@@ -487,10 +487,10 @@ clkdom_dump(struct clkdom * clkdom)
CLK_TOPO_SLOCK();
TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
rv = clknode_get_freq(clknode, &freq);
- printf("Clock: %s, parent: %s(%d), freq: %llu\n", clknode->name,
+ printf("Clock: %s, parent: %s(%d), freq: %ju\n", clknode->name,
clknode->parent == NULL ? "(NULL)" : clknode->parent->name,
clknode->parent_idx,
- ((rv == 0) ? freq: rv));
+ (uintmax_t)((rv == 0) ? freq: rv));
}
CLK_TOPO_UNLOCK();
}
@@ -818,6 +818,10 @@ clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
/* We have exclusive topology lock, node lock is not needed. */
CLK_TOPO_XASSERT();
+ /* Check for no change */
+ if (clknode->freq == freq)
+ return (0);
+
parent_freq = 0;
/*
@@ -1258,4 +1262,75 @@ clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk)
return (rv);
return (clk_get_by_ofw_index(dev, idx, clk));
}
+
+/* --------------------------------------------------------------------------
+ *
+ * Support functions for parsing various clock related OFW things.
+ */
+
+/*
+ * Get "clock-output-names" and (optional) "clock-indices" lists.
+ * Both lists are alocated using M_OFWPROP specifier.
+ *
+ * Returns number of items or 0.
+ */
+int
+clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
+ uint32_t **indices)
+{
+ int name_items, rv;
+
+ *out_names = NULL;
+ *indices = NULL;
+ if (!OF_hasprop(node, "clock-output-names"))
+ return (0);
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ out_names);
+ if (rv <= 0)
+ return (0);
+ name_items = rv;
+
+ if (!OF_hasprop(node, "clock-indices"))
+ return (name_items);
+ rv = OF_getencprop_alloc(node, "clock-indices", sizeof (uint32_t),
+ (void **)indices);
+ if (rv != name_items) {
+ device_printf(dev, " Size of 'clock-output-names' and "
+ "'clock-indices' differs\n");
+ free(*out_names, M_OFWPROP);
+ free(*indices, M_OFWPROP);
+ return (0);
+ }
+ return (name_items);
+}
+
+/*
+ * Get output clock name for single output clock node.
+ */
+int
+clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
+{
+ const char **out_names;
+ const char *tmp_name;
+ int rv;
+
+ *name = NULL;
+ if (!OF_hasprop(node, "clock-output-names")) {
+ tmp_name = ofw_bus_get_name(dev);
+ if (tmp_name == NULL)
+ return (ENXIO);
+ *name = strdup(tmp_name, M_OFWPROP);
+ return (0);
+ }
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ &out_names);
+ if (rv != 1) {
+ free(out_names, M_OFWPROP);
+ device_printf(dev, "Malformed 'clock-output-names' property\n");
+ return (ENXIO);
+ }
+ *name = strdup(out_names[0], M_OFWPROP);
+ free(out_names, M_OFWPROP);
+ return (0);
+}
#endif
diff --git a/sys/dev/extres/clk/clk.h b/sys/dev/extres/clk/clk.h
index 8547bae..510f0ce 100644
--- a/sys/dev/extres/clk/clk.h
+++ b/sys/dev/extres/clk/clk.h
@@ -131,6 +131,9 @@ const char *clk_get_name(clk_t clk);
#ifdef FDT
int clk_get_by_ofw_index(device_t dev, int idx, clk_t *clk);
int clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk);
+int clk_parse_ofw_out_names(device_t dev, phandle_t node,
+ const char ***out_names, uint32_t **indices);
+int clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name);
#endif
#endif /* _DEV_EXTRES_CLK_H_ */
diff --git a/sys/dev/extres/clk/clk_bus.c b/sys/dev/extres/clk/clk_bus.c
new file mode 100644
index 0000000..e475736
--- /dev/null
+++ b/sys/dev/extres/clk/clk_bus.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+struct ofw_clkbus_softc {
+ struct simplebus_softc simplebus_sc;
+};
+
+static int
+ofw_clkbus_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+
+ if (name == NULL || strcmp(name, "clocks") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "OFW clocks bus");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+ofw_clkbus_attach(device_t dev)
+{
+ struct ofw_clkbus_softc *sc;
+ phandle_t node, child;
+ device_t cdev;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ simplebus_init(dev, node);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+ if (cdev != NULL)
+ device_probe_and_attach(cdev);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t ofw_clkbus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_clkbus_probe),
+ DEVMETHOD(device_attach, ofw_clkbus_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofw_clkbus, ofw_clkbus_driver, ofw_clkbus_methods,
+ sizeof(struct ofw_clkbus_softc), simplebus_driver);
+static devclass_t ofw_clkbus_devclass;
+EARLY_DRIVER_MODULE(ofw_clkbus, simplebus, ofw_clkbus_driver,
+ ofw_clkbus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofw_clkbus, 1);
diff --git a/sys/dev/extres/clk/clk_div.c b/sys/dev/extres/clk/clk_div.c
index fcb0a57..51cc838 100644
--- a/sys/dev/extres/clk/clk_div.c
+++ b/sys/dev/extres/clk/clk_div.c
@@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_div_init(struct clknode *clk, device_t dev);
static int clknode_div_recalc(struct clknode *clk, uint64_t *req);
@@ -86,7 +90,9 @@ clknode_div_init(struct clknode *clk, device_t dev)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
if (rv != 0)
return (rv);
@@ -171,12 +177,17 @@ clknode_div_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
(*fout != (_fin / divider)))
return (ERANGE);
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset,
(sc->i_mask << sc->i_shift) | (sc->f_mask << sc->f_shift),
(i_div << sc->i_shift) | (f_div << sc->f_shift));
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
+
sc->divider = divider;
}
diff --git a/sys/dev/extres/clk/clk_fixed.c b/sys/dev/extres/clk/clk_fixed.c
index 4ddceae..02721ae 100644
--- a/sys/dev/extres/clk/clk_fixed.c
+++ b/sys/dev/extres/clk/clk_fixed.c
@@ -27,7 +27,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/bus.h>
@@ -35,20 +34,25 @@ __FBSDID("$FreeBSD$");
#include <sys/kobj.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/module.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <machine/bus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
#include <dev/extres/clk/clk_fixed.h>
-#define DEVICE_LOCK(_sc) mtx_lock((_sc)->mtx)
-#define DEVICE_UNLOCK(_sc) mtx_unlock((_sc)->mtx)
+#define CLK_TYPE_FIXED 1
+#define CLK_TYPE_FIXED_FACTOR 2
static int clknode_fixed_init(struct clknode *clk, device_t dev);
static int clknode_fixed_recalc(struct clknode *clk, uint64_t *freq);
+static int clknode_fixed_set_freq(struct clknode *clk, uint64_t fin,
+ uint64_t *fout, int flags, int *stop);
+
struct clknode_fixed_sc {
- struct mtx *mtx;
int fixed_flags;
uint64_t freq;
uint32_t mult;
@@ -59,6 +63,7 @@ static clknode_method_t clknode_fixed_methods[] = {
/* Device interface */
CLKNODEMETHOD(clknode_init, clknode_fixed_init),
CLKNODEMETHOD(clknode_recalc_freq, clknode_fixed_recalc),
+ CLKNODEMETHOD(clknode_set_freq, clknode_fixed_set_freq),
CLKNODEMETHOD_END
};
DEFINE_CLASS_1(clknode_fixed, clknode_fixed_class, clknode_fixed_methods,
@@ -74,36 +79,52 @@ clknode_fixed_init(struct clknode *clk, device_t dev)
clknode_init_parent_idx(clk, 0);
return(0);
}
+
static int
clknode_fixed_recalc(struct clknode *clk, uint64_t *freq)
{
struct clknode_fixed_sc *sc;
sc = clknode_get_softc(clk);
- if (sc->freq != 0)
- *freq = sc->freq;
- else if ((sc->mult != 0) && (sc->div != 0))
+
+ if ((sc->mult != 0) && (sc->div != 0))
*freq = (*freq / sc->div) * sc->mult;
else
- *freq = 0;
+ *freq = sc->freq;
+ return (0);
+}
+
+static int
+clknode_fixed_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct clknode_fixed_sc *sc;
+
+ sc = clknode_get_softc(clk);
+ if (sc->mult == 0 || sc->div == 0) {
+ /* Fixed frequency clock. */
+ *stop = 1;
+ if (*fout != sc->freq)
+ return (ERANGE);
+ return (0);
+ }
+ /* Fixed factor clock. */
+ *stop = 0;
+ *fout = (*fout / sc->mult) * sc->div;
return (0);
}
int
-clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
- struct mtx *dev_mtx)
+clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef)
{
struct clknode *clk;
struct clknode_fixed_sc *sc;
- if ((clkdef->freq == 0) && (clkdef->clkdef.parent_cnt == 0))
- panic("fixed clk: Frequency is not defined for clock source");
clk = clknode_create(clkdom, &clknode_fixed_class, &clkdef->clkdef);
if (clk == NULL)
return (1);
sc = clknode_get_softc(clk);
- sc->mtx = dev_mtx;
sc->fixed_flags = clkdef->fixed_flags;
sc->freq = clkdef->freq;
sc->mult = clkdef->mult;
@@ -112,3 +133,150 @@ clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
clknode_register(clkdom, clk);
return (0);
}
+
+#ifdef FDT
+
+static struct ofw_compat_data compat_data[] = {
+ {"fixed-clock", CLK_TYPE_FIXED},
+ {"fixed-factor-clock", CLK_TYPE_FIXED_FACTOR},
+ {NULL, 0},
+};
+
+struct clk_fixed_softc {
+ device_t dev;
+ struct clkdom *clkdom;
+};
+
+static int
+clk_fixed_probe(device_t dev)
+{
+ intptr_t clk_type;
+
+ clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ switch (clk_type) {
+ case CLK_TYPE_FIXED:
+ device_set_desc(dev, "Fixed clock");
+ return (BUS_PROBE_DEFAULT);
+ case CLK_TYPE_FIXED_FACTOR:
+ device_set_desc(dev, "Fixed factor clock");
+ return (BUS_PROBE_DEFAULT);
+ default:
+ return (ENXIO);
+ }
+}
+
+static int
+clk_fixed_init_fixed(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ uint32_t freq;
+ int rv;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
+ if (rv <= 0)
+ return (ENXIO);
+ def->freq = freq;
+ return (0);
+}
+
+static int
+clk_fixed_init_fixed_factor(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ int rv;
+ clk_t parent;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-mult", &def->mult, sizeof(def->mult));
+ if (rv <= 0)
+ return (ENXIO);
+ rv = OF_getencprop(node, "clock-div", &def->div, sizeof(def->div));
+ if (rv <= 0)
+ return (ENXIO);
+ /* Get name of parent clock */
+ rv = clk_get_by_ofw_index(sc->dev, 0, &parent);
+ if (rv != 0)
+ return (ENXIO);
+ def->clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP, M_WAITOK);
+ def->clkdef.parent_names[0] = clk_get_name(parent);
+ def->clkdef.parent_cnt = 1;
+ clk_release(parent);
+ return (0);
+}
+
+static int
+clk_fixed_attach(device_t dev)
+{
+ struct clk_fixed_softc *sc;
+ intptr_t clk_type;
+ phandle_t node;
+ struct clk_fixed_def def;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+ clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+ bzero(&def, sizeof(def));
+ if (clk_type == CLK_TYPE_FIXED)
+ rv = clk_fixed_init_fixed(sc, node, &def);
+ else if (clk_type == CLK_TYPE_FIXED_FACTOR)
+ rv = clk_fixed_init_fixed_factor(sc, node, &def);
+ else
+ rv = ENXIO;
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot FDT parameters.\n");
+ goto fail;
+ }
+ rv = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse clock name.\n");
+ goto fail;
+ }
+ sc->clkdom = clkdom_create(dev);
+ KASSERT(sc->clkdom != NULL, ("Clock domain is NULL"));
+
+ rv = clknode_fixed_register(sc->clkdom, &def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot register fixed clock.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rv = clkdom_finit(sc->clkdom);
+ if (rv != 0) {
+ device_printf(sc->dev, "Clk domain finit fails.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+#ifdef CLK_DEBUG
+ clkdom_dump(sc->clkdom);
+#endif
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (bus_generic_attach(dev));
+
+fail:
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (rv);
+}
+
+static device_method_t clk_fixed_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, clk_fixed_probe),
+ DEVMETHOD(device_attach, clk_fixed_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(clk_fixed, clk_fixed_driver, clk_fixed_methods,
+ sizeof(struct clk_fixed_softc));
+static devclass_t clk_fixed_devclass;
+EARLY_DRIVER_MODULE(clk_fixed, simplebus, clk_fixed_driver,
+ clk_fixed_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(clk_fixed, 1);
+
+#endif
diff --git a/sys/dev/extres/clk/clk_fixed.h b/sys/dev/extres/clk/clk_fixed.h
index f57ee96..e2643ff 100644
--- a/sys/dev/extres/clk/clk_fixed.h
+++ b/sys/dev/extres/clk/clk_fixed.h
@@ -47,7 +47,6 @@ struct clk_fixed_def {
int fixed_flags;
};
-int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
- struct mtx *dev_mtx);
+int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef);
#endif /*_DEV_EXTRES_CLK_FIXED_H_*/
diff --git a/sys/dev/extres/clk/clk_gate.c b/sys/dev/extres/clk/clk_gate.c
index 2107450..e0673fd 100644
--- a/sys/dev/extres/clk/clk_gate.c
+++ b/sys/dev/extres/clk/clk_gate.c
@@ -46,7 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
-
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_gate_init(struct clknode *clk, device_t dev);
static int clknode_gate_set_gate(struct clknode *clk, bool enable);
@@ -77,7 +80,9 @@ clknode_gate_init(struct clknode *clk, device_t dev)
int rv;
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
if (rv != 0)
return (rv);
reg = (reg >> sc->shift) & sc->mask;
@@ -95,11 +100,15 @@ clknode_gate_set_gate(struct clknode *clk, bool enable)
sc = clknode_get_softc(clk);
sc->ungated = enable;
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
(sc->ungated ? sc->on_value : sc->off_value) << sc->shift);
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
return(0);
}
diff --git a/sys/dev/extres/clk/clk_mux.c b/sys/dev/extres/clk/clk_mux.c
index 54e0653..624f587 100644
--- a/sys/dev/extres/clk/clk_mux.c
+++ b/sys/dev/extres/clk/clk_mux.c
@@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_mux_init(struct clknode *clk, device_t dev);
static int clknode_mux_set_mux(struct clknode *clk, int idx);
@@ -76,9 +80,12 @@ clknode_mux_init(struct clknode *clk, device_t dev)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
- if (rv != 0)
+ DEVICE_UNLOCK(clk);
+ if (rv != 0) {
return (rv);
+ }
reg = (reg >> sc->shift) & sc->mask;
clknode_init_parent_idx(clk, reg);
return(0);
@@ -93,11 +100,16 @@ clknode_mux_set_mux(struct clknode *clk, int idx)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
(idx & sc->mask) << sc->shift);
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
+
return(0);
}
diff --git a/sys/dev/extres/clk/clkdev_if.m b/sys/dev/extres/clk/clkdev_if.m
index b43d205..f9f5084 100644
--- a/sys/dev/extres/clk/clkdev_if.m
+++ b/sys/dev/extres/clk/clkdev_if.m
@@ -30,6 +30,71 @@
INTERFACE clkdev;
+CODE {
+ #include <sys/systm.h>
+ #include <sys/bus.h>
+ static int
+ clkdev_default_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_WRITE_4(pdev, addr, val));
+ }
+
+ static int
+ clkdev_default_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_READ_4(pdev, addr, val));
+ }
+
+ static int
+ clkdev_default_modify_4(device_t dev, bus_addr_t addr,
+ uint32_t clear_mask, uint32_t set_mask)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_MODIFY_4(pdev, addr, clear_mask, set_mask));
+ }
+
+ static void
+ clkdev_default_device_lock(device_t dev)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ panic("clkdev_device_lock not implemented");
+
+ CLKDEV_DEVICE_LOCK(pdev);
+ }
+
+ static void
+ clkdev_default_device_unlock(device_t dev)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ panic("clkdev_device_unlock not implemented");
+
+ CLKDEV_DEVICE_UNLOCK(pdev);
+ }
+}
+
#
# Write single register
#
@@ -37,7 +102,7 @@ METHOD int write_4 {
device_t dev;
bus_addr_t addr;
uint32_t val;
-};
+} DEFAULT clkdev_default_write_4;
#
# Read single register
@@ -46,7 +111,7 @@ METHOD int read_4 {
device_t dev;
bus_addr_t addr;
uint32_t *val;
-};
+} DEFAULT clkdev_default_read_4;
#
# Modify single register
@@ -56,4 +121,18 @@ METHOD int modify_4 {
bus_addr_t addr;
uint32_t clear_mask;
uint32_t set_mask;
-};
+} DEFAULT clkdev_default_modify_4;
+
+#
+# Get exclusive access to underlying device
+#
+METHOD void device_lock {
+ device_t dev;
+} DEFAULT clkdev_default_device_lock;
+
+#
+# Release exclusive access to underlying device
+#
+METHOD void device_unlock {
+ device_t dev;
+} DEFAULT clkdev_default_device_unlock;
diff --git a/sys/dev/extres/phy/phy.c b/sys/dev/extres/phy/phy.c
new file mode 100644
index 0000000..0e2c7e1
--- /dev/null
+++ b/sys/dev/extres/phy/phy.c
@@ -0,0 +1,235 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+#include "opt_platform.h"
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
+#include <dev/extres/phy/phy.h>
+
+#include "phy_if.h"
+
+struct phy {
+ device_t consumer_dev; /* consumer device*/
+ device_t provider_dev; /* provider device*/
+ uintptr_t phy_id; /* phy id */
+};
+
+MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
+
+int
+phy_init(device_t consumer, phy_t phy)
+{
+
+ return (PHY_INIT(phy->provider_dev, phy->phy_id, true));
+}
+
+int
+phy_deinit(device_t consumer, phy_t phy)
+{
+
+ return (PHY_INIT(phy->provider_dev, phy->phy_id, false));
+}
+
+
+int
+phy_enable(device_t consumer, phy_t phy)
+{
+
+ return (PHY_ENABLE(phy->provider_dev, phy->phy_id, true));
+}
+
+int
+phy_disable(device_t consumer, phy_t phy)
+{
+
+ return (PHY_ENABLE(phy->provider_dev, phy->phy_id, false));
+}
+
+int
+phy_status(device_t consumer, phy_t phy, int *value)
+{
+
+ return (PHY_STATUS(phy->provider_dev, phy->phy_id, value));
+}
+
+int
+phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
+ phy_t *phy_out)
+{
+ phy_t phy;
+
+ /* Create handle */
+ phy = malloc(sizeof(struct phy), M_PHY,
+ M_WAITOK | M_ZERO);
+ phy->consumer_dev = consumer_dev;
+ phy->provider_dev = provider_dev;
+ phy->phy_id = id;
+ *phy_out = phy;
+ return (0);
+}
+
+void
+phy_release(phy_t phy)
+{
+ free(phy, M_PHY);
+}
+
+
+#ifdef FDT
+int phy_default_map(device_t provider, phandle_t xref, int ncells,
+ pcell_t *cells, intptr_t *id)
+{
+
+ if (ncells == 0)
+ *id = 1;
+ else if (ncells == 1)
+ *id = cells[0];
+ else
+ return (ERANGE);
+
+ return (0);
+}
+
+int
+phy_get_by_ofw_idx(device_t consumer_dev, int idx, phy_t *phy)
+{
+ phandle_t cnode, xnode;
+ pcell_t *cells;
+ device_t phydev;
+ int ncells, rv;
+ intptr_t id;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
+ &xnode, &ncells, &cells);
+ if (rv != 0)
+ return (rv);
+
+ /* Tranlate provider to device. */
+ phydev = OF_device_from_xref(xnode);
+ if (phydev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+ /* Map phy to number. */
+ rv = PHY_MAP(phydev, xnode, ncells, cells, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+
+ return (phy_get_by_id(consumer_dev, phydev, id, phy));
+}
+
+int
+phy_get_by_ofw_name(device_t consumer_dev, char *name, phy_t *phy)
+{
+ int rv, idx;
+ phandle_t cnode;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
+ if (rv != 0)
+ return (rv);
+ return (phy_get_by_ofw_idx(consumer_dev, idx, phy));
+}
+
+int
+phy_get_by_ofw_property(device_t consumer_dev, char *name, phy_t *phy)
+{
+ phandle_t cnode;
+ pcell_t *cells;
+ device_t phydev;
+ int ncells, rv;
+ intptr_t id;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
+ (void **)&cells);
+ if (ncells < 1)
+ return (ENXIO);
+
+ /* Tranlate provider to device. */
+ phydev = OF_device_from_xref(cells[0]);
+ if (phydev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+ /* Map phy to number. */
+ rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+
+ return (phy_get_by_id(consumer_dev, phydev, id, phy));
+}
+
+void
+phy_register_provider(device_t provider_dev)
+{
+ phandle_t xref, node;
+
+ node = ofw_bus_get_node(provider_dev);
+ if (node <= 0)
+ panic("%s called on not ofw based device.\n", __func__);
+
+ xref = OF_xref_from_node(node);
+ OF_device_register_xref(xref, provider_dev);
+}
+
+void
+phy_unregister_provider(device_t provider_dev)
+{
+ phandle_t xref;
+
+ xref = OF_xref_from_device(provider_dev);
+ OF_device_register_xref(xref, NULL);
+}
+#endif
diff --git a/sys/dev/extres/phy/phy.h b/sys/dev/extres/phy/phy.h
new file mode 100644
index 0000000..93b4fe4
--- /dev/null
+++ b/sys/dev/extres/phy/phy.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef DEV_EXTRES_PHY_H
+#define DEV_EXTRES_PHY_H
+
+#include "opt_platform.h"
+#include <sys/types.h>
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+typedef struct phy *phy_t;
+
+/*
+ * Provider interface
+ */
+#ifdef FDT
+void phy_register_provider(device_t provider);
+void phy_unregister_provider(device_t provider);
+#endif
+
+/*
+ * Consumer interface
+ */
+int phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
+ phy_t *phy);
+void phy_release(phy_t phy);
+int phy_get_by_ofw_name(device_t consumer, char *name, phy_t *phy);
+int phy_get_by_ofw_idx(device_t consumer, int idx, phy_t *phy);
+int phy_get_by_ofw_property(device_t consumer, char *name, phy_t *phy);
+
+int phy_init(device_t consumer, phy_t phy);
+int phy_deinit(device_t consumer, phy_t phy);
+int phy_enable(device_t consumer, phy_t phy);
+int phy_disable(device_t consumer, phy_t phy);
+int phy_status(device_t consumer, phy_t phy, int *value);
+
+#endif /* DEV_EXTRES_PHY_H */
diff --git a/sys/dev/extres/phy/phy_if.m b/sys/dev/extres/phy/phy_if.m
new file mode 100644
index 0000000..e3b4e33
--- /dev/null
+++ b/sys/dev/extres/phy/phy_if.m
@@ -0,0 +1,84 @@
+#-
+# Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#ifdef FDT
+#include <sys/types.h>
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+INTERFACE phy;
+
+#ifdef FDT
+HEADER {
+int phy_default_map(device_t , phandle_t, int, pcell_t *, intptr_t *);
+}
+
+#
+# map fdt property cells to phy number
+# Returns 0 on success or a standard errno value.
+#
+METHOD int map {
+ device_t provider_dev;
+ phandle_t xref;
+ int ncells;
+ pcell_t *cells;
+ intptr_t *id;
+} DEFAULT phy_default_map;
+#endif
+
+#
+# Init/deinit phy
+# Returns 0 on success or a standard errno value.
+#
+METHOD int init {
+ device_t provider_dev;
+ intptr_t id;
+ bool inti;
+};
+
+#
+# Enable/disable phy
+# Returns 0 on success or a standard errno value.
+#
+METHOD int enable {
+ device_t provider_dev;
+ intptr_t id;
+ bool enable;
+};
+
+#
+# Get phy status
+# Returns 0 on success or a standard errno value.
+#
+METHOD int status {
+ device_t provider_dev;
+ intptr_t id;
+ int *status; /* PHY_STATUS_* */
+};
+
+
diff --git a/sys/dev/extres/regulator/regdev_if.m b/sys/dev/extres/regulator/regdev_if.m
new file mode 100644
index 0000000..eecbf8b
--- /dev/null
+++ b/sys/dev/extres/regulator/regdev_if.m
@@ -0,0 +1,56 @@
+#-
+# Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#ifdef FDT
+#include <sys/types.h>
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+#include <machine/bus.h>
+
+INTERFACE regdev;
+
+#ifdef FDT
+
+HEADER {
+int regdev_default_ofw_map(device_t , phandle_t, int, pcell_t *, intptr_t *);
+}
+
+#
+# map fdt property cells to regulator number
+# Returns 0 on success or a standard errno value.
+#
+METHOD int map {
+ device_t provider_dev;
+ phandle_t xref;
+ int ncells;
+ pcell_t *cells;
+ intptr_t *id;
+} DEFAULT regdev_default_ofw_map;
+
+#endif
diff --git a/sys/dev/extres/regulator/regnode_if.m b/sys/dev/extres/regulator/regnode_if.m
new file mode 100644
index 0000000..d92f26f
--- /dev/null
+++ b/sys/dev/extres/regulator/regnode_if.m
@@ -0,0 +1,82 @@
+#-
+# Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+# 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 AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+INTERFACE regnode;
+HEADER {
+ struct regnode;
+}
+
+#
+# Initialize regulator
+# Returns 0 on success or a standard errno value.
+#
+METHOD int init {
+ struct regnode *regnode;
+};
+
+#
+# Enable/disable regulator
+# Returns 0 on success or a standard errno value.
+# - enable - input.
+# - delay - output, delay needed to stabilize voltage (in us)
+#
+METHOD int enable {
+ struct regnode *regnode;
+ bool enable;
+ int *udelay;
+};
+
+#
+# Get regulator status
+# Returns 0 on success or a standard errno value.
+#
+METHOD int status {
+ struct regnode *regnode;
+ int *status; /* REGULATOR_STATUS_* */
+};
+
+#
+# Set regulator voltage
+# Returns 0 on success or a standard errno value.
+# - min_uvolt, max_uvolt - input, requested voltage range (in uV)
+# - delay - output, delay needed to stabilize voltage (in us)
+METHOD int set_voltage {
+ struct regnode *regnode;
+ int min_uvolt;
+ int max_uvolt;
+ int *udelay;
+};
+
+#
+# Get regulator voltage
+# Returns 0 on success or a standard errno value.
+#
+METHOD int get_voltage {
+ struct regnode *regnode;
+ int *uvolt;
+};
diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/extres/regulator/regulator.c
new file mode 100644
index 0000000..b941aa1
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator.c
@@ -0,0 +1,984 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/kobj.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+#include <dev/extres/regulator/regulator.h>
+
+#include "regdev_if.h"
+
+MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework");
+
+/* Forward declarations. */
+struct regulator;
+struct regnode;
+
+typedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t;
+typedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t;
+
+/* Default regulator methods. */
+static int regnode_method_enable(struct regnode *regnode, bool enable,
+ int *udelay);
+static int regnode_method_status(struct regnode *regnode, int *status);
+static int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt,
+ int max_uvolt, int *udelay);
+static int regnode_method_get_voltage(struct regnode *regnode, int *uvolt);
+
+/*
+ * Regulator controller methods.
+ */
+static regnode_method_t regnode_methods[] = {
+ REGNODEMETHOD(regnode_enable, regnode_method_enable),
+ REGNODEMETHOD(regnode_status, regnode_method_status),
+ REGNODEMETHOD(regnode_set_voltage, regnode_method_set_voltage),
+ REGNODEMETHOD(regnode_get_voltage, regnode_method_get_voltage),
+
+ REGNODEMETHOD_END
+};
+DEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0);
+
+/*
+ * Regulator node - basic element for modelling SOC and bard power supply
+ * chains. Its contains producer data.
+ */
+struct regnode {
+ KOBJ_FIELDS;
+
+ TAILQ_ENTRY(regnode) reglist_link; /* Global list entry */
+ regulator_list_t consumers_list; /* Consumers list */
+
+ /* Cache for already resolved names */
+ struct regnode *parent; /* Resolved parent */
+
+ /* Details of this device. */
+ const char *name; /* Globally unique name */
+ const char *parent_name; /* Parent name */
+
+ device_t pdev; /* Producer device_t */
+ void *softc; /* Producer softc */
+ intptr_t id; /* Per producer unique id */
+#ifdef FDT
+ phandle_t ofw_node; /* OFW node of regulator */
+#endif
+ int flags; /* REGULATOR_FLAGS_ */
+ struct sx lock; /* Lock for this regulator */
+ int ref_cnt; /* Reference counter */
+ int enable_cnt; /* Enabled counter */
+
+ struct regnode_std_param std_param; /* Standard parameters */
+};
+
+/*
+ * Per consumer data, information about how a consumer is using a regulator
+ * node.
+ * A pointer to this structure is used as a handle in the consumer interface.
+ */
+struct regulator {
+ device_t cdev; /* Consumer device */
+ struct regnode *regnode;
+ TAILQ_ENTRY(regulator) link; /* Consumers list entry */
+
+ int enable_cnt;
+ int min_uvolt; /* Requested uvolt range */
+ int max_uvolt;
+};
+
+/*
+ * Regulator names must be system wide unique.
+ */
+static regnode_list_t regnode_list = TAILQ_HEAD_INITIALIZER(regnode_list);
+
+static struct sx regnode_topo_lock;
+SX_SYSINIT(regulator_topology, &regnode_topo_lock, "Regulator topology lock");
+
+#define REG_TOPO_SLOCK() sx_slock(&regnode_topo_lock)
+#define REG_TOPO_XLOCK() sx_xlock(&regnode_topo_lock)
+#define REG_TOPO_UNLOCK() sx_unlock(&regnode_topo_lock)
+#define REG_TOPO_ASSERT() sx_assert(&regnode_topo_lock, SA_LOCKED)
+#define REG_TOPO_XASSERT() sx_assert(&regnode_topo_lock, SA_XLOCKED)
+
+#define REGNODE_SLOCK(_sc) sx_slock(&((_sc)->lock))
+#define REGNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock))
+#define REGNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock))
+
+/* ----------------------------------------------------------------------------
+ *
+ * Default regulator methods for base class.
+ *
+ */
+static int
+regnode_method_enable(struct regnode *regnode, bool enable, int *udelay)
+{
+
+ if (!enable)
+ return (ENXIO);
+
+ *udelay = 0;
+ return (0);
+}
+
+static int
+regnode_method_status(struct regnode *regnode, int *status)
+{
+ *status = REGULATOR_STATUS_ENABLED;
+ return (0);
+}
+
+static int
+regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt,
+ int *udelay)
+{
+
+ if ((min_uvolt > regnode->std_param.max_uvolt) ||
+ (max_uvolt < regnode->std_param.min_uvolt))
+ return (ERANGE);
+ *udelay = 0;
+ return (0);
+}
+
+static int
+regnode_method_get_voltage(struct regnode *regnode, int *uvolt)
+{
+
+ return (regnode->std_param.min_uvolt +
+ (regnode->std_param.max_uvolt - regnode->std_param.min_uvolt) / 2);
+}
+
+/* ----------------------------------------------------------------------------
+ *
+ * Internal functions.
+ *
+ */
+
+static struct regnode *
+regnode_find_by_name(const char *name)
+{
+ struct regnode *entry;
+
+ REG_TOPO_ASSERT();
+
+ TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
+ if (strcmp(entry->name, name) == 0)
+ return (entry);
+ }
+ return (NULL);
+}
+
+static struct regnode *
+regnode_find_by_id(device_t dev, intptr_t id)
+{
+ struct regnode *entry;
+
+ REG_TOPO_ASSERT();
+
+ TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
+ if ((entry->pdev == dev) && (entry->id == id))
+ return (entry);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Create and initialize regulator object, but do not register it.
+ */
+struct regnode *
+regnode_create(device_t pdev, regnode_class_t regnode_class,
+ struct regnode_init_def *def)
+{
+ struct regnode *regnode;
+
+ KASSERT(def->name != NULL, ("regulator name is NULL"));
+ KASSERT(def->name[0] != '\0', ("regulator name is empty"));
+
+ REG_TOPO_SLOCK();
+ if (regnode_find_by_name(def->name) != NULL)
+ panic("Duplicated regulator registration: %s\n", def->name);
+ REG_TOPO_UNLOCK();
+
+ /* Create object and initialize it. */
+ regnode = malloc(sizeof(struct regnode), M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class);
+ sx_init(&regnode->lock, "Regulator node lock");
+
+ /* Allocate softc if required. */
+ if (regnode_class->size > 0) {
+ regnode->softc = malloc(regnode_class->size, M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ }
+
+
+ /* Copy all strings unless they're flagged as static. */
+ if (def->flags & REGULATOR_FLAGS_STATIC) {
+ regnode->name = def->name;
+ regnode->parent_name = def->parent_name;
+ } else {
+ regnode->name = strdup(def->name, M_REGULATOR);
+ if (def->parent_name != NULL)
+ regnode->parent_name = strdup(def->parent_name,
+ M_REGULATOR);
+ }
+
+ /* Rest of init. */
+ TAILQ_INIT(&regnode->consumers_list);
+ regnode->id = def->id;
+ regnode->pdev = pdev;
+ regnode->flags = def->flags;
+ regnode->parent = NULL;
+ regnode->std_param = def->std_param;
+#ifdef FDT
+ regnode->ofw_node = def->ofw_node;
+#endif
+
+ return (regnode);
+}
+
+/* Register regulator object. */
+struct regnode *
+regnode_register(struct regnode *regnode)
+{
+ int rv;
+
+#ifdef FDT
+ if (regnode->ofw_node <= 0)
+ regnode->ofw_node = ofw_bus_get_node(regnode->pdev);
+ if (regnode->ofw_node <= 0)
+ return (NULL);
+#endif
+
+ rv = REGNODE_INIT(regnode);
+ if (rv != 0) {
+ printf("REGNODE_INIT failed: %d\n", rv);
+ return (NULL);
+ }
+
+ REG_TOPO_XLOCK();
+ TAILQ_INSERT_TAIL(&regnode_list, regnode, reglist_link);
+ REG_TOPO_UNLOCK();
+#ifdef FDT
+ OF_device_register_xref(OF_xref_from_node(regnode->ofw_node),
+ regnode->pdev);
+#endif
+ return (regnode);
+}
+
+static int
+regnode_resolve_parent(struct regnode *regnode)
+{
+
+ /* All ready resolved or no parent? */
+ if ((regnode->parent != NULL) ||
+ (regnode->parent_name == NULL))
+ return (0);
+
+ regnode->parent = regnode_find_by_name(regnode->parent_name);
+ if (regnode->parent == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+static void
+regnode_delay(int usec)
+{
+ int ticks;
+
+ if (usec == 0)
+ return;
+ ticks = (usec * hz + 999999) / 1000000;
+
+ if (cold || ticks < 2)
+ DELAY(usec);
+ else
+ pause("REGULATOR", ticks);
+}
+
+/* --------------------------------------------------------------------------
+ *
+ * Regulator providers interface
+ *
+ */
+
+const char *
+regnode_get_name(struct regnode *regnode)
+{
+
+ return (regnode->name);
+}
+
+const char *
+regnode_get_parent_name(struct regnode *regnode)
+{
+
+ return (regnode->parent_name);
+}
+
+int
+regnode_get_flags(struct regnode *regnode)
+{
+
+ return (regnode->flags);
+}
+
+void *
+regnode_get_softc(struct regnode *regnode)
+{
+
+ return (regnode->softc);
+}
+
+device_t
+regnode_get_device(struct regnode *regnode)
+{
+
+ return (regnode->pdev);
+}
+
+struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode)
+{
+
+ return (&regnode->std_param);
+}
+
+void regnode_topo_unlock(void)
+{
+
+ REG_TOPO_UNLOCK();
+}
+
+void regnode_topo_xlock(void)
+{
+
+ REG_TOPO_XLOCK();
+}
+
+void regnode_topo_slock(void)
+{
+
+ REG_TOPO_SLOCK();
+}
+
+
+/* --------------------------------------------------------------------------
+ *
+ * Real consumers executive
+ *
+ */
+struct regnode *
+regnode_get_parent(struct regnode *regnode)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (NULL);
+
+ return (regnode->parent);
+}
+
+/*
+ * Enable regulator.
+ */
+int
+regnode_enable(struct regnode *regnode)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ /* Enable regulator for each node in chain, starting from source. */
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL) {
+ rv = regnode_enable(regnode->parent);
+ if (rv != 0)
+ return (rv);
+ }
+
+ /* Handle this node. */
+ REGNODE_XLOCK(regnode);
+ if (regnode->enable_cnt == 0) {
+ rv = REGNODE_ENABLE(regnode, true, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ regnode->enable_cnt++;
+ REGNODE_UNLOCK(regnode);
+ return (0);
+}
+
+/*
+ * Disable regulator.
+ */
+int
+regnode_disable(struct regnode *regnode)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+ rv = 0;
+
+ REGNODE_XLOCK(regnode);
+ /* Disable regulator for each node in chain, starting from consumer. */
+ if ((regnode->enable_cnt == 1) &&
+ ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
+ rv = REGNODE_ENABLE(regnode, false, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ regnode->enable_cnt--;
+ REGNODE_UNLOCK(regnode);
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_disable(regnode->parent);
+ return (rv);
+}
+
+/*
+ * Stop regulator.
+ */
+int
+regnode_stop(struct regnode *regnode, int depth)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+ rv = 0;
+
+ REGNODE_XLOCK(regnode);
+ /* The first node must not be enabled. */
+ if ((regnode->enable_cnt != 0) && (depth == 0)) {
+ REGNODE_UNLOCK(regnode);
+ return (EBUSY);
+ }
+ /* Disable regulator for each node in chain, starting from consumer */
+ if ((regnode->enable_cnt == 0) &&
+ ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
+ rv = REGNODE_ENABLE(regnode, false, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ REGNODE_UNLOCK(regnode);
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_stop(regnode->parent, depth + 1);
+ return (rv);
+}
+
+/*
+ * Get regulator status. (REGULATOR_STATUS_*)
+ */
+int
+regnode_status(struct regnode *regnode, int *status)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ rv = REGNODE_STATUS(regnode, status);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+/*
+ * Get actual regulator voltage.
+ */
+int
+regnode_get_voltage(struct regnode *regnode, int *uvolt)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ rv = REGNODE_GET_VOLTAGE(regnode, uvolt);
+ REGNODE_UNLOCK(regnode);
+
+ /* Pass call into parent, if regulator is in bypass mode. */
+ if (rv == ENOENT) {
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_get_voltage(regnode->parent, uvolt);
+
+ }
+ return (rv);
+}
+
+/*
+ * Set regulator voltage.
+ */
+int
+regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+
+ rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
+ if (rv == 0)
+ regnode_delay(udelay);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+/*
+ * Consumer variant of regnode_set_voltage().
+ */
+static int
+regnode_set_voltage_checked(struct regnode *regnode, struct regulator *reg,
+ int min_uvolt, int max_uvolt)
+{
+ int udelay;
+ int all_max_uvolt;
+ int all_min_uvolt;
+ struct regulator *tmp;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ /* Return error if requested range is outside of regulator range. */
+ if ((min_uvolt > regnode->std_param.max_uvolt) ||
+ (max_uvolt < regnode->std_param.min_uvolt)) {
+ REGNODE_UNLOCK(regnode);
+ return (ERANGE);
+ }
+
+ /* Get actual voltage range for all consumers. */
+ all_min_uvolt = regnode->std_param.min_uvolt;
+ all_max_uvolt = regnode->std_param.max_uvolt;
+ TAILQ_FOREACH(tmp, &regnode->consumers_list, link) {
+ /* Don't take requestor in account. */
+ if (tmp == reg)
+ continue;
+ if (all_min_uvolt < tmp->min_uvolt)
+ all_min_uvolt = tmp->min_uvolt;
+ if (all_max_uvolt > tmp->max_uvolt)
+ all_max_uvolt = tmp->max_uvolt;
+ }
+
+ /* Test if request fits to actual contract. */
+ if ((min_uvolt > all_max_uvolt) ||
+ (max_uvolt < all_min_uvolt)) {
+ REGNODE_UNLOCK(regnode);
+ return (ERANGE);
+ }
+
+ /* Adjust new range.*/
+ if (min_uvolt < all_min_uvolt)
+ min_uvolt = all_min_uvolt;
+ if (max_uvolt > all_max_uvolt)
+ max_uvolt = all_max_uvolt;
+
+ rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
+ regnode_delay(udelay);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+#ifdef FDT
+phandle_t
+regnode_get_ofw_node(struct regnode *regnode)
+{
+
+ return (regnode->ofw_node);
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ *
+ * Regulator consumers interface.
+ *
+ */
+/* Helper function for regulator_get*() */
+static regulator_t
+regulator_create(struct regnode *regnode, device_t cdev)
+{
+ struct regulator *reg;
+
+ REG_TOPO_ASSERT();
+
+ reg = malloc(sizeof(struct regulator), M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ reg->cdev = cdev;
+ reg->regnode = regnode;
+ reg->enable_cnt = 0;
+
+ REGNODE_XLOCK(regnode);
+ regnode->ref_cnt++;
+ TAILQ_INSERT_TAIL(&regnode->consumers_list, reg, link);
+ reg ->min_uvolt = regnode->std_param.min_uvolt;
+ reg ->max_uvolt = regnode->std_param.max_uvolt;
+ REGNODE_UNLOCK(regnode);
+
+ return (reg);
+}
+
+int
+regulator_enable(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ REG_TOPO_SLOCK();
+ rv = regnode_enable(regnode);
+ if (rv == 0)
+ reg->enable_cnt++;
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_disable(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ KASSERT(reg->enable_cnt > 0,
+ ("Attempt to disable already disabled regulator: %s\n",
+ regnode->name));
+ REG_TOPO_SLOCK();
+ rv = regnode_disable(regnode);
+ if (rv == 0)
+ reg->enable_cnt--;
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_stop(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ KASSERT(reg->enable_cnt == 0,
+ ("Attempt to stop already enabled regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_stop(regnode, 0);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_status(regulator_t reg, int *status)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_status(regnode, status);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_get_voltage(regulator_t reg, int *uvolt)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_get_voltage(regnode, uvolt);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt)
+{
+ struct regnode *regnode;
+ int rv;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+
+ rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, max_uvolt);
+ if (rv == 0) {
+ reg->min_uvolt = min_uvolt;
+ reg->max_uvolt = max_uvolt;
+ }
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+const char *
+regulator_get_name(regulator_t reg)
+{
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ return (regnode->name);
+}
+
+int
+regulator_get_by_name(device_t cdev, const char *name, regulator_t *reg)
+{
+ struct regnode *regnode;
+
+ REG_TOPO_SLOCK();
+ regnode = regnode_find_by_name(name);
+ if (regnode == NULL) {
+ REG_TOPO_UNLOCK();
+ return (ENODEV);
+ }
+ *reg = regulator_create(regnode, cdev);
+ REG_TOPO_UNLOCK();
+ return (0);
+}
+
+int
+regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *reg)
+{
+ struct regnode *regnode;
+
+ REG_TOPO_SLOCK();
+
+ regnode = regnode_find_by_id(pdev, id);
+ if (regnode == NULL) {
+ REG_TOPO_UNLOCK();
+ return (ENODEV);
+ }
+ *reg = regulator_create(regnode, cdev);
+ REG_TOPO_UNLOCK();
+
+ return (0);
+}
+
+int
+regulator_release(regulator_t reg)
+{
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ REG_TOPO_SLOCK();
+ while (reg->enable_cnt > 0) {
+ regnode_disable(regnode);
+ reg->enable_cnt--;
+ }
+ REGNODE_XLOCK(regnode);
+ TAILQ_REMOVE(&regnode->consumers_list, reg, link);
+ regnode->ref_cnt--;
+ REGNODE_UNLOCK(regnode);
+ REG_TOPO_UNLOCK();
+
+ free(reg, M_REGULATOR);
+ return (0);
+}
+
+#ifdef FDT
+/* Default DT mapper. */
+int
+regdev_default_ofw_map(device_t dev, phandle_t xref, int ncells,
+ pcell_t *cells, intptr_t *id)
+{
+ if (ncells == 0)
+ *id = 1;
+ else if (ncells == 1)
+ *id = cells[0];
+ else
+ return (ERANGE);
+
+ return (0);
+}
+
+int
+regulator_parse_ofw_stdparam(device_t pdev, phandle_t node,
+ struct regnode_init_def *def)
+{
+ phandle_t supply_xref;
+ struct regnode_std_param *par;
+ int rv;
+
+ par = &def->std_param;
+ rv = OF_getprop_alloc(node, "regulator-name", 1,
+ (void **)&def->name);
+ if (rv <= 0) {
+ device_printf(pdev, "%s: Missing regulator name\n",
+ __func__);
+ return (ENXIO);
+ }
+
+ rv = OF_getencprop(node, "regulator-min-microvolt", &par->min_uvolt,
+ sizeof(par->min_uvolt));
+ if (rv <= 0)
+ par->min_uvolt = 0;
+
+ rv = OF_getencprop(node, "regulator-max-microvolt", &par->max_uvolt,
+ sizeof(par->max_uvolt));
+ if (rv <= 0)
+ par->max_uvolt = 0;
+
+ rv = OF_getencprop(node, "regulator-min-microamp", &par->min_uamp,
+ sizeof(par->min_uamp));
+ if (rv <= 0)
+ par->min_uamp = 0;
+
+ rv = OF_getencprop(node, "regulator-max-microamp", &par->max_uamp,
+ sizeof(par->max_uamp));
+ if (rv <= 0)
+ par->max_uamp = 0;
+
+ rv = OF_getencprop(node, "regulator-ramp-delay", &par->ramp_delay,
+ sizeof(par->ramp_delay));
+ if (rv <= 0)
+ par->ramp_delay = 0;
+
+ rv = OF_getencprop(node, "regulator-enable-ramp-delay",
+ &par->enable_delay, sizeof(par->enable_delay));
+ if (rv <= 0)
+ par->enable_delay = 0;
+
+ if (OF_hasprop(node, "regulator-boot-on"))
+ par->boot_on = 1;
+
+ if (OF_hasprop(node, "regulator-always-on"))
+ par->always_on = 1;
+
+ if (OF_hasprop(node, "enable-active-high"))
+ par->enable_active_high = 1;
+
+ rv = OF_getencprop(node, "vin-supply", &supply_xref,
+ sizeof(supply_xref));
+ if (rv >= 0) {
+ rv = OF_getprop_alloc(supply_xref, "regulator-name", 1,
+ (void **)&def->parent_name);
+ if (rv <= 0)
+ def->parent_name = NULL;
+ }
+ return (0);
+}
+
+int
+regulator_get_by_ofw_property(device_t cdev, char *name, regulator_t *reg)
+{
+ phandle_t cnode, *cells;
+ device_t regdev;
+ int ncells, rv;
+ intptr_t id;
+
+ *reg = NULL;
+
+ cnode = ofw_bus_get_node(cdev);
+ if (cnode <= 0) {
+ device_printf(cdev, "%s called on not ofw based device\n",
+ __func__);
+ return (ENXIO);
+ }
+
+ cells = NULL;
+ ncells = OF_getencprop_alloc(cnode, name, sizeof(*cells),
+ (void **)&cells);
+ if (ncells <= 0)
+ return (ENXIO);
+
+ /* Translate xref to device */
+ regdev = OF_device_from_xref(cells[0]);
+ if (regdev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+
+ /* Map regulator to number */
+ rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+ return (regulator_get_by_id(cdev, regdev, id, reg));
+}
+#endif
diff --git a/sys/dev/extres/regulator/regulator.h b/sys/dev/extres/regulator/regulator.h
new file mode 100644
index 0000000..380bad6
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator.h
@@ -0,0 +1,127 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_EXTRES_REGULATOR_H_
+#define _DEV_EXTRES_REGULATOR_H_
+#include "opt_platform.h"
+
+#include <sys/kobj.h>
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#endif
+#include "regnode_if.h"
+
+#define REGULATOR_FLAGS_STATIC 0x00000001 /* Static strings */
+#define REGULATOR_FLAGS_NOT_DISABLE 0x00000002 /* Cannot be disabled */
+
+#define REGULATOR_STATUS_ENABLED 0x00000001
+#define REGULATOR_STATUS_OVERCURRENT 0x00000002
+
+typedef struct regulator *regulator_t;
+
+/* Standard regulator parameters. */
+struct regnode_std_param {
+ int min_uvolt; /* In uV */
+ int max_uvolt; /* In uV */
+ int min_uamp; /* In uA */
+ int max_uamp; /* In uA */
+ int ramp_delay; /* In uV/usec */
+ int enable_delay; /* In usec */
+ bool boot_on; /* Is enabled on boot */
+ bool always_on; /* Must be enabled */
+ int enable_active_high;
+};
+
+/* Initialization parameters. */
+struct regnode_init_def {
+ char *name; /* Regulator name */
+ char *parent_name; /* Name of parent regulator */
+ struct regnode_std_param std_param; /* Standard parameters */
+ intptr_t id; /* Regulator ID */
+ int flags; /* Flags */
+#ifdef FDT
+ phandle_t ofw_node; /* OFW node of regulator */
+#endif
+
+};
+
+/*
+ * Shorthands for constructing method tables.
+ */
+#define REGNODEMETHOD KOBJMETHOD
+#define REGNODEMETHOD_END KOBJMETHOD_END
+#define regnode_method_t kobj_method_t
+#define regnode_class_t kobj_class_t
+DECLARE_CLASS(regnode_class);
+
+/* Providers interface. */
+struct regnode *regnode_create(device_t pdev, regnode_class_t regnode_class,
+ struct regnode_init_def *def);
+struct regnode *regnode_register(struct regnode *regnode);
+const char *regnode_get_name(struct regnode *regnode);
+const char *regnode_get_parent_name(struct regnode *regnode);
+struct regnode *regnode_get_parent(struct regnode *regnode);
+int regnode_get_flags(struct regnode *regnode);
+void *regnode_get_softc(struct regnode *regnode);
+device_t regnode_get_device(struct regnode *regnode);
+struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode);
+void regnode_topo_unlock(void);
+void regnode_topo_xlock(void);
+void regnode_topo_slock(void);
+
+int regnode_enable(struct regnode *regnode);
+int regnode_disable(struct regnode *regnode);
+int regnode_stop(struct regnode *regnode, int depth);
+int regnode_status(struct regnode *regnode, int *status);
+int regnode_get_voltage(struct regnode *regnode, int *uvolt);
+int regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt);
+#ifdef FDT
+phandle_t regnode_get_ofw_node(struct regnode *regnode);
+#endif
+
+/* Consumers interface. */
+int regulator_get_by_name(device_t cdev, const char *name,
+ regulator_t *regulator);
+int regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id,
+ regulator_t *regulator);
+int regulator_release(regulator_t regulator);
+const char *regulator_get_name(regulator_t regulator);
+int regulator_enable(regulator_t reg);
+int regulator_disable(regulator_t reg);
+int regulator_stop(regulator_t reg);
+int regulator_status(regulator_t reg, int *status);
+int regulator_get_voltage(regulator_t reg, int *uvolt);
+int regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt);
+
+#ifdef FDT
+int regulator_get_by_ofw_property(device_t dev, char *name, regulator_t *reg);
+int regulator_parse_ofw_stdparam(device_t dev, phandle_t node,
+ struct regnode_init_def *def);
+#endif
+
+#endif /* _DEV_EXTRES_REGULATOR_H_ */
diff --git a/sys/dev/extres/regulator/regulator_bus.c b/sys/dev/extres/regulator/regulator_bus.c
new file mode 100644
index 0000000..5e7f4c9
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator_bus.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+struct ofw_regulator_bus_softc {
+ struct simplebus_softc simplebus_sc;
+};
+
+static int
+ofw_regulator_bus_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+ if (name == NULL || strcmp(name, "regulators") != 0)
+ return (ENXIO);
+ device_set_desc(dev, "OFW regulators bus");
+
+ return (0);
+}
+
+static int
+ofw_regulator_bus_attach(device_t dev)
+{
+ struct ofw_regulator_bus_softc *sc;
+ phandle_t node, child;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ simplebus_init(dev, node);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t ofw_regulator_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_regulator_bus_probe),
+ DEVMETHOD(device_attach, ofw_regulator_bus_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofw_regulator_bus, ofw_regulator_bus_driver,
+ ofw_regulator_bus_methods, sizeof(struct ofw_regulator_bus_softc),
+ simplebus_driver);
+static devclass_t ofw_regulator_bus_devclass;
+EARLY_DRIVER_MODULE(ofw_regulator_bus, simplebus, ofw_regulator_bus_driver,
+ ofw_regulator_bus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofw_regulator_bus, 1);
diff --git a/sys/dev/extres/regulator/regulator_fixed.c b/sys/dev/extres/regulator/regulator_fixed.c
new file mode 100644
index 0000000..5a44a72
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator_fixed.c
@@ -0,0 +1,456 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/extres/regulator/regulator_fixed.h>
+
+#include "regdev_if.h"
+
+MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator");
+
+/* GPIO list for shared pins. */
+typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t;
+struct gpio_entry {
+ TAILQ_ENTRY(gpio_entry) link;
+ struct gpiobus_pin gpio_pin;
+ int use_cnt;
+ int enable_cnt;
+};
+static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list);
+static struct mtx gpio_list_mtx;
+MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF);
+
+struct regnode_fixed_sc {
+ struct regnode_std_param *param;
+ bool gpio_open_drain;
+ struct gpio_entry *gpio_entry;
+};
+
+static int regnode_fixed_init(struct regnode *regnode);
+static int regnode_fixed_enable(struct regnode *regnode, bool enable,
+ int *udelay);
+static int regnode_fixed_status(struct regnode *regnode, int *status);
+
+static regnode_method_t regnode_fixed_methods[] = {
+ /* Regulator interface */
+ REGNODEMETHOD(regnode_init, regnode_fixed_init),
+ REGNODEMETHOD(regnode_enable, regnode_fixed_enable),
+ REGNODEMETHOD(regnode_status, regnode_fixed_status),
+ REGNODEMETHOD_END
+};
+DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods,
+ sizeof(struct regnode_fixed_sc), regnode_class);
+
+/*
+ * GPIO list functions.
+ * Two or more regulators can share single GPIO pins, so we must track all
+ * GPIOs in gpio_list.
+ * The GPIO pin is registerd and reseved for first consumer, all others share
+ * gpio_entry with it.
+ */
+static struct gpio_entry *
+regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
+{
+ struct gpio_entry *entry, *tmp;
+ device_t busdev;
+ int rv;
+
+ busdev = GPIO_GET_BUS(gpio_pin->dev);
+ if (busdev == NULL)
+ return (NULL);
+ entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR,
+ M_WAITOK | M_ZERO);
+
+ mtx_lock(&gpio_list_mtx);
+
+ TAILQ_FOREACH(tmp, &gpio_list, link) {
+ if (tmp->gpio_pin.dev == gpio_pin->dev &&
+ tmp->gpio_pin.pin == gpio_pin->pin) {
+ tmp->use_cnt++;
+ mtx_unlock(&gpio_list_mtx);
+ free(entry, M_FIXEDREGULATOR);
+ return (tmp);
+ }
+ }
+
+ /* Reserve pin. */
+ /* XXX Can we call gpiobus_map_pin() with gpio_list_mtx mutex held? */
+ rv = gpiobus_map_pin(busdev, gpio_pin->pin);
+ if (rv != 0) {
+ mtx_unlock(&gpio_list_mtx);
+ free(entry, M_FIXEDREGULATOR);
+ return (NULL);
+ }
+ /* Everything is OK, build new entry and insert it to list. */
+ entry->gpio_pin = *gpio_pin;
+ entry->use_cnt = 1;
+ TAILQ_INSERT_TAIL(&gpio_list, entry, link);
+
+ mtx_unlock(&gpio_list_mtx);
+ return (entry);
+}
+
+
+/*
+ * Regulator class implementation.
+ */
+static int
+regnode_fixed_init(struct regnode *regnode)
+{
+ device_t dev;
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ uint32_t flags;
+ bool enable;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+ dev = regnode_get_device(regnode);
+ sc->param = regnode_get_stdparam(regnode);
+ if (sc->gpio_entry == NULL)
+ return (0);
+ pin = &sc->gpio_entry->gpio_pin;
+
+ flags = GPIO_PIN_OUTPUT;
+ if (sc->gpio_open_drain)
+ flags |= GPIO_PIN_OPENDRAIN;
+ enable = sc->param->boot_on || sc->param->always_on;
+ if (!sc->param->enable_active_high)
+ enable = !enable;
+ rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+ rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags);
+ if (rv != 0) {
+ device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+
+ return (0);
+}
+
+/*
+ * Enable/disable regulator.
+ * Take shared GPIO pins in account
+ */
+static int
+regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay)
+{
+ device_t dev;
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+ dev = regnode_get_device(regnode);
+
+ *udelay = 0;
+ if (sc->param->always_on && !enable)
+ return (0);
+ if (sc->gpio_entry == NULL)
+ return (0);
+ pin = &sc->gpio_entry->gpio_pin;
+ if (enable) {
+ sc->gpio_entry->enable_cnt++;
+ if (sc->gpio_entry->enable_cnt > 1)
+ return (0);
+ } else {
+ KASSERT(sc->gpio_entry->enable_cnt > 0,
+ ("Invalid enable count"));
+ sc->gpio_entry->enable_cnt--;
+ if (sc->gpio_entry->enable_cnt >= 1)
+ return (0);
+ }
+ if (!sc->param->enable_active_high)
+ enable = !enable;
+ rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+ *udelay = sc->param->enable_delay;
+ return (0);
+}
+
+static int
+regnode_fixed_status(struct regnode *regnode, int *status)
+{
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ uint32_t val;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+
+ *status = 0;
+ if (sc->gpio_entry == NULL) {
+ *status = REGULATOR_STATUS_ENABLED;
+ return (0);
+ }
+ pin = &sc->gpio_entry->gpio_pin;
+
+ rv = GPIO_PIN_GET(pin->dev, pin->pin, &val);
+ if (rv == 0) {
+ if (!sc->param->enable_active_high ^ (val != 0))
+ *status = REGULATOR_STATUS_ENABLED;
+ }
+ return (rv);
+}
+
+int
+regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def)
+{
+ struct regnode *regnode;
+ struct regnode_fixed_sc *sc;
+
+ regnode = regnode_create(dev, &regnode_fixed_class,
+ &init_def->reg_init_def);
+ if (regnode == NULL) {
+ device_printf(dev, "Cannot create regulator.\n");
+ return(ENXIO);
+ }
+ sc = regnode_get_softc(regnode);
+ sc->gpio_open_drain = init_def->gpio_open_drain;
+ if (init_def->gpio_pin != NULL) {
+ sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin);
+ if (sc->gpio_entry == NULL)
+ return(ENXIO);
+ }
+ regnode = regnode_register(regnode);
+ if (regnode == NULL) {
+ device_printf(dev, "Cannot register regulator.\n");
+ return(ENXIO);
+ }
+ return (0);
+}
+
+/*
+ * OFW Driver implementation.
+ */
+#ifdef FDT
+
+struct regfix_softc
+{
+ device_t dev;
+ bool attach_done;
+ struct regnode_fixed_init_def init_def;
+ phandle_t gpio_prodxref;
+ pcell_t *gpio_cells;
+ int gpio_ncells;
+ struct gpiobus_pin gpio_pin;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"regulator-fixed", 1},
+ {NULL, 0},
+};
+
+static int
+regfix_get_gpio(struct regfix_softc * sc)
+{
+ device_t busdev;
+ phandle_t node;
+
+ int rv;
+
+ if (sc->gpio_prodxref == 0)
+ return (0);
+
+ node = ofw_bus_get_node(sc->dev);
+
+ /* Test if controller exist. */
+ sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref);
+ if (sc->gpio_pin.dev == NULL)
+ return (ENODEV);
+
+ /* Test if GPIO bus already exist. */
+ busdev = GPIO_GET_BUS(sc->gpio_pin.dev);
+ if (busdev == NULL)
+ return (ENODEV);
+
+ rv = gpio_map_gpios(sc->gpio_pin.dev, node,
+ OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells,
+ sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags));
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot map the gpio property.\n");
+ return (ENXIO);
+ }
+ sc->init_def.gpio_pin = &sc->gpio_pin;
+ return (0);
+}
+
+static int
+regfix_parse_fdt(struct regfix_softc * sc)
+{
+ phandle_t node;
+ int rv;
+ struct regnode_init_def *init_def;
+
+ node = ofw_bus_get_node(sc->dev);
+ init_def = &sc->init_def.reg_init_def;
+
+ rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse standard parameters.\n");
+ return(rv);
+ }
+
+ /* Fixed regulator uses 'startup-delay-us' property for enable_delay */
+ rv = OF_getencprop(node, "startup-delay-us",
+ &init_def->std_param.enable_delay,
+ sizeof(init_def->std_param.enable_delay));
+ if (rv <= 0)
+ init_def->std_param.enable_delay = 0;
+ /* GPIO pin */
+ if (OF_hasprop(node, "gpio-open-drain"))
+ sc->init_def.gpio_open_drain = true;
+
+ if (!OF_hasprop(node, "gpio"))
+ return (0);
+ rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0,
+ &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells);
+ if (rv != 0) {
+ sc->gpio_prodxref = 0;
+ device_printf(sc->dev, "Malformed gpio property\n");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+static void
+regfix_new_pass(device_t dev)
+{
+ struct regfix_softc * sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ bus_generic_new_pass(dev);
+
+ if (sc->attach_done)
+ return;
+
+ /* Try to get and configure GPIO. */
+ rv = regfix_get_gpio(sc);
+ if (rv != 0)
+ return;
+
+ /* Register regulator. */
+ regnode_fixed_register(sc->dev, &sc->init_def);
+ sc->attach_done = true;
+}
+
+static int
+regfix_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Fixed Regulator");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+regfix_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static int
+regfix_attach(device_t dev)
+{
+ struct regfix_softc * sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ /* Parse FDT data. */
+ rv = regfix_parse_fdt(sc);
+ if (rv != 0)
+ return(ENXIO);
+
+ /* Fill reset of init. */
+ sc->init_def.reg_init_def.id = 1;
+ sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC;
+
+ /* Try to get and configure GPIO. */
+ rv = regfix_get_gpio(sc);
+ if (rv != 0)
+ return (bus_generic_attach(dev));
+
+ /* Register regulator. */
+ regnode_fixed_register(sc->dev, &sc->init_def);
+ sc->attach_done = true;
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t regfix_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, regfix_probe),
+ DEVMETHOD(device_attach, regfix_attach),
+ DEVMETHOD(device_detach, regfix_detach),
+ /* Bus interface */
+ DEVMETHOD(bus_new_pass, regfix_new_pass),
+ /* Regdev interface */
+ DEVMETHOD(regdev_map, regdev_default_ofw_map),
+
+ DEVMETHOD_END
+};
+
+static devclass_t regfix_devclass;
+DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods,
+ sizeof(struct regfix_softc));
+EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver,
+ regfix_devclass, 0, 0, BUS_PASS_BUS);
+
+#endif /* FDT */
diff --git a/sys/compat/cloudabi64/cloudabi64_syscalldefs.h b/sys/dev/extres/regulator/regulator_fixed.h
index d57f5f4..5cc0751 100644
--- a/sys/compat/cloudabi64/cloudabi64_syscalldefs.h
+++ b/sys/dev/extres/regulator/regulator_fixed.h
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Nuxi, https://nuxi.nl/
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,21 +26,19 @@
* $FreeBSD$
*/
-#ifndef _CLOUDABI64_SYSCALLDEFS_H_
-#define _CLOUDABI64_SYSCALLDEFS_H_
+#ifndef _DEV_EXTRES_REGULATOR_FIXED_H_
+#define _DEV_EXTRES_REGULATOR_FIXED_H_
-#include <sys/types.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/extres/regulator/regulator.h>
-#include <compat/cloudabi/cloudabi_syscalldefs.h>
+struct regnode_fixed_init_def {
+ struct regnode_init_def reg_init_def;
+ bool gpio_open_drain;
+ struct gpiobus_pin *gpio_pin;
+};
-typedef uint64_t cloudabi64_size_t;
-typedef uint64_t cloudabi64_uintptr_t;
+int regnode_fixed_register(device_t dev,
+ struct regnode_fixed_init_def *init_def);
-/* Import machine-dependent CloudABI definitions for 64-bit systems. */
-#define IDENT(ident) cloudabi64_##ident
-#define PTR(type) cloudabi64_uintptr_t
-#include <contrib/cloudabi/syscalldefs_md.h>
-#undef IDENT
-#undef PTR
-
-#endif
+#endif /*_DEV_EXTRES_REGULATOR_FIXED_H_*/
diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c
index 6211aca..73f7ada 100644
--- a/sys/dev/fdt/fdt_common.c
+++ b/sys/dev/fdt/fdt_common.c
@@ -722,3 +722,16 @@ fdt_get_unit(device_t dev)
return (strtol(name,NULL,0));
}
+
+int
+fdt_get_chosen_bootargs(char *bootargs, size_t max_size)
+{
+ phandle_t chosen;
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return (ENXIO);
+ if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1)
+ return (ENXIO);
+ return (0);
+} \ No newline at end of file
diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h
index db27b43..17af344 100644
--- a/sys/dev/fdt/fdt_common.h
+++ b/sys/dev/fdt/fdt_common.h
@@ -100,5 +100,6 @@ int fdt_parent_addr_cells(phandle_t);
int fdt_reg_to_rl(phandle_t, struct resource_list *);
int fdt_pm(phandle_t);
int fdt_get_unit(device_t);
+int fdt_get_chosen_bootargs(char *bootargs, size_t max_size);
#endif /* _FDT_COMMON_H_ */
diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index 36c278f..8d43a70 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -369,7 +369,7 @@ simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
if (j == sc->nranges && sc->nranges != 0) {
if (bootverbose)
device_printf(bus, "Could not map resource "
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
@@ -387,8 +387,8 @@ simplebus_print_res(struct simplebus_devinfo *di)
if (di == NULL)
return (0);
rv = 0;
- rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c
index cd40c5a..10f27ad 100644
--- a/sys/dev/filemon/filemon.c
+++ b/sys/dev/filemon/filemon.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/poll.h>
#include <sys/proc.h>
-#include <sys/queue.h>
#include <sys/sx.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
@@ -80,23 +79,112 @@ static struct cdevsw filemon_cdevsw = {
MALLOC_DECLARE(M_FILEMON);
MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor");
+/*
+ * The filemon->lock protects several things currently:
+ * - fname1/fname2/msgbufr are pre-allocated and used per syscall
+ * for logging and copyins rather than stack variables.
+ * - Serializing the filemon's log output.
+ * - Preventing inheritance or removal of the filemon into proc.p_filemon.
+ */
struct filemon {
- TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */
- struct sx lock; /* Lock mutex for this filemon. */
+ struct sx lock; /* Lock for this filemon. */
struct file *fp; /* Output file pointer. */
- struct proc *p; /* The process being monitored. */
char fname1[MAXPATHLEN]; /* Temporary filename buffer. */
char fname2[MAXPATHLEN]; /* Temporary filename buffer. */
char msgbufr[1024]; /* Output message buffer. */
+ int error; /* Log write error, returned on close(2). */
+ u_int refcnt; /* Pointer reference count. */
+ u_int proccnt; /* Process count. */
};
-static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse);
-static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free);
-static struct sx access_lock;
-
static struct cdev *filemon_dev;
+static void filemon_output(struct filemon *filemon, char *msg, size_t len);
+
+static __inline struct filemon *
+filemon_acquire(struct filemon *filemon)
+{
+
+ if (filemon != NULL)
+ refcount_acquire(&filemon->refcnt);
+ return (filemon);
+}
+
+/*
+ * Release a reference and free on the last one.
+ */
+static void
+filemon_release(struct filemon *filemon)
+{
+
+ if (refcount_release(&filemon->refcnt) == 0)
+ return;
+ /*
+ * There are valid cases of releasing while locked, such as in
+ * filemon_untrack_processes, but none which are done where there
+ * is not at least 1 reference remaining.
+ */
+ sx_assert(&filemon->lock, SA_UNLOCKED);
+
+ sx_destroy(&filemon->lock);
+ free(filemon, M_FILEMON);
+}
+
+/*
+ * Acquire the proc's p_filemon reference and lock the filemon.
+ * The proc's p_filemon may not match this filemon on return.
+ */
+static struct filemon *
+filemon_proc_get(struct proc *p)
+{
+ struct filemon *filemon;
+
+ PROC_LOCK(p);
+ filemon = filemon_acquire(p->p_filemon);
+ PROC_UNLOCK(p);
+
+ if (filemon == NULL)
+ return (NULL);
+ /*
+ * The p->p_filemon may have changed by now. That case is handled
+ * by the exit and fork hooks and filemon_attach_proc specially.
+ */
+ sx_xlock(&filemon->lock);
+ return (filemon);
+}
+
+/* Remove and release the filemon on the given process. */
+static void
+filemon_proc_drop(struct proc *p)
+{
+ struct filemon *filemon;
+
+ KASSERT(p->p_filemon != NULL, ("%s: proc %p NULL p_filemon",
+ __func__, p));
+ sx_assert(&p->p_filemon->lock, SA_XLOCKED);
+ PROC_LOCK(p);
+ filemon = p->p_filemon;
+ p->p_filemon = NULL;
+ --filemon->proccnt;
+ PROC_UNLOCK(p);
+ /*
+ * This should not be the last reference yet. filemon_release()
+ * cannot be called with filemon locked, which the caller expects
+ * will stay locked.
+ */
+ KASSERT(filemon->refcnt > 1, ("%s: proc %p dropping filemon %p "
+ "with last reference", __func__, p, filemon));
+ filemon_release(filemon);
+}
+
+/* Unlock and release the filemon. */
+static __inline void
+filemon_drop(struct filemon *filemon)
+{
+
+ sx_xunlock(&filemon->lock);
+ filemon_release(filemon);
+}
-#include "filemon_lock.c"
#include "filemon_wrapper.c"
static void
@@ -115,35 +203,151 @@ filemon_comment(struct filemon *filemon)
filemon_output(filemon, filemon->msgbufr, len);
}
+/*
+ * Invalidate the passed filemon in all processes.
+ */
static void
-filemon_dtr(void *data)
+filemon_untrack_processes(struct filemon *filemon)
{
- struct filemon *filemon = data;
+ struct proc *p;
- if (filemon != NULL) {
- struct file *fp;
+ sx_assert(&filemon->lock, SA_XLOCKED);
- /* Follow same locking order as filemon_pid_check. */
- filemon_lock_write();
- sx_xlock(&filemon->lock);
+ /* Avoid allproc loop if there is no need. */
+ if (filemon->proccnt == 0)
+ return;
+
+ /*
+ * Processes in this list won't go away while here since
+ * filemon_event_process_exit() will lock on filemon->lock
+ * which we hold.
+ */
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ /*
+ * No PROC_LOCK is needed to compare here since it is
+ * guaranteed to not change since we have its filemon
+ * locked. Everything that changes this p_filemon will
+ * be locked on it.
+ */
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+ }
+ sx_sunlock(&allproc_lock);
+
+ /*
+ * It's possible some references were acquired but will be
+ * dropped shortly as they are restricted from being
+ * inherited. There is at least the reference in cdevpriv remaining.
+ */
+ KASSERT(filemon->refcnt > 0, ("%s: filemon %p should have "
+ "references still.", __func__, filemon));
+ KASSERT(filemon->proccnt == 0, ("%s: filemon %p should not have "
+ "attached procs still.", __func__, filemon));
+}
- /* Remove from the in-use list. */
- TAILQ_REMOVE(&filemons_inuse, filemon, link);
+/*
+ * Close out the log.
+ */
+static void
+filemon_close_log(struct filemon *filemon)
+{
+ struct file *fp;
+ struct timeval now;
+ size_t len;
- fp = filemon->fp;
- filemon->fp = NULL;
- filemon->p = NULL;
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ if (filemon->fp == NULL)
+ return;
- /* Add to the free list. */
- TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
+ getmicrotime(&now);
- /* Give up write access. */
- sx_xunlock(&filemon->lock);
- filemon_unlock_write();
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr),
+ "# Stop %ju.%06ju\n# Bye bye\n",
+ (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
+
+ filemon_output(filemon, filemon->msgbufr, len);
+ fp = filemon->fp;
+ filemon->fp = NULL;
+
+ sx_xunlock(&filemon->lock);
+ fdrop(fp, curthread);
+ sx_xlock(&filemon->lock);
+}
+
+/*
+ * The devfs file is being closed. Untrace all processes. It is possible
+ * filemon_close/close(2) was not called.
+ */
+static void
+filemon_dtr(void *data)
+{
+ struct filemon *filemon = data;
- if (fp != NULL)
- fdrop(fp, curthread);
+ if (filemon == NULL)
+ return;
+
+ sx_xlock(&filemon->lock);
+ /*
+ * Detach the filemon. It cannot be inherited after this.
+ */
+ filemon_untrack_processes(filemon);
+ filemon_close_log(filemon);
+ filemon_drop(filemon);
+}
+
+/* Attach the filemon to the process. */
+static int
+filemon_attach_proc(struct filemon *filemon, struct proc *p)
+{
+ struct filemon *filemon2;
+
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ KASSERT((p->p_flag & P_WEXIT) == 0,
+ ("%s: filemon %p attaching to exiting process %p",
+ __func__, filemon, p));
+
+ if (p->p_filemon == filemon)
+ return (0);
+ /*
+ * Don't allow truncating other process traces. It is
+ * not really intended to trace procs other than curproc
+ * anyhow.
+ */
+ if (p->p_filemon != NULL && p != curproc)
+ return (EBUSY);
+ /*
+ * Historic behavior of filemon has been to let a child initiate
+ * tracing on itself and cease existing tracing. Bmake
+ * .META + .MAKE relies on this. It is only relevant for attaching to
+ * curproc.
+ */
+ while (p->p_filemon != NULL) {
+ PROC_UNLOCK(p);
+ sx_xunlock(&filemon->lock);
+ while ((filemon2 = filemon_proc_get(p)) != NULL) {
+ /* It may have changed. */
+ if (p->p_filemon == filemon2)
+ filemon_proc_drop(p);
+ filemon_drop(filemon2);
+ }
+ sx_xlock(&filemon->lock);
+ PROC_LOCK(p);
+ /*
+ * It may have been attached to, though unlikely.
+ * Try again if needed.
+ */
}
+
+ KASSERT(p->p_filemon == NULL,
+ ("%s: proc %p didn't detach filemon %p", __func__, p,
+ p->p_filemon));
+ p->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+
+ return (0);
}
static int
@@ -178,10 +382,16 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
/* Set the monitored process ID. */
case FILEMON_SET_PID:
+ /* Invalidate any existing processes already set. */
+ filemon_untrack_processes(filemon);
+
error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT,
&p);
if (error == 0) {
- filemon->p = p;
+ KASSERT(p->p_filemon != filemon,
+ ("%s: proc %p didn't untrack filemon %p",
+ __func__, p, filemon));
+ error = filemon_attach_proc(filemon, p);
PROC_UNLOCK(p);
}
break;
@@ -199,49 +409,48 @@ static int
filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused,
struct thread *td __unused)
{
+ int error;
struct filemon *filemon;
- /* Get exclusive write access. */
- filemon_lock_write();
-
- if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL)
- TAILQ_REMOVE(&filemons_free, filemon, link);
-
- /* Give up write access. */
- filemon_unlock_write();
-
- if (filemon == NULL) {
- filemon = malloc(sizeof(struct filemon), M_FILEMON,
- M_WAITOK | M_ZERO);
- sx_init(&filemon->lock, "filemon");
- }
-
- devfs_set_cdevpriv(filemon, filemon_dtr);
-
- /* Get exclusive write access. */
- filemon_lock_write();
+ filemon = malloc(sizeof(*filemon), M_FILEMON,
+ M_WAITOK | M_ZERO);
+ sx_init(&filemon->lock, "filemon");
+ refcount_init(&filemon->refcnt, 1);
- /* Add to the in-use list. */
- TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link);
+ error = devfs_set_cdevpriv(filemon, filemon_dtr);
+ if (error != 0)
+ filemon_release(filemon);
- /* Give up write access. */
- filemon_unlock_write();
-
- return (0);
+ return (error);
}
+/* Called on close of last devfs file handle, before filemon_dtr(). */
static int
filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused,
struct thread *td __unused)
{
+ struct filemon *filemon;
+ int error;
- return (0);
+ if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0)
+ return (error);
+
+ sx_xlock(&filemon->lock);
+ filemon_close_log(filemon);
+ error = filemon->error;
+ sx_xunlock(&filemon->lock);
+ /*
+ * Processes are still being traced but won't log anything
+ * now. After this call returns filemon_dtr() is called which
+ * will detach processes.
+ */
+
+ return (error);
}
static void
filemon_load(void *dummy __unused)
{
- sx_init(&access_lock, "filemons_inuse");
/* Install the syscall wrappers. */
filemon_wrapper_install();
@@ -253,38 +462,11 @@ filemon_load(void *dummy __unused)
static int
filemon_unload(void)
{
- struct filemon *filemon;
- int error = 0;
-
- /* Get exclusive write access. */
- filemon_lock_write();
-
- if (TAILQ_FIRST(&filemons_inuse) != NULL)
- error = EBUSY;
- else {
- destroy_dev(filemon_dev);
-
- /* Deinstall the syscall wrappers. */
- filemon_wrapper_deinstall();
- }
- /* Give up write access. */
- filemon_unlock_write();
+ destroy_dev(filemon_dev);
+ filemon_wrapper_deinstall();
- if (error == 0) {
- /* free() filemon structs free list. */
- filemon_lock_write();
- while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) {
- TAILQ_REMOVE(&filemons_free, filemon, link);
- sx_destroy(&filemon->lock);
- free(filemon, M_FILEMON);
- }
- filemon_unlock_write();
-
- sx_destroy(&access_lock);
- }
-
- return (error);
+ return (0);
}
static int
diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c
index 6911dc5..87c9392 100644
--- a/sys/dev/filemon/filemon_wrapper.c
+++ b/sys/dev/filemon/filemon_wrapper.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/imgact.h>
#include <sys/eventhandler.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
#include <sys/sx.h>
#include <sys/vnode.h>
@@ -45,6 +46,7 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
{
struct uio auio;
struct iovec aiov;
+ int error;
if (filemon->fp == NULL)
return;
@@ -62,56 +64,33 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
if (filemon->fp->f_type == DTYPE_VNODE)
bwillwrite();
- fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
-}
-
-static struct filemon *
-filemon_pid_check(struct proc *p)
-{
- struct filemon *filemon;
-
- filemon_lock_read();
- if (TAILQ_EMPTY(&filemons_inuse)) {
- filemon_unlock_read();
- return (NULL);
- }
- sx_slock(&proctree_lock);
- while (p->p_pid != 0) {
- TAILQ_FOREACH(filemon, &filemons_inuse, link) {
- if (p == filemon->p) {
- sx_sunlock(&proctree_lock);
- sx_xlock(&filemon->lock);
- filemon_unlock_read();
- return (filemon);
- }
- }
- p = proc_realparent(p);
- }
- sx_sunlock(&proctree_lock);
- filemon_unlock_read();
- return (NULL);
+ error = fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
+ if (error != 0)
+ filemon->error = error;
}
static int
filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_chdir(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "C %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -126,12 +105,11 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
char *fullpath, *freepath;
size_t len;
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
fullpath = "<unknown>";
freepath = NULL;
- vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
- &freepath);
+ vn_fullpath(curthread, imgp->vp, &fullpath, &freepath);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "E %d %s\n",
@@ -139,321 +117,244 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
free(freepath, M_TEMP);
}
}
-static int
-filemon_wrapper_open(struct thread *td, struct open_args *uap)
+static void
+_filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
{
- int ret;
- size_t done;
+ int error;
size_t len;
+ struct file *fp;
struct filemon *filemon;
+ char *atpath, *freepath;
+ cap_rights_t rights;
- if ((ret = sys_open(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- if (uap->flags & O_RDWR) {
- /*
- * We'll get the W record below, but need
- * to also output an R to distingish from
- * O_WRONLY.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "R %d %s\n",
- curproc->p_pid, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ atpath = "";
+ freepath = NULL;
+ fp = NULL;
+ if ((error = copyinstr(upath, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
+ if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
+ /*
+ * rats - we cannot do too much about this.
+ * the trace should show a dir we read
+ * recently.. output an A record as a clue
+ * until we can do better.
+ * XXX: This may be able to come out with
+ * the namecache lookup now.
+ */
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "%c %d %s\n",
- (uap->flags & O_ACCMODE) ? 'W':'R',
+ sizeof(filemon->msgbufr), "A %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+ /*
+ * Try to resolve the path from the vnode using the
+ * namecache. It may be inaccurate, but better
+ * than nothing.
+ */
+ if (getvnode(td, fd,
+ cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
+ vn_fullpath(td, fp->f_vnode, &atpath,
+ &freepath);
+ }
+ }
+ if (flags & O_RDWR) {
+ /*
+ * We'll get the W record below, but need
+ * to also output an R to distinguish from
+ * O_WRONLY.
+ */
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "R %d %s%s%s\n",
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
}
- }
- return (ret);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
+ (flags & O_ACCMODE) ? 'W':'R',
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
+ if (fp != NULL)
+ fdrop(fp, td);
+ free(freepath, M_TEMP);
+ }
}
static int
-filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
+filemon_wrapper_open(struct thread *td, struct open_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_openat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- filemon->fname2[0] = '\0';
- if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
- /*
- * rats - we cannot do too much about this.
- * the trace should show a dir we read
- * recently.. output an A record as a clue
- * until we can do better.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "A %d %s\n",
- curproc->p_pid, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
- if (uap->flag & O_RDWR) {
- /*
- * We'll get the W record below, but need
- * to also output an R to distingish from
- * O_WRONLY.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "R %d %s%s\n",
- curproc->p_pid, filemon->fname2, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
-
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "%c %d %s%s\n",
- (uap->flag & O_ACCMODE) ? 'W':'R',
- curproc->p_pid, filemon->fname2, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_open(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
return (ret);
}
static int
-filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
+filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_rename(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->from, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->to, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
-
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_openat(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
return (ret);
}
static int
-filemon_wrapper_link(struct thread *td, struct link_args *uap)
+filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
- if ((ret = sys_link(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->link, filemon->fname2,
- sizeof(filemon->fname2), &done);
+ if ((ret = sys_rename(td, uap)) == 0) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(uap->from, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(uap->to, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
return (ret);
}
-static int
-filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
+static void
+_filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
{
- int ret;
- size_t done;
- size_t len;
struct filemon *filemon;
+ size_t len;
+ int error;
+
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(upath1, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(upath2, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
- if ((ret = sys_symlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->link, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
-
- filemon_output(filemon, filemon->msgbufr, len);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ curproc->p_pid, filemon->fname1, filemon->fname2);
- sx_xunlock(&filemon->lock);
- }
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
}
-
- return (ret);
}
static int
-filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
+filemon_wrapper_link(struct thread *td, struct link_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
-
- if ((ret = sys_linkat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path1, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->path2, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_link(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
return (ret);
}
static int
-filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
+filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "S %d %s\n",
- curproc->p_pid, filemon->fname1);
-
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_symlink(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
return (ret);
}
-#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
static int
-filemon_wrapper_freebsd32_stat(struct thread *td,
- struct freebsd32_stat_args *uap)
+filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
-
- if ((ret = freebsd32_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "S %d %s\n",
- curproc->p_pid, filemon->fname1);
-
- filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_linkat(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path1, uap->path2);
return (ret);
}
-#endif
static void
filemon_event_process_exit(void *arg __unused, struct proc *p)
{
size_t len;
struct filemon *filemon;
- struct timeval now;
- /* Get timestamp before locking. */
- getmicrotime(&now);
-
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
"X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig);
filemon_output(filemon, filemon->msgbufr, len);
- /* Check if the monitored process is about to exit. */
- if (filemon->p == p) {
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr),
- "# Stop %ju.%06ju\n# Bye bye\n",
- (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
-
- filemon_output(filemon, filemon->msgbufr, len);
- filemon->p = NULL;
- }
-
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() may have dropped this p_filemon
+ * already while in filemon_proc_get() before acquiring the
+ * filemon lock.
+ */
+ KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
+ ("%s: p %p was attached while exiting, expected "
+ "filemon %p or NULL", __func__, p, filemon));
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+
+ filemon_drop(filemon);
}
}
static int
filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_unlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "D %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -467,14 +368,34 @@ filemon_event_process_fork(void *arg __unused, struct proc *p1,
size_t len;
struct filemon *filemon;
- if ((filemon = filemon_pid_check(p1)) != NULL) {
+ if ((filemon = filemon_proc_get(p1)) != NULL) {
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "F %d %d\n",
p1->p_pid, p2->p_pid);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() or
+ * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
+ * p_filemon while in filemon_proc_get() before acquiring the
+ * filemon lock. Only inherit if the parent is still traced by
+ * this filemon.
+ */
+ if (p1->p_filemon == filemon) {
+ PROC_LOCK(p2);
+ /*
+ * It may have been attached to already by a new
+ * filemon.
+ */
+ if (p2->p_filemon == NULL) {
+ p2->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+ }
+ PROC_UNLOCK(p2);
+ }
+
+ filemon_drop(filemon);
}
}
@@ -491,7 +412,6 @@ filemon_wrapper_install(void)
sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
- sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -504,7 +424,6 @@ filemon_wrapper_install(void)
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
- sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -532,7 +451,6 @@ filemon_wrapper_deinstall(void)
sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
- sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
@@ -545,7 +463,6 @@ filemon_wrapper_deinstall(void)
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
- sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
diff --git a/sys/dev/flash/mx25l.c b/sys/dev/flash/mx25l.c
index c4dad4b..6b71340 100644
--- a/sys/dev/flash/mx25l.c
+++ b/sys/dev/flash/mx25l.c
@@ -26,6 +26,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
@@ -40,6 +42,12 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <geom/geom_disk.h>
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
#include <dev/spibus/spi.h>
#include "spibus_if.h"
@@ -48,6 +56,8 @@ __FBSDID("$FreeBSD$");
#define FL_NONE 0x00
#define FL_ERASE_4K 0x01
#define FL_ERASE_32K 0x02
+#define FL_ENABLE_4B_ADDR 0x04
+#define FL_DISABLE_4B_ADDR 0x08
/*
* Define the sectorsize to be a smaller size rather than the flash
@@ -105,6 +115,7 @@ struct mx25l_flash_ident flash_devices[] = {
{ "mx25ll32", 0xc2, 0x2016, 64 * 1024, 64, FL_NONE },
{ "mx25ll64", 0xc2, 0x2017, 64 * 1024, 128, FL_NONE },
{ "mx25ll128", 0xc2, 0x2018, 64 * 1024, 256, FL_ERASE_4K | FL_ERASE_32K },
+ { "mx25ll256", 0xc2, 0x2019, 64 * 1024, 512, FL_ERASE_4K | FL_ERASE_32K | FL_ENABLE_4B_ADDR },
{ "s25fl032", 0x01, 0x0215, 64 * 1024, 64, FL_NONE },
{ "s25fl064", 0x01, 0x0216, 64 * 1024, 128, FL_NONE },
{ "s25fl128", 0x01, 0x2018, 64 * 1024, 256, FL_NONE },
@@ -211,10 +222,13 @@ mx25l_set_writable(device_t dev, int writable)
static void
mx25l_erase_cmd(device_t dev, off_t sector, uint8_t ecmd)
{
- uint8_t txBuf[4], rxBuf[4];
+ struct mx25l_softc *sc;
+ uint8_t txBuf[5], rxBuf[5];
struct spi_command cmd;
int err;
+ sc = device_get_softc(dev);
+
mx25l_wait_for_device_ready(dev);
mx25l_set_writable(dev, 1);
@@ -225,11 +239,20 @@ mx25l_erase_cmd(device_t dev, off_t sector, uint8_t ecmd)
txBuf[0] = ecmd;
cmd.tx_cmd = txBuf;
cmd.rx_cmd = rxBuf;
- cmd.rx_cmd_sz = 4;
- cmd.tx_cmd_sz = 4;
- txBuf[1] = ((sector >> 16) & 0xff);
- txBuf[2] = ((sector >> 8) & 0xff);
- txBuf[3] = (sector & 0xff);
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.rx_cmd_sz = 5;
+ cmd.tx_cmd_sz = 5;
+ txBuf[1] = ((sector >> 24) & 0xff);
+ txBuf[2] = ((sector >> 16) & 0xff);
+ txBuf[3] = ((sector >> 8) & 0xff);
+ txBuf[4] = (sector & 0xff);
+ } else {
+ cmd.rx_cmd_sz = 4;
+ cmd.tx_cmd_sz = 4;
+ txBuf[1] = ((sector >> 16) & 0xff);
+ txBuf[2] = ((sector >> 8) & 0xff);
+ txBuf[3] = (sector & 0xff);
+ }
err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd);
}
@@ -247,8 +270,13 @@ mx25l_write(device_t dev, off_t offset, caddr_t data, off_t count)
pdev = device_get_parent(dev);
sc = device_get_softc(dev);
- cmd.tx_cmd_sz = 4;
- cmd.rx_cmd_sz = 4;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.tx_cmd_sz = 5;
+ cmd.rx_cmd_sz = 5;
+ } else {
+ cmd.tx_cmd_sz = 4;
+ cmd.rx_cmd_sz = 4;
+ }
bytes_writen = 0;
write_offset = offset;
@@ -282,9 +310,16 @@ mx25l_write(device_t dev, off_t offset, caddr_t data, off_t count)
mx25l_erase_cmd(dev, offset + bytes_writen, CMD_SECTOR_ERASE);
txBuf[0] = CMD_PAGE_PROGRAM;
- txBuf[1] = ((write_offset >> 16) & 0xff);
- txBuf[2] = ((write_offset >> 8) & 0xff);
- txBuf[3] = (write_offset & 0xff);
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ txBuf[1] = ((write_offset >> 24) & 0xff);
+ txBuf[2] = ((write_offset >> 16) & 0xff);
+ txBuf[3] = ((write_offset >> 8) & 0xff);
+ txBuf[4] = (write_offset & 0xff);
+ } else {
+ txBuf[1] = ((write_offset >> 16) & 0xff);
+ txBuf[2] = ((write_offset >> 8) & 0xff);
+ txBuf[3] = (write_offset & 0xff);
+ }
bytes_to_write = MIN(FLASH_PAGE_SIZE,
count - bytes_writen);
@@ -336,14 +371,26 @@ mx25l_read(device_t dev, off_t offset, caddr_t data, off_t count)
return (EIO);
txBuf[0] = CMD_FAST_READ;
- cmd.tx_cmd_sz = 5;
- cmd.rx_cmd_sz = 5;
-
- txBuf[1] = ((offset >> 16) & 0xff);
- txBuf[2] = ((offset >> 8) & 0xff);
- txBuf[3] = (offset & 0xff);
- /* Dummy byte */
- txBuf[4] = 0;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.tx_cmd_sz = 6;
+ cmd.rx_cmd_sz = 6;
+
+ txBuf[1] = ((offset >> 24) & 0xff);
+ txBuf[2] = ((offset >> 16) & 0xff);
+ txBuf[3] = ((offset >> 8) & 0xff);
+ txBuf[4] = (offset & 0xff);
+ /* Dummy byte */
+ txBuf[5] = 0;
+ } else {
+ cmd.tx_cmd_sz = 5;
+ cmd.rx_cmd_sz = 5;
+
+ txBuf[1] = ((offset >> 16) & 0xff);
+ txBuf[2] = ((offset >> 8) & 0xff);
+ txBuf[3] = (offset & 0xff);
+ /* Dummy byte */
+ txBuf[4] = 0;
+ }
cmd.tx_cmd = txBuf;
cmd.rx_cmd = rxBuf;
@@ -358,9 +405,45 @@ mx25l_read(device_t dev, off_t offset, caddr_t data, off_t count)
}
static int
+mx25l_set_4b_mode(device_t dev, uint8_t command)
+{
+ uint8_t txBuf[1], rxBuf[1];
+ struct spi_command cmd;
+ device_t pdev;
+ int err;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(txBuf, 0, sizeof(txBuf));
+ memset(rxBuf, 0, sizeof(rxBuf));
+
+ pdev = device_get_parent(dev);
+
+ cmd.tx_cmd_sz = cmd.rx_cmd_sz = 1;
+
+ cmd.tx_cmd = txBuf;
+ cmd.rx_cmd = rxBuf;
+
+ txBuf[0] = command;
+
+ err = SPIBUS_TRANSFER(pdev, dev, &cmd);
+
+ mx25l_wait_for_device_ready(dev);
+
+ return (err);
+}
+
+static int
mx25l_probe(device_t dev)
{
+
+#ifdef FDT
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "st,m25p"))
+ return (ENXIO);
+#endif
device_set_desc(dev, "M25Pxx Flash Family");
+
return (0);
}
@@ -397,6 +480,12 @@ mx25l_attach(device_t dev)
sc->sc_sectorsize = ident->sectorsize;
sc->sc_flags = ident->flags;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR)
+ mx25l_set_4b_mode(dev, CMD_ENTER_4B_MODE);
+
+ if (sc->sc_flags & FL_DISABLE_4B_ADDR)
+ mx25l_set_4b_mode(dev, CMD_EXIT_4B_MODE);
+
/* NB: use stripesize to hold the erase/region size for RedBoot */
sc->sc_disk->d_stripesize = ident->sectorsize;
diff --git a/sys/dev/flash/mx25lreg.h b/sys/dev/flash/mx25lreg.h
index 7253dba..5e303e1 100644
--- a/sys/dev/flash/mx25lreg.h
+++ b/sys/dev/flash/mx25lreg.h
@@ -45,6 +45,8 @@
#define CMD_BULK_ERASE 0xC7
#define CMD_BLOCK_4K_ERASE 0x20
#define CMD_BLOCK_32K_ERASE 0x52
+#define CMD_ENTER_4B_MODE 0xB7
+#define CMD_EXIT_4B_MODE 0xE9
/*
* Status register flags
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 44ab581..553d574 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -390,7 +390,7 @@ gpiobus_probe_nomatch(device_t dev, device_t child)
device_printf(dev, "<unknown device> at pins %s", pins);
else
device_printf(dev, "<unknown device> at pin %s", pins);
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
printf("\n");
}
@@ -412,7 +412,7 @@ gpiobus_print_child(device_t dev, device_t child)
gpiobus_print_pins(devi, pins, sizeof(pins));
retval += printf("%s", pins);
}
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
return (retval);
diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c
index be5a747..f6d2115 100644
--- a/sys/dev/gpio/ofw_gpiobus.c
+++ b/sys/dev/gpio/ofw_gpiobus.c
@@ -575,6 +575,7 @@ static devclass_t ofwgpiobus_devclass;
DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods,
sizeof(struct gpiobus_softc), gpiobus_driver);
-DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0);
+EARLY_DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass,
+ 0, 0, BUS_PASS_BUS);
MODULE_VERSION(ofw_gpiobus, 1);
MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1);
diff --git a/sys/dev/hyperv/include/hyperv.h b/sys/dev/hyperv/include/hyperv.h
index 0a057c8..26a2bfc 100644
--- a/sys/dev/hyperv/include/hyperv.h
+++ b/sys/dev/hyperv/include/hyperv.h
@@ -124,6 +124,8 @@ typedef struct hv_guid {
unsigned char data[16];
} __packed hv_guid;
+int snprintf_hv_guid(char *, size_t, const hv_guid *);
+
#define HV_NIC_GUID \
.data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, \
0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
index 0cec9a7..acc49b4 100644
--- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
+++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
@@ -181,6 +181,7 @@ struct hn_txdesc {
#define HN_CSUM_ASSIST_WIN8 (CSUM_IP | CSUM_TCP)
#define HN_CSUM_ASSIST (CSUM_IP | CSUM_UDP | CSUM_TCP)
+#define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU)
#define HN_LRO_LENLIM_DEF (25 * ETHERMTU)
/* YYY 2*MTU is a bit rough, but should be good enough. */
#define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu)
@@ -333,6 +334,17 @@ static void hn_xmit_txeof(struct hn_tx_ring *);
static void hn_xmit_taskfunc(void *, int);
static void hn_xmit_txeof_taskfunc(void *, int);
+#if __FreeBSD_version >= 1100099
+static void
+hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
+{
+ int i;
+
+ for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
+ sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
+}
+#endif
+
static int
hn_ifmedia_upd(struct ifnet *ifp __unused)
{
@@ -530,6 +542,16 @@ netvsc_attach(device_t dev)
device_printf(dev, "%d TX ring, %d RX ring\n",
sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
+#if __FreeBSD_version >= 1100099
+ if (sc->hn_rx_ring_inuse > 1) {
+ /*
+ * Reduce TCP segment aggregation limit for multiple
+ * RX rings to increase ACK timeliness.
+ */
+ hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
+ }
+#endif
+
if (device_info.link_state == 0) {
sc->hn_carrier = 1;
}
@@ -756,13 +778,8 @@ netvsc_channel_rollup(struct hv_vmbus_channel *chan)
struct hn_tx_ring *txr = chan->hv_chan_txr;
#if defined(INET) || defined(INET6)
struct hn_rx_ring *rxr = chan->hv_chan_rxr;
- struct lro_ctrl *lro = &rxr->hn_lro;
- struct lro_entry *queued;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(&rxr->hn_lro);
#endif
/*
@@ -1238,8 +1255,10 @@ netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
return (0);
} else if (packet->tot_data_buf_len <= MHLEN) {
m_new = m_gethdr(M_NOWAIT, MT_DATA);
- if (m_new == NULL)
+ if (m_new == NULL) {
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
return (0);
+ }
memcpy(mtod(m_new, void *), packet->data,
packet->tot_data_buf_len);
m_new->m_pkthdr.len = m_new->m_len = packet->tot_data_buf_len;
@@ -1259,7 +1278,7 @@ netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
if (m_new == NULL) {
- if_printf(ifp, "alloc mbuf failed.\n");
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
return (0);
}
@@ -1449,14 +1468,8 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
*/
NV_LOCK(sc);
if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
- HN_LRO_LENLIM_MIN(ifp)) {
- int i;
-
- for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
- sc->hn_rx_ring[i].hn_lro.lro_length_lim =
- HN_LRO_LENLIM_MIN(ifp);
- }
- }
+ HN_LRO_LENLIM_MIN(ifp))
+ hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
NV_UNLOCK(sc);
#endif
@@ -1789,7 +1802,7 @@ hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
{
struct hn_softc *sc = arg1;
unsigned int lenlim;
- int error, i;
+ int error;
lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
error = sysctl_handle_int(oidp, &lenlim, 0, req);
@@ -1801,8 +1814,7 @@ hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
return EINVAL;
NV_LOCK(sc);
- for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
- sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
+ hn_set_lro_lenlim(sc, lenlim);
NV_UNLOCK(sc);
return 0;
}
diff --git a/sys/dev/hyperv/utilities/hv_heartbeat.c b/sys/dev/hyperv/utilities/hv_heartbeat.c
index c1b6da5..09bd28b 100644
--- a/sys/dev/hyperv/utilities/hv_heartbeat.c
+++ b/sys/dev/hyperv/utilities/hv_heartbeat.c
@@ -94,6 +94,10 @@ static int
hv_heartbeat_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvheartbeat", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Heartbeat Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_kvp.c b/sys/dev/hyperv/utilities/hv_kvp.c
index 8517918..d71310b 100644
--- a/sys/dev/hyperv/utilities/hv_kvp.c
+++ b/sys/dev/hyperv/utilities/hv_kvp.c
@@ -304,28 +304,11 @@ hv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg,
{
int err_ip, err_subnet, err_gway, err_dns, err_adap;
int UNUSED_FLAG = 1;
- int guid_index;
struct hv_device *hv_dev; /* GUID Data Structure */
hn_softc_t *sc; /* hn softc structure */
char if_name[4];
- unsigned char guid_instance[40];
- char *guid_data = NULL;
char buf[39];
- struct guid_extract {
- char a1[2];
- char a2[2];
- char a3[2];
- char a4[2];
- char b1[2];
- char b2[2];
- char c1[2];
- char c2[2];
- char d[4];
- char e[12];
- };
-
- struct guid_extract *id;
device_t *devs;
int devcnt;
@@ -352,17 +335,7 @@ hv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg,
/* Trying to find GUID of Network Device */
hv_dev = sc->hn_dev_obj;
- for (guid_index = 0; guid_index < 16; guid_index++) {
- sprintf(&guid_instance[guid_index * 2], "%02x",
- hv_dev->device_id.data[guid_index]);
- }
-
- guid_data = (char *)guid_instance;
- id = (struct guid_extract *)guid_data;
- snprintf(buf, sizeof(buf), "{%.2s%.2s%.2s%.2s-%.2s%.2s-%.2s%.2s-%.4s-%s}",
- id->a4, id->a3, id->a2, id->a1,
- id->b2, id->b1, id->c2, id->c1, id->d, id->e);
- guid_data = NULL;
+ snprintf_hv_guid(buf, sizeof(buf), &hv_dev->device_id);
sprintf(if_name, "%s%d", "hn", device_get_unit(devs[devcnt]));
if (strncmp(buf, (char *)umsg->body.kvp_ip_val.adapter_id, 39) == 0) {
@@ -890,6 +863,10 @@ static int
hv_kvp_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvkvp", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V KVP Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_shutdown.c b/sys/dev/hyperv/utilities/hv_shutdown.c
index 20bc65e..0beed5a 100644
--- a/sys/dev/hyperv/utilities/hv_shutdown.c
+++ b/sys/dev/hyperv/utilities/hv_shutdown.c
@@ -116,6 +116,10 @@ static int
hv_shutdown_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvshutdown", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Shutdown Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_timesync.c b/sys/dev/hyperv/utilities/hv_timesync.c
index d1ea904..06580d7 100644
--- a/sys/dev/hyperv/utilities/hv_timesync.c
+++ b/sys/dev/hyperv/utilities/hv_timesync.c
@@ -171,6 +171,10 @@ static int
hv_timesync_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvtimesync", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Time Synch Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/vmbus/hv_connection.c b/sys/dev/hyperv/vmbus/hv_connection.c
index aa1e59e..e170298 100644
--- a/sys/dev/hyperv/vmbus/hv_connection.c
+++ b/sys/dev/hyperv/vmbus/hv_connection.c
@@ -364,31 +364,35 @@ hv_vmbus_on_events(int cpu)
/**
* Send a msg on the vmbus's message connection
*/
-int hv_vmbus_post_message(void *buffer, size_t bufferLen) {
- int ret = 0;
+int hv_vmbus_post_message(void *buffer, size_t bufferLen)
+{
hv_vmbus_connection_id connId;
- unsigned retries = 0;
+ sbintime_t time = SBT_1MS;
+ int retries;
+ int ret;
- /* NetScaler delays from previous code were consolidated here */
- static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000};
+ connId.as_uint32_t = 0;
+ connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- /* for(each entry in delayAmount) try to post message,
- * delay a little bit before retrying
+ /*
+ * We retry to cope with transient failures caused by host side's
+ * insufficient resources. 20 times should suffice in practice.
*/
- for (retries = 0;
- retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) {
- connId.as_uint32_t = 0;
- connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen);
- if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
- break;
- /* TODO: KYS We should use a blocking wait call */
- DELAY(delayAmount[retries]);
+ for (retries = 0; retries < 20; retries++) {
+ ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer,
+ bufferLen);
+ if (ret == HV_STATUS_SUCCESS)
+ return (0);
+
+ pause_sbt("pstmsg", time, 0, C_HARDCLOCK);
+ if (time < SBT_1S * 2)
+ time *= 2;
}
- KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n"));
+ KASSERT(ret == HV_STATUS_SUCCESS,
+ ("Error VMBUS: Message Post Failed, ret=%d\n", ret));
- return (ret);
+ return (EAGAIN);
}
/**
diff --git a/sys/dev/hyperv/vmbus/hv_et.c b/sys/dev/hyperv/vmbus/hv_et.c
index d961486..9fb6e23 100644
--- a/sys/dev/hyperv/vmbus/hv_et.c
+++ b/sys/dev/hyperv/vmbus/hv_et.c
@@ -60,7 +60,7 @@ hv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime)
timer_cfg.as_uint64 = 0;
timer_cfg.auto_enable = 1;
- timer_cfg.sintx = HV_VMBUS_MESSAGE_SINT;
+ timer_cfg.sintx = HV_VMBUS_TIMER_SINT;
periodticks[curcpu] = sbintime2tick(periodtime);
if (firsttime == 0)
diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c
index 6afc2b8..a87b5ce 100644
--- a/sys/dev/hyperv/vmbus/hv_hv.c
+++ b/sys/dev/hyperv/vmbus/hv_hv.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/pcpu.h>
#include <sys/timetc.h>
+#include <sys/kernel.h>
#include <machine/bus.h>
#include <machine/md_var.h>
#include <vm/vm.h>
@@ -207,8 +208,6 @@ hv_vmbus_init(void)
hv_vmbus_g_context.hypercall_page = virt_addr;
- tc_init(&hv_timecounter); /* register virtual timecount */
-
hv_et_init();
return (0);
@@ -368,6 +367,9 @@ hv_vmbus_synic_init(void *arg)
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
+ wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
+ shared_sint.as_uint64_t);
+
/* Enable the global synic bit */
sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL);
sctrl.u.enable = 1;
@@ -404,12 +406,23 @@ void hv_vmbus_synic_cleanup(void *arg)
shared_sint.u.masked = 1;
/*
- * Disable the interrupt
+ * Disable the interrupt 0
*/
wrmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
+ shared_sint.as_uint64_t = rdmsr(
+ HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT);
+
+ shared_sint.u.masked = 1;
+
+ /*
+ * Disable the interrupt 1
+ */
+ wrmsr(
+ HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
+ shared_sint.as_uint64_t);
simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
simp.u.simp_enabled = 0;
simp.u.base_simp_gpa = 0;
@@ -423,3 +436,14 @@ void hv_vmbus_synic_cleanup(void *arg)
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
}
+static void
+hv_tc_init(void)
+{
+ if (vm_guest != VM_GUEST_HV)
+ return;
+
+ /* register virtual timecounter */
+ tc_init(&hv_timecounter);
+}
+
+SYSINIT(hv_tc_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hv_tc_init, NULL);
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
index 4895f71..669a532 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pcpu.h>
#include <x86/apicvar.h>
+#include <dev/hyperv/include/hyperv.h>
#include "hv_vmbus_priv.h"
#include <contrib/dev/acpica/include/acpi.h>
@@ -75,7 +76,7 @@ static char *vmbus_ids[] = { "VMBUS", NULL };
* the hypervisor.
*/
static void
-vmbus_msg_swintr(void *arg)
+vmbus_msg_swintr(void *arg, int pending __unused)
{
int cpu;
void* page_addr;
@@ -174,12 +175,15 @@ hv_vmbus_isr(struct trapframe *frame)
/* Check if there are actual msgs to be process */
page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
- msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
+ msg = (hv_vmbus_message*) page_addr + HV_VMBUS_TIMER_SINT;
/* we call eventtimer process the message */
if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
msg->header.message_type = HV_MESSAGE_TYPE_NONE;
+ /* call intrrupt handler of event timer */
+ hv_et_intr(frame);
+
/*
* Make sure the write to message_type (ie set to
* HV_MESSAGE_TYPE_NONE) happens before we read the
@@ -196,12 +200,12 @@ hv_vmbus_isr(struct trapframe *frame)
*/
wrmsr(HV_X64_MSR_EOM, 0);
}
- hv_et_intr(frame);
- return (FILTER_HANDLED);
}
+ msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
- swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
+ taskqueue_enqueue(hv_vmbus_g_context.hv_msg_tq[cpu],
+ &hv_vmbus_g_context.hv_msg_task[cpu]);
}
return (FILTER_HANDLED);
@@ -279,6 +283,23 @@ vmbus_write_ivar(
return (ENOENT);
}
+static int
+vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen)
+{
+ char guidbuf[40];
+ struct hv_device *dev_ctx = device_get_ivars(child);
+
+ strlcat(buf, "classid=", buflen);
+ snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->class_id);
+ strlcat(buf, guidbuf, buflen);
+
+ strlcat(buf, " deviceid=", buflen);
+ snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->device_id);
+ strlcat(buf, guidbuf, buflen);
+
+ return (0);
+}
+
struct hv_device*
hv_vmbus_child_device_create(
hv_guid type,
@@ -300,15 +321,17 @@ hv_vmbus_child_device_create(
return (child_dev);
}
-static void
-print_dev_guid(struct hv_device *dev)
+int
+snprintf_hv_guid(char *buf, size_t sz, const hv_guid *guid)
{
- int i;
- unsigned char guid_name[100];
- for (i = 0; i < 32; i += 2)
- sprintf(&guid_name[i], "%02x", dev->class_id.data[i / 2]);
- if(bootverbose)
- printf("VMBUS: Class ID: %s\n", guid_name);
+ int cnt;
+ const unsigned char *d = guid->data;
+
+ cnt = snprintf(buf, sz,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
+ d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ return (cnt);
}
int
@@ -317,8 +340,11 @@ hv_vmbus_child_device_register(struct hv_device *child_dev)
device_t child;
int ret = 0;
- print_dev_guid(child_dev);
-
+ if (bootverbose) {
+ char name[40];
+ snprintf_hv_guid(name, sizeof(name), &child_dev->class_id);
+ printf("VMBUS: Class ID: %s\n", name);
+ }
child = device_add_child(vmbus_devp, NULL, -1);
child_dev->device = child;
@@ -485,9 +511,6 @@ vmbus_bus_init(void)
setup_args.vector = hv_vmbus_g_context.hv_cb_vector;
CPU_FOREACH(j) {
- hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
- hv_vmbus_g_context.msg_swintr[j] = NULL;
-
snprintf(buf, sizeof(buf), "cpu%d:hyperv", j);
intrcnt_add(buf, &hv_vmbus_intr_cpu[j]);
@@ -504,39 +527,21 @@ vmbus_bus_init(void)
*/
hv_vmbus_g_context.hv_event_queue[j] = taskqueue_create_fast("hyperv event", M_WAITOK,
taskqueue_thread_enqueue, &hv_vmbus_g_context.hv_event_queue[j]);
- if (hv_vmbus_g_context.hv_event_queue[j] == NULL) {
- if (bootverbose)
- printf("VMBUS: failed to setup taskqueue\n");
- goto cleanup1;
- }
CPU_SETOF(j, &cpu_mask);
taskqueue_start_threads_cpuset(&hv_vmbus_g_context.hv_event_queue[j], 1, PI_NET, &cpu_mask,
"hvevent%d", j);
/*
- * Setup software interrupt thread and handler for msg handling.
- */
- ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j],
- "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0,
- &hv_vmbus_g_context.msg_swintr[j]);
- if (ret) {
- if(bootverbose)
- printf("VMBUS: failed to setup msg swi for "
- "cpu %d\n", j);
- goto cleanup1;
- }
-
- /*
- * Bind the swi thread to the cpu.
+ * Setup per-cpu tasks and taskqueues to handle msg.
*/
- ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j],
- j);
- if (ret) {
- if(bootverbose)
- printf("VMBUS: failed to bind msg swi thread "
- "to cpu %d\n", j);
- goto cleanup1;
- }
+ hv_vmbus_g_context.hv_msg_tq[j] = taskqueue_create_fast(
+ "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
+ &hv_vmbus_g_context.hv_msg_tq[j]);
+ CPU_SETOF(j, &cpu_mask);
+ taskqueue_start_threads_cpuset(&hv_vmbus_g_context.hv_msg_tq[j],
+ 1, PI_NET, &cpu_mask, "hvmsg%d", j);
+ TASK_INIT(&hv_vmbus_g_context.hv_msg_task[j], 0,
+ vmbus_msg_swintr, (void *)(long)j);
/*
* Prepare the per cpu msg and event pages to be called on each cpu.
@@ -576,11 +581,10 @@ vmbus_bus_init(void)
* remove swi and vmbus callback vector;
*/
CPU_FOREACH(j) {
- if (hv_vmbus_g_context.hv_event_queue[j] != NULL)
+ if (hv_vmbus_g_context.hv_event_queue[j] != NULL) {
taskqueue_free(hv_vmbus_g_context.hv_event_queue[j]);
- if (hv_vmbus_g_context.msg_swintr[j] != NULL)
- swi_remove(hv_vmbus_g_context.msg_swintr[j]);
- hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
+ hv_vmbus_g_context.hv_event_queue[j] = NULL;
+ }
}
vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
@@ -645,11 +649,10 @@ vmbus_bus_exit(void)
/* remove swi */
CPU_FOREACH(i) {
- if (hv_vmbus_g_context.hv_event_queue[i] != NULL)
+ if (hv_vmbus_g_context.hv_event_queue[i] != NULL) {
taskqueue_free(hv_vmbus_g_context.hv_event_queue[i]);
- if (hv_vmbus_g_context.msg_swintr[i] != NULL)
- swi_remove(hv_vmbus_g_context.msg_swintr[i]);
- hv_vmbus_g_context.hv_msg_intr_event[i] = NULL;
+ hv_vmbus_g_context.hv_event_queue[i] = NULL;
+ }
}
vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
@@ -714,6 +717,7 @@ static device_method_t vmbus_methods[] = {
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, vmbus_read_ivar),
DEVMETHOD(bus_write_ivar, vmbus_write_ivar),
+ DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str),
{ 0, 0 } };
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
index 62fa22a..1a0ed04 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
@@ -70,6 +70,7 @@ typedef uint16_t hv_vmbus_status;
* You did not supply enough message buffers to send a message.
*/
+#define HV_STATUS_SUCCESS ((uint16_t)0)
#define HV_STATUS_INSUFFICIENT_BUFFERS ((uint16_t)0x0013)
typedef void (*hv_vmbus_channel_callback)(void *context);
@@ -180,7 +181,8 @@ enum {
HV_VMBUS_EVENT_PORT_ID = 2,
HV_VMBUS_MONITOR_CONNECTION_ID = 3,
HV_VMBUS_MONITOR_PORT_ID = 3,
- HV_VMBUS_MESSAGE_SINT = 2
+ HV_VMBUS_MESSAGE_SINT = 2,
+ HV_VMBUS_TIMER_SINT = 4,
};
#define HV_PRESENT_BIT 0x80000000
@@ -203,8 +205,8 @@ typedef struct {
* event and msg handling.
*/
struct taskqueue *hv_event_queue[MAXCPU];
- struct intr_event *hv_msg_intr_event[MAXCPU];
- void *msg_swintr[MAXCPU];
+ struct taskqueue *hv_msg_tq[MAXCPU];
+ struct task hv_msg_task[MAXCPU];
/*
* Host use this vector to intrrupt guest for vmbus channel
* event and msg.
diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c
index ec84f8f..75c41b7 100644
--- a/sys/dev/ichwd/ichwd.c
+++ b/sys/dev/ichwd/ichwd.c
@@ -540,9 +540,6 @@ ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p)
if (ich == NULL)
return (NULL);
- ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n",
- id->ich_version, id->desc);
-
if (id_p)
*id_p = id;
@@ -573,8 +570,6 @@ ichwd_identify(driver_t *driver, device_t parent)
if (dev == NULL)
return;
- device_set_desc_copy(dev, id_p->desc);
-
switch (id_p->tco_version) {
case 1:
break;
@@ -611,10 +606,16 @@ ichwd_identify(driver_t *driver, device_t parent)
static int
ichwd_probe(device_t dev)
{
+ struct ichwd_device *id_p;
/* Do not claim some ISA PnP device by accident. */
if (isa_get_logicalid(dev) != 0)
return (ENXIO);
+
+ if (ichwd_find_ich_lpc_bridge(&id_p) == NULL)
+ return (ENXIO);
+
+ device_set_desc_copy(dev, id_p->desc);
return (0);
}
@@ -677,9 +678,6 @@ ichwd_attach(device_t dev)
if (ichwd_clear_noreboot(sc) != 0)
goto fail;
- ichwd_verbose_printf(dev, "%s (ICH%d or equivalent)\n",
- id_p->desc, sc->ich_version);
-
/*
* Determine if we are coming up after a watchdog-induced reset. Some
* BIOSes may clear this bit at bootup, preventing us from reporting
diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c
index df29b09..a090bb9 100644
--- a/sys/dev/iicbus/iicbus.c
+++ b/sys/dev/iicbus/iicbus.c
@@ -149,7 +149,7 @@ iicbus_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
if (devi->addr != 0)
retval += printf(" at addr %#x", devi->addr);
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
return (retval);
diff --git a/sys/dev/iir/iir.c b/sys/dev/iir/iir.c
index bf5cec5..e74698e 100644
--- a/sys/dev/iir/iir.c
+++ b/sys/dev/iir/iir.c
@@ -744,9 +744,9 @@ gdt_next(struct gdt_softc *gdt)
ccb->ccb_h.flags));
csio = &ccb->csio;
ccbh = &ccb->ccb_h;
- cmd = csio->cdb_io.cdb_bytes[0];
- /* Max CDB length is 12 bytes */
- if (csio->cdb_len > 12) {
+ cmd = scsiio_cdb_ptr(csio)[0];
+ /* Max CDB length is 12 bytes, can't be phys addr */
+ if (csio->cdb_len > 12 || (ccbh->flags & CAM_CDB_PHYS)) {
ccbh->status = CAM_REQ_INVALID;
--gdt_stat.io_count_act;
xpt_done(ccb);
diff --git a/sys/dev/iir/iir_pci.c b/sys/dev/iir/iir_pci.c
index 261f5a6..5db66b1 100644
--- a/sys/dev/iir/iir_pci.c
+++ b/sys/dev/iir/iir_pci.c
@@ -228,7 +228,7 @@ iir_pci_attach(device_t dev)
/* check and reset interface area */
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC, htole32(GDT_MPR_MAGIC));
if (bus_read_4(gdt->sc_dpmem, GDT_MPR_IC) != htole32(GDT_MPR_MAGIC)) {
- device_printf(dev, "cannot access DPMEM at 0x%lx (shadowed?)\n",
+ device_printf(dev, "cannot access DPMEM at 0x%jx (shadowed?)\n",
rman_get_start(gdt->sc_dpmem));
error = ENXIO;
goto err;
diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
index 8101717..314d4d6 100644
--- a/sys/dev/ipmi/ipmi.c
+++ b/sys/dev/ipmi/ipmi.c
@@ -603,6 +603,20 @@ ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req)
*/
static int
+ipmi_reset_watchdog(struct ipmi_softc *sc)
+{
+ struct ipmi_request *req;
+ int error;
+
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_RESET_WDOG, 0, 0);
+ error = ipmi_submit_driver_request(sc, req, 0);
+ if (error)
+ device_printf(sc->ipmi_dev, "Failed to reset watchdog\n");
+ return (error);
+}
+
+static int
ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
{
struct ipmi_request *req;
@@ -613,7 +627,6 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_SET_WDOG, 6, 0);
-
if (sec) {
req->ir_request[0] = IPMI_SET_WD_TIMER_DONT_STOP
| IPMI_SET_WD_TIMER_SMS_OS;
@@ -630,24 +643,10 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
req->ir_request[4] = 0;
req->ir_request[5] = 0;
}
-
error = ipmi_submit_driver_request(sc, req, 0);
if (error)
device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
- else if (sec) {
- IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
- IPMI_RESET_WDOG, 0, 0);
-
- error = ipmi_submit_driver_request(sc, req, 0);
- if (error)
- device_printf(sc->ipmi_dev,
- "Failed to reset watchdog\n");
- }
-
return (error);
- /*
- dump_watchdog(sc);
- */
}
static void
@@ -665,12 +664,24 @@ ipmi_wd_event(void *arg, unsigned int cmd, int *error)
timeout = ((uint64_t)1 << cmd) / 1000000000;
if (timeout == 0)
timeout = 1;
- e = ipmi_set_watchdog(sc, timeout);
- if (e == 0) {
- *error = 0;
- sc->ipmi_watchdog_active = 1;
- } else
- (void)ipmi_set_watchdog(sc, 0);
+ if (timeout != sc->ipmi_watchdog_active) {
+ e = ipmi_set_watchdog(sc, timeout);
+ if (e == 0) {
+ sc->ipmi_watchdog_active = timeout;
+ } else {
+ (void)ipmi_set_watchdog(sc, 0);
+ sc->ipmi_watchdog_active = 0;
+ }
+ }
+ if (sc->ipmi_watchdog_active != 0) {
+ e = ipmi_reset_watchdog(sc);
+ if (e == 0) {
+ *error = 0;
+ } else {
+ (void)ipmi_set_watchdog(sc, 0);
+ sc->ipmi_watchdog_active = 0;
+ }
+ }
} else if (atomic_readandclear_int(&sc->ipmi_watchdog_active) != 0) {
e = ipmi_set_watchdog(sc, 0);
if (e != 0 && cmd == 0)
diff --git a/sys/dev/isci/isci_controller.c b/sys/dev/isci/isci_controller.c
index b0f4285..d3ec045 100644
--- a/sys/dev/isci/isci_controller.c
+++ b/sys/dev/isci/isci_controller.c
@@ -740,6 +740,11 @@ void isci_action(struct cam_sim *sim, union ccb *ccb)
}
break;
case XPT_SCSI_IO:
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
isci_io_request_execute_scsi_io(ccb, controller);
break;
#if __FreeBSD_version >= 900026
@@ -802,6 +807,7 @@ isci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
{
struct ISCI_REMOTE_DEVICE *dev;
struct ccb_hdr *ccb_h;
+ uint8_t *ptr;
int dev_idx;
KASSERT(mtx_owned(&controller->lock), ("controller lock not owned"));
@@ -821,8 +827,8 @@ isci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
if (ccb_h == NULL)
continue;
- isci_log_message(1, "ISCI", "release %p %x\n", ccb_h,
- ((union ccb *)ccb_h)->csio.cdb_io.cdb_bytes[0]);
+ ptr = scsiio_cdb_ptr(&((union ccb *)ccb_h)->csio);
+ isci_log_message(1, "ISCI", "release %p %x\n", ccb_h, *ptr);
dev->queued_ccb_in_progress = (union ccb *)ccb_h;
isci_io_request_execute_scsi_io(
diff --git a/sys/dev/isci/isci_io_request.c b/sys/dev/isci/isci_io_request.c
index e6b68fd..f86c126 100644
--- a/sys/dev/isci/isci_io_request.c
+++ b/sys/dev/isci/isci_io_request.c
@@ -86,6 +86,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
struct ISCI_REMOTE_DEVICE *isci_remote_device;
union ccb *ccb;
BOOL complete_ccb;
+ struct ccb_scsiio *csio;
complete_ccb = TRUE;
isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller);
@@ -93,7 +94,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
(struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device);
ccb = isci_request->ccb;
-
+ csio = &ccb->csio;
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
switch (completion_status) {
@@ -124,7 +125,6 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
SCI_SSP_RESPONSE_IU_T * response_buffer;
uint32_t sense_length;
int error_code, sense_key, asc, ascq;
- struct ccb_scsiio *csio = &ccb->csio;
response_buffer = (SCI_SSP_RESPONSE_IU_T *)
scif_io_request_get_response_iu_address(
@@ -146,7 +146,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(1, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0],
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio),
csio->scsi_status, sense_key, asc, ascq);
break;
}
@@ -157,7 +157,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(0, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x remote device reset required\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio));
break;
case SCI_IO_FAILURE_TERMINATED:
@@ -165,7 +165,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(0, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio));
break;
case SCI_IO_FAILURE_INVALID_STATE:
@@ -208,7 +208,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(1, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0],
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio),
completion_status);
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
break;
@@ -285,13 +285,13 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
* get a ready notification for this device.
*/
isci_log_message(1, "ISCI", "already queued %p %x\n",
- ccb, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb, scsiio_cdb_ptr(csio));
isci_remote_device->queued_ccb_in_progress = NULL;
} else {
isci_log_message(1, "ISCI", "queue %p %x\n", ccb,
- ccb->csio.cdb_io.cdb_bytes[0]);
+ scsiio_cdb_ptr(csio));
ccb->ccb_h.status |= CAM_SIM_QUEUED;
TAILQ_INSERT_TAIL(&isci_remote_device->queued_ccbs,
@@ -373,7 +373,7 @@ scif_cb_io_request_get_cdb_address(void * scif_user_io_request)
struct ISCI_IO_REQUEST *isci_request =
(struct ISCI_IO_REQUEST *)scif_user_io_request;
- return (isci_request->ccb->csio.cdb_io.cdb_bytes);
+ return (scsiio_cdb_ptr(&isci_request->ccb->csio));
}
/**
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index a9bdaf7..7172ec0 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -288,6 +288,8 @@ iscsi_session_terminate_task(struct iscsi_session *is,
struct iscsi_outstanding *io, bool requeue)
{
+ ISCSI_SESSION_LOCK_ASSERT(is);
+
if (io->io_ccb != NULL) {
io->io_ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK);
if (requeue)
@@ -2220,6 +2222,7 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT);
if (error != 0) {
+ iscsi_outstanding_remove(is, io);
icl_pdu_free(request);
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
xpt_freeze_devq(ccb->ccb_h.path, 1);
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index 28b7b7f..bffa8de 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -2554,7 +2554,8 @@ iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c)
} else {
for (j = 0; j < 5; j++) {
for (i = 0; i < iwn_bands[j].nchan; i++) {
- if (iwn_bands[j].chan[i] == c->ic_ieee)
+ if (iwn_bands[j].chan[i] == c->ic_ieee &&
+ ((j == 0) ^ IEEE80211_IS_CHAN_A(c)) == 1)
return &sc->eeprom_channels[j][i];
}
}
@@ -8700,7 +8701,9 @@ iwn_panicked(void *arg0, int pending)
struct iwn_softc *sc = arg0;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+#if 0
int error;
+#endif
if (vap == NULL) {
printf("%s: null vap\n", __func__);
@@ -8708,8 +8711,18 @@ iwn_panicked(void *arg0, int pending)
}
device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; "
- "resetting...\n", __func__, vap->iv_state);
+ "restarting\n", __func__, vap->iv_state);
+ /*
+ * This is not enough work. We need to also reinitialise
+ * the correct transmit state for aggregation enabled queues,
+ * which has a very specific requirement of
+ * ring index = 802.11 seqno % 256. If we don't do this (which
+ * we definitely don't!) then the firmware will just panic again.
+ */
+#if 1
+ ieee80211_restart_all(ic);
+#else
IWN_LOCK(sc);
iwn_stop_locked(sc);
@@ -8726,6 +8739,7 @@ iwn_panicked(void *arg0, int pending)
}
IWN_UNLOCK(sc);
+#endif
}
static void
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index f0e218f..5e16fbd 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -4749,10 +4749,6 @@ ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS)
if ((error) || (req->newptr == NULL))
return (error);
- /* Checks to validate new value */
- if (adapter->advertise == advertise) /* no change */
- return (0);
-
return ixgbe_set_advertise(adapter, advertise);
}
@@ -4763,6 +4759,10 @@ ixgbe_set_advertise(struct adapter *adapter, int advertise)
struct ixgbe_hw *hw;
ixgbe_link_speed speed;
+ /* Checks to validate new value */
+ if (adapter->advertise == advertise) /* no change */
+ return (0);
+
hw = &adapter->hw;
dev = adapter->dev;
diff --git a/sys/dev/ixgbe/ix_txrx.c b/sys/dev/ixgbe/ix_txrx.c
index 00e5dc8..66bcb25 100644
--- a/sys/dev/ixgbe/ix_txrx.c
+++ b/sys/dev/ixgbe/ix_txrx.c
@@ -1753,7 +1753,6 @@ ixgbe_rxeof(struct ix_queue *que)
struct rx_ring *rxr = que->rxr;
struct ifnet *ifp = adapter->ifp;
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
int i, nextp, processed = 0;
u32 staterr = 0;
u32 count = adapter->rx_process_limit;
@@ -2003,10 +2002,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
IXGBE_RX_UNLOCK(rxr);
diff --git a/sys/dev/ixl/ixl_txrx.c b/sys/dev/ixl/ixl_txrx.c
index 0ae7433..ca6e252 100644
--- a/sys/dev/ixl/ixl_txrx.c
+++ b/sys/dev/ixl/ixl_txrx.c
@@ -1511,7 +1511,6 @@ ixl_rxeof(struct ixl_queue *que, int count)
struct ifnet *ifp = vsi->ifp;
#if defined(INET6) || defined(INET)
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
#endif
int i, nextp, processed = 0;
union i40e_rx_desc *cur;
@@ -1735,10 +1734,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
#endif
IXL_RX_UNLOCK(rxr);
diff --git a/sys/dev/le/lebuffer_sbus.c b/sys/dev/le/lebuffer_sbus.c
index 1254fc3..f2c7c5f 100644
--- a/sys/dev/le/lebuffer_sbus.c
+++ b/sys/dev/le/lebuffer_sbus.c
@@ -297,7 +297,7 @@ lebuffer_print_res(struct lebuffer_devinfo *ldi)
rv = 0;
rv += resource_list_print_type(&ldi->ldi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
- rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%ld");
+ "%#jx");
+ rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/dev/mca/mca_bus.c b/sys/dev/mca/mca_bus.c
index 55ac9ed..2de61da 100644
--- a/sys/dev/mca/mca_bus.c
+++ b/sys/dev/mca/mca_bus.c
@@ -365,11 +365,11 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
if (rle->count == 1) {
- snprintf(buf, sizeof(buf), "%s%lx",
+ snprintf(buf, sizeof(buf), "%s%jx",
((rid == 1) ? "io 0x" : "0x"),
rle->start);
} else {
- snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
+ snprintf(buf, sizeof(buf), "%s%jx-0x%jx",
((rid == 1) ? "io 0x" : "0x"),
rle->start,
(rle->start + rle->count));
@@ -381,11 +381,11 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
if (rle->count == 1) {
- snprintf(buf, sizeof(buf), "%s%lx",
+ snprintf(buf, sizeof(buf), "%s%jx",
((rid == 1) ? "mem 0x" : "0x"),
rle->start);
} else {
- snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
+ snprintf(buf, sizeof(buf), "%s%jx-0x%jx",
((rid == 1) ? "mem 0x" : "0x"),
rle->start,
(rle->start + rle->count));
@@ -396,14 +396,14 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
- snprintf(buf, sizeof(buf), "irq %ld", rle->start);
+ snprintf(buf, sizeof(buf), "irq %jd", rle->start);
mca_reg_print(child, buf,
((rid == 1) ? &separator : NULL), &column);
}
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
- snprintf(buf, sizeof(buf), "drq %lx", rle->start);
+ snprintf(buf, sizeof(buf), "drq %jx", rle->start);
mca_reg_print(child, buf,
((rid == 1) ? &separator : NULL), &column);
}
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index ddcc853..c224186 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -2141,7 +2141,7 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
pass = &cm->cm_frame->pass;
bzero(pass->cdb, 16);
pass->header.cmd = MFI_CMD_PD_SCSI_IO;
- switch (bio->bio_cmd & 0x03) {
+ switch (bio->bio_cmd) {
case BIO_READ:
flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
readop = 1;
@@ -2200,7 +2200,7 @@ mfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
bzero(cm->cm_frame, sizeof(union mfi_frame));
cm->cm_frame->header.context = context;
io = &cm->cm_frame->io;
- switch (bio->bio_cmd & 0x03) {
+ switch (bio->bio_cmd) {
case BIO_READ:
io->header.cmd = MFI_CMD_LD_READ;
flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
index 48339be..230dfcc 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -322,9 +322,6 @@ mlx5e_decompress_cqes(struct mlx5e_cq *cq)
static int
mlx5e_poll_rx_cq(struct mlx5e_rq *rq, int budget)
{
-#ifndef HAVE_TURBO_LRO
- struct lro_entry *queued;
-#endif
int i;
for (i = 0; i < budget; i++) {
@@ -399,10 +396,7 @@ wq_ll_pop:
/* ensure cq space is freed before enabling more cqes */
wmb();
#ifndef HAVE_TURBO_LRO
- while ((queued = SLIST_FIRST(&rq->lro.lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&rq->lro.lro_active, next);
- tcp_lro_flush(&rq->lro, queued);
- }
+ tcp_lro_flush_all(&rq->lro);
#endif
return (i);
}
diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c
index 5dc0626..5b24a6d 100644
--- a/sys/dev/mmc/host/dwmmc.c
+++ b/sys/dev/mmc/host/dwmmc.c
@@ -1178,3 +1178,4 @@ static devclass_t dwmmc_devclass;
DRIVER_MODULE(dwmmc, simplebus, dwmmc_driver, dwmmc_devclass, 0, 0);
DRIVER_MODULE(dwmmc, ofwbus, dwmmc_driver, dwmmc_devclass, 0, 0);
DRIVER_MODULE(mmc, dwmmc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(dwmmc, mmc, 1, 1, 1);
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index a65ff41..9f88079 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -1811,3 +1811,5 @@ driver_t mmc_driver = {
sizeof(struct mmc_softc),
};
devclass_t mmc_devclass;
+
+MODULE_VERSION(mmc, 1);
diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h
index f454ddb..b169d26 100644
--- a/sys/dev/mmc/mmcreg.h
+++ b/sys/dev/mmc/mmcreg.h
@@ -85,8 +85,11 @@ struct mmc_command {
#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
-#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC)
-#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC)
+#define MMC_RSP_R4 (MMC_RSP_PRESENT)
+#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R5B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define MMC_RSP(x) ((x) & MMC_RSP_MASK)
uint32_t retries;
uint32_t error;
diff --git a/sys/dev/mvs/mvs_pci.c b/sys/dev/mvs/mvs_pci.c
index 316ac00..b3262f8 100644
--- a/sys/dev/mvs/mvs_pci.c
+++ b/sys/dev/mvs/mvs_pci.c
@@ -396,7 +396,7 @@ mvs_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct mvs_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = HC_BASE(unit >> 2) + PORT_BASE(unit & 0x03);
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/mvs/mvs_soc.c b/sys/dev/mvs/mvs_soc.c
index d4ecd8f..b34df30 100644
--- a/sys/dev/mvs/mvs_soc.c
+++ b/sys/dev/mvs/mvs_soc.c
@@ -342,7 +342,7 @@ mvs_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct mvs_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = PORT_BASE(unit & 0x03);
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 928917f..f78b34b 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -2819,11 +2819,7 @@ mxge_clean_rx_done(struct mxge_slice_state *ss)
break;
}
#if defined(INET) || defined (INET6)
- while (!SLIST_EMPTY(&ss->lc.lro_active)) {
- struct lro_entry *lro = SLIST_FIRST(&ss->lc.lro_active);
- SLIST_REMOVE_HEAD(&ss->lc.lro_active, next);
- tcp_lro_flush(&ss->lc, lro);
- }
+ tcp_lro_flush_all(&ss->lc);
#endif
}
@@ -4612,7 +4608,7 @@ mxge_add_msix_irqs(mxge_softc_t *sc)
device_printf(sc->dev, "using %d msix IRQs:",
sc->num_slices);
for (i = 0; i < sc->num_slices; i++)
- printf(" %ld", rman_get_start(sc->msix_irq_res[i]));
+ printf(" %jd", rman_get_start(sc->msix_irq_res[i]));
printf("\n");
}
return (0);
@@ -4668,7 +4664,7 @@ mxge_add_single_irq(mxge_softc_t *sc)
return ENXIO;
}
if (mxge_verbose)
- device_printf(sc->dev, "using %s irq %ld\n",
+ device_printf(sc->dev, "using %s irq %jd\n",
sc->legacy_irq ? "INTx" : "MSI",
rman_get_start(sc->irq_res));
err = bus_setup_intr(sc->dev, sc->irq_res,
@@ -4823,7 +4819,7 @@ mxge_attach(device_t dev)
sc->sram = rman_get_virtual(sc->mem_res);
sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100;
if (sc->sram_size > rman_get_size(sc->mem_res)) {
- device_printf(dev, "impossible memory region size %ld\n",
+ device_printf(dev, "impossible memory region size %jd\n",
rman_get_size(sc->mem_res));
err = ENXIO;
goto abort_with_mem_res;
diff --git a/sys/dev/ncr/ncr.c b/sys/dev/ncr/ncr.c
index 6c941e1..111cd69 100644
--- a/sys/dev/ncr/ncr.c
+++ b/sys/dev/ncr/ncr.c
@@ -3860,6 +3860,16 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
csio = &ccb->csio;
/*
+ * Make sure we support this request. We can't do
+ * PHYS pointers.
+ */
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
* Last time we need to check if this CCB needs to
* be aborted.
*/
@@ -4070,8 +4080,7 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
/*
** command
*/
- /* XXX JGibbs - Support other command types */
- cp->phys.cmd.addr = vtophys (csio->cdb_io.cdb_bytes);
+ cp->phys.cmd.addr = vtophys (scsiio_cdb_ptr(csio));
cp->phys.cmd.size = csio->cdb_len;
/*
** sense command
@@ -4083,7 +4092,6 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
*/
cp->sensecmd[0] = 0x03;
cp->sensecmd[1] = ccb->ccb_h.target_lun << 5;
- cp->sensecmd[4] = sizeof(struct scsi_sense_data);
cp->sensecmd[4] = csio->sense_len;
/*
** sense data
diff --git a/sys/dev/nctgpio/nctgpio.c b/sys/dev/nctgpio/nctgpio.c
new file mode 100644
index 0000000..ab547c0
--- /dev/null
+++ b/sys/dev/nctgpio/nctgpio.c
@@ -0,0 +1,802 @@
+/*-
+ * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Nuvoton GPIO driver.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/lock.h>
+
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/gpio.h>
+
+#include <isa/isavar.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#include "gpio_if.h"
+
+/*
+ * Global configuration registers (CR).
+ */
+#define NCT_CR_LDN 0x07 /* Logical Device Number */
+#define NCT_CR_CHIP_ID 0x20 /* Chip ID */
+#define NCT_CR_CHIP_ID_H 0x20 /* Chip ID (high byte) */
+#define NCT_CR_CHIP_ID_L 0x21 /* Chip ID (low byte) */
+#define NCT_CR_OPT_1 0x26 /* Global Options (1) */
+
+/* Logical Device Numbers. */
+#define NCT_LDN_GPIO 0x07
+#define NCT_LDN_GPIO_CFG 0x08
+#define NCT_LDN_GPIO_MODE 0x0f
+
+/* Logical Device 7 */
+#define NCT_LD7_GPIO_ENABLE 0x30
+#define NCT_LD7_GPIO0_IOR 0xe0
+#define NCT_LD7_GPIO0_DAT 0xe1
+#define NCT_LD7_GPIO0_INV 0xe2
+#define NCT_LD7_GPIO0_DST 0xe3
+#define NCT_LD7_GPIO1_IOR 0xe4
+#define NCT_LD7_GPIO1_DAT 0xe5
+#define NCT_LD7_GPIO1_INV 0xe6
+#define NCT_LD7_GPIO1_DST 0xe7
+
+/* Logical Device F */
+#define NCT_LDF_GPIO0_OUTCFG 0xe0
+#define NCT_LDF_GPIO1_OUTCFG 0xe1
+
+#define NCT_EXTFUNC_ENTER 0x87
+#define NCT_EXTFUNC_EXIT 0xaa
+
+#define NCT_MAX_PIN 15
+#define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN)
+
+#define NCT_PIN_BIT(_p) (1 << ((_p) % 8))
+
+#define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
+ GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
+ GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
+
+struct nct_softc {
+ device_t dev;
+ device_t busdev;
+ struct mtx mtx;
+ struct resource *portres;
+ int rid;
+ struct gpio_pin pins[NCT_MAX_PIN];
+};
+
+#define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
+ device_get_nameunit(dev), NULL, MTX_DEF)
+#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
+
+#define NCT_BARRIER_WRITE(_sc) \
+ bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE)
+
+#define NCT_BARRIER_READ_WRITE(_sc) \
+ bus_barrier((_sc)->portres, 0, 2, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+static void ext_cfg_enter(struct nct_softc *);
+static void ext_cfg_exit(struct nct_softc *);
+
+/*
+ * Potential Extended Function Enable Register addresses.
+ * Same address as EFIR.
+ */
+uint8_t probe_addrs[] = {0x2e, 0x4e};
+
+struct nuvoton_vendor_device_id {
+ uint16_t chip_id;
+ const char * descr;
+} nct_devs[] = {
+ {
+ .chip_id = 0x1061,
+ .descr = "Nuvoton NCT5104D",
+ },
+ {
+ .chip_id = 0xc452,
+ .descr = "Nuvoton NCT5104D (PC-Engines APU)",
+ },
+};
+
+static void
+write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, reg);
+ NCT_BARRIER_WRITE(sc);
+ bus_write_1(sc->portres, 1, value);
+ NCT_BARRIER_WRITE(sc);
+}
+
+static uint8_t
+read_cfg_reg_1(struct nct_softc *sc, uint8_t reg)
+{
+ uint8_t value;
+
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, reg);
+ NCT_BARRIER_READ_WRITE(sc);
+ value = bus_read_1(sc->portres, 1);
+ NCT_BARRIER_READ_WRITE(sc);
+
+ return (value);
+}
+
+static uint16_t
+read_cfg_reg_2(struct nct_softc *sc, uint8_t reg)
+{
+ uint16_t value;
+
+ value = read_cfg_reg_1(sc, reg) << 8;
+ value |= read_cfg_reg_1(sc, reg + 1);
+
+ return (value);
+}
+
+/*
+ * Enable extended function mode.
+ *
+ */
+static void
+ext_cfg_enter(struct nct_softc *sc)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
+ NCT_BARRIER_WRITE(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
+ NCT_BARRIER_WRITE(sc);
+}
+
+/*
+ * Disable extended function mode.
+ *
+ */
+static void
+ext_cfg_exit(struct nct_softc *sc)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT);
+ NCT_BARRIER_WRITE(sc);
+}
+
+/*
+ * Select a Logical Device.
+ */
+static void
+select_ldn(struct nct_softc *sc, uint8_t ldn)
+{
+ write_cfg_reg_1(sc, NCT_CR_LDN, ldn);
+}
+
+/*
+ * Get the GPIO Input/Output register address
+ * for a pin.
+ */
+static uint8_t
+nct_ior_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_IOR;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_IOR;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Data register address for a pin.
+ */
+static uint8_t
+nct_dat_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_DAT;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_DAT;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Inversion register address
+ * for a pin.
+ */
+static uint8_t
+nct_inv_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_INV;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_INV;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Output Configuration/Mode
+ * register address for a pin.
+ */
+static uint8_t
+nct_outcfg_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LDF_GPIO0_OUTCFG;
+ if (pin_num > 7)
+ addr = NCT_LDF_GPIO1_OUTCFG;
+
+ return (addr);
+}
+
+/*
+ * Set a pin to output mode.
+ */
+static void
+nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+ ior &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, ior);
+}
+
+/*
+ * Set a pin to input mode.
+ */
+static void
+nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+ ior |= NCT_PIN_BIT(pin_num);
+ write_cfg_reg_1(sc, reg, ior);
+}
+
+/*
+ * Check whether a pin is configured as an input.
+ */
+static bool
+nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+
+ return (ior & NCT_PIN_BIT(pin_num));
+}
+
+/*
+ * Write a value to an output pin.
+ */
+static void
+nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data)
+{
+ uint8_t reg;
+ uint8_t value;
+
+ reg = nct_dat_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ value = read_cfg_reg_1(sc, reg);
+ if (data)
+ value |= NCT_PIN_BIT(pin_num);
+ else
+ value &= ~(NCT_PIN_BIT(pin_num));
+
+ write_cfg_reg_1(sc, reg, value);
+}
+
+static bool
+nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+
+ reg = nct_dat_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+
+ return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+ inv |= (NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, inv);
+}
+
+static void
+nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+ inv &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, inv);
+}
+
+static bool
+nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+
+ return (inv & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+ outcfg |= (NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, outcfg);
+}
+
+static void
+nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+ outcfg &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, outcfg);
+}
+
+static bool
+nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+
+ return (outcfg & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_identify(driver_t *driver, device_t parent)
+{
+ if (device_find_child(parent, driver->name, 0) != NULL)
+ return;
+
+ BUS_ADD_CHILD(parent, 0, driver->name, 0);
+}
+
+static int
+nct_probe(device_t dev)
+{
+ int i, j;
+ int rc;
+ struct nct_softc *sc;
+ uint16_t chipid;
+
+ /* Make sure we do not claim some ISA PNP device. */
+ if (isa_get_logicalid(dev) != 0)
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) {
+ sc->rid = 0;
+ sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
+ probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE);
+ if (sc->portres == NULL)
+ continue;
+
+ GPIO_LOCK_INIT(sc);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_enter(sc);
+ chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+
+ GPIO_LOCK_DESTROY(sc);
+
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+ bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid);
+
+ for (j = 0; j < sizeof(nct_devs) / sizeof(*nct_devs); j++) {
+ if (chipid == nct_devs[j].chip_id) {
+ rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2);
+ if (rc != 0) {
+ device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]);
+ continue;
+ }
+ device_set_desc(dev, nct_devs[j].descr);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+nct_attach(device_t dev)
+{
+ struct nct_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ sc->rid = 0;
+ sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
+ 0ul, ~0ul, 2, RF_ACTIVE);
+ if (sc->portres == NULL) {
+ device_printf(dev, "cannot allocate ioport\n");
+ return (ENXIO);
+ }
+
+ GPIO_LOCK_INIT(sc);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_enter(sc);
+ select_ldn(sc, NCT_LDN_GPIO);
+ /* Enable gpio0 and gpio1. */
+ write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE,
+ read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03);
+
+ for (i = 0; i <= NCT_MAX_PIN; i++) {
+ struct gpio_pin *pin;
+
+ pin = &sc->pins[i];
+ pin->gp_pin = i;
+ pin->gp_caps = NCT_GPIO_CAPS;
+ pin->gp_flags = 0;
+
+ snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i);
+ pin->gp_name[GPIOMAXNAME - 1] = '\0';
+
+ if (nct_pin_is_input(sc, i))
+ pin->gp_flags |= GPIO_PIN_INPUT;
+ else
+ pin->gp_flags |= GPIO_PIN_OUTPUT;
+
+ if (nct_pin_is_opendrain(sc, i))
+ pin->gp_flags |= GPIO_PIN_OPENDRAIN;
+ else
+ pin->gp_flags |= GPIO_PIN_PUSHPULL;
+
+ if (nct_pin_is_inverted(sc, i))
+ pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
+ }
+ GPIO_UNLOCK(sc);
+
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+ GPIO_LOCK_DESTROY(sc);
+
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+nct_detach(device_t dev)
+{
+ struct nct_softc *sc;
+
+ sc = device_get_softc(dev);
+ gpiobus_detach_bus(dev);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+
+ /* Cleanup resources. */
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+
+ GPIO_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_t
+nct_gpio_get_bus(device_t dev)
+{
+ struct nct_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->busdev);
+}
+
+static int
+nct_gpio_pin_max(device_t dev, int *npins)
+{
+ *npins = NCT_MAX_PIN;
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ nct_write_pin(sc, pin_num, pin_value);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *pin_value = nct_read_pin(sc, pin_num);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ if (nct_read_pin(sc, pin_num))
+ nct_write_pin(sc, pin_num, 0);
+ else
+ nct_write_pin(sc, pin_num, 1);
+
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *caps = sc->pins[pin_num].gp_caps;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *flags = sc->pins[pin_num].gp_flags;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
+{
+ struct nct_softc *sc;
+ struct gpio_pin *pin;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ pin = &sc->pins[pin_num];
+ if ((flags & pin->gp_caps) != flags)
+ return (EINVAL);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_INPUT)
+ nct_set_pin_is_input(sc, pin_num);
+ else
+ nct_set_pin_is_output(sc, pin_num);
+ }
+
+ if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
+ if (flags & GPIO_PIN_INPUT) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
+ (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_OPENDRAIN)
+ nct_set_pin_opendrain(sc, pin_num);
+ else
+ nct_set_pin_pushpull(sc, pin_num);
+ }
+
+ if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
+ if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) !=
+ (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_INVIN)
+ nct_set_pin_is_inverted(sc, pin_num);
+ else
+ nct_set_pin_not_inverted(sc, pin_num);
+ }
+
+ pin->gp_flags = flags;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static device_method_t nct_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, nct_identify),
+ DEVMETHOD(device_probe, nct_probe),
+ DEVMETHOD(device_attach, nct_attach),
+ DEVMETHOD(device_detach, nct_detach),
+
+ /* GPIO */
+ DEVMETHOD(gpio_get_bus, nct_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, nct_gpio_pin_max),
+ DEVMETHOD(gpio_pin_get, nct_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, nct_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle),
+ DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags),
+
+ DEVMETHOD_END
+};
+
+static driver_t nct_isa_driver = {
+ "gpio",
+ nct_methods,
+ sizeof(struct nct_softc)
+};
+
+static devclass_t nct_devclass;
+
+DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL);
+MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index bc5b452..9129960 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -129,8 +129,9 @@ static inline struct mbuf *
netmap_get_mbuf(int len)
{
struct mbuf *m;
- m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR | M_NOFREE);
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (m) {
+ m->m_flags |= M_NOFREE; /* XXXNP: Almost certainly incorrect. */
m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
m->m_ext.ext_free = (void *)netmap_default_mbuf_destructor;
m->m_ext.ext_type = EXT_EXTREF;
diff --git a/sys/dev/oce/oce_if.c b/sys/dev/oce/oce_if.c
index f0cce5f..3704612 100644
--- a/sys/dev/oce/oce_if.c
+++ b/sys/dev/oce/oce_if.c
@@ -1497,16 +1497,12 @@ static void
oce_rx_flush_lro(struct oce_rq *rq)
{
struct lro_ctrl *lro = &rq->lro;
- struct lro_entry *queued;
POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
if (!IF_LRO_ENABLED(sc))
return;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
rq->lro_pkts_queued = 0;
return;
diff --git a/sys/dev/ofw/ofw_iicbus.c b/sys/dev/ofw/ofw_iicbus.c
index c0fa054..73cad7c 100644
--- a/sys/dev/ofw/ofw_iicbus.c
+++ b/sys/dev/ofw/ofw_iicbus.c
@@ -80,8 +80,10 @@ static devclass_t ofwiicbus_devclass;
DEFINE_CLASS_1(iicbus, ofw_iicbus_driver, ofw_iicbus_methods,
sizeof(struct iicbus_softc), iicbus_driver);
-DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0);
-DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0);
+EARLY_DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass,
+ 0, 0, BUS_PASS_BUS);
+EARLY_DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass,
+ 0, 0, BUS_PASS_BUS);
MODULE_VERSION(ofw_iicbus, 1);
MODULE_DEPEND(ofw_iicbus, iicbus, 1, 1, 1);
diff --git a/sys/dev/ofw/ofwbus.c b/sys/dev/ofw/ofwbus.c
index 8eb5dd5..fc43410 100644
--- a/sys/dev/ofw/ofwbus.c
+++ b/sys/dev/ofw/ofwbus.c
@@ -200,8 +200,8 @@ ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
start = rle->start;
- count = ulmax(count, rle->count);
- end = ulmax(rle->end, start + count - 1);
+ count = ummax(count, rle->count);
+ end = ummax(rle->end, start + count - 1);
}
switch (type) {
diff --git a/sys/dev/ofw/ofwpci.c b/sys/dev/ofw/ofwpci.c
new file mode 100644
index 0000000..2872fe1
--- /dev/null
+++ b/sys/dev/ofw/ofwpci.c
@@ -0,0 +1,628 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include "pcib_if.h"
+
+/*
+ * If it is necessary to set another value of this for
+ * some platforms it should be set at fdt.h file
+ */
+#ifndef PCI_MAP_INTR
+#define PCI_MAP_INTR 4
+#endif
+
+#define PCI_INTR_PINS 4
+
+/*
+ * bus interface.
+ */
+static struct resource * ofw_pci_alloc_resource(device_t, device_t,
+ int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
+static int ofw_pci_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_adjust_resource(device_t, device_t, int,
+ struct resource *, rman_res_t, rman_res_t);
+
+#ifdef __powerpc__
+static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
+#endif
+
+/*
+ * pcib interface
+ */
+static int ofw_pci_maxslots(device_t);
+
+/*
+ * ofw_bus interface
+ */
+static phandle_t ofw_pci_get_node(device_t, device_t);
+
+/*
+ * local methods
+ */
+static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
+
+/*
+ * Driver methods.
+ */
+static device_method_t ofw_pci_methods[] = {
+
+ /* Device interface */
+ DEVMETHOD(device_attach, ofw_pci_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ofw_pci_write_ivar),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, ofw_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ofw_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, ofw_pci_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
+#ifdef __powerpc__
+ DEVMETHOD(bus_get_bus_tag, ofw_pci_bus_get_bus_tag),
+#endif
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, ofw_pci_maxslots),
+ DEVMETHOD(pcib_route_interrupt, ofw_pci_route_interrupt),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
+
+int
+ofw_pci_init(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ phandle_t node;
+ u_int32_t busrange[2];
+ struct ofw_pci_range *rp;
+ int error;
+ struct ofw_pci_cell_info *cell_info;
+
+ node = ofw_bus_get_node(dev);
+ sc = device_get_softc(dev);
+ sc->sc_initialized = 1;
+ sc->sc_range = NULL;
+
+ cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ sc->sc_cell_info = cell_info;
+
+ if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
+ busrange[0] = 0;
+
+ sc->sc_dev = dev;
+ sc->sc_node = node;
+ sc->sc_bus = busrange[0];
+
+ if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
+ phandle_t c;
+ int n, i;
+
+ sc->sc_nrange = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_nranges(c, cell_info);
+ if (n > 0)
+ sc->sc_nrange += n;
+ }
+ if (sc->sc_nrange == 0) {
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ i = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
+ if (n > 0)
+ i += n;
+ }
+ KASSERT(i == sc->sc_nrange, ("range count mismatch"));
+ } else {
+ sc->sc_nrange = ofw_pci_nranges(node, cell_info);
+ if (sc->sc_nrange <= 0) {
+ device_printf(dev, "could not getranges\n");
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ ofw_pci_fill_ranges(node, sc->sc_range);
+ }
+
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "PCI I/O Ports";
+ error = rman_init(&sc->sc_io_rman);
+ if (error) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "PCI Memory";
+ error = rman_init(&sc->sc_mem_rman);
+ if (error) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
+ rp->pci_hi != 0; rp++) {
+ error = 0;
+
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_CONFIG:
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ error = rman_manage_region(&sc->sc_io_rman, rp->pci,
+ rp->pci + rp->size - 1);
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ error = rman_manage_region(&sc->sc_mem_rman, rp->pci,
+ rp->pci + rp->size - 1);
+ break;
+ }
+
+ if (error) {
+ device_printf(dev,
+ "rman_manage_region(%x, %#jx, %#jx) failed. "
+ "error = %d\n", rp->pci_hi &
+ OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
+ rp->pci + rp->size - 1, error);
+ goto out;
+ }
+ }
+
+ ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
+ return (0);
+
+out:
+ free(cell_info, M_DEVBUF);
+ free(sc->sc_range, M_DEVBUF);
+ rman_fini(&sc->sc_io_rman);
+ rman_fini(&sc->sc_mem_rman);
+
+ return (error);
+}
+
+int
+ofw_pci_attach(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ if (!sc->sc_initialized) {
+ error = ofw_pci_init(dev);
+ if (error)
+ return (error);
+ }
+
+ device_add_child(dev, "pci", -1);
+ return (bus_generic_attach(dev));
+}
+
+static int
+ofw_pci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+int
+ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
+{
+ struct ofw_pci_softc *sc;
+ struct ofw_pci_register reg;
+ uint32_t pintr, mintr[PCI_MAP_INTR];
+ int intrcells;
+ phandle_t iparent;
+
+ sc = device_get_softc(bus);
+ pintr = pin;
+
+ /* Fabricate imap information in case this isn't an OFW device */
+ bzero(&reg, sizeof(reg));
+ reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
+ (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
+ (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
+
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
+ &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
+ mintr, sizeof(mintr), &iparent);
+ if (intrcells != 0) {
+ pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
+ return (pintr);
+ }
+
+ /*
+ * Maybe it's a real interrupt, not an intpin
+ */
+ if (pin > PCI_INTR_PINS)
+ return (pin);
+
+ device_printf(bus, "could not route pin %d for device %d.%d\n",
+ pin, pci_get_slot(dev), pci_get_function(dev));
+ return (PCI_INVALID_IRQ);
+}
+
+int
+ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = device_get_unit(dev);
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_bus;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_bus = value;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
+{
+ ssize_t nbase_ranges;
+
+ if (info == NULL)
+ return (-1);
+
+ info->host_address_cells = 1;
+ info->size_cells = 2;
+ info->pci_address_cell = 3;
+
+ OF_getencprop(OF_parent(node), "#address-cells",
+ &(info->host_address_cells), sizeof(info->host_address_cells));
+ OF_getencprop(node, "#address-cells",
+ &(info->pci_address_cell), sizeof(info->pci_address_cell));
+ OF_getencprop(node, "#size-cells", &(info->size_cells),
+ sizeof(info->size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+
+ return (nbase_ranges / sizeof(cell_t) /
+ (info->pci_address_cell + info->host_address_cells +
+ info->size_cells));
+}
+
+static struct resource *
+ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct ofw_pci_softc *sc;
+ struct resource *rv;
+ struct rman *rm;
+ int needactivate;
+
+ needactivate = flags & RF_ACTIVE;
+ flags &= ~RF_ACTIVE;
+
+ sc = device_get_softc(bus);
+
+ switch (type) {
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ break;
+
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ break;
+
+ case SYS_RES_IRQ:
+ return (bus_alloc_resource(bus, type, rid, start, end, count,
+ flags));
+
+ default:
+ device_printf(bus, "unknown resource request from %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL) {
+ device_printf(bus, "failed to reserve resource for %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv) != 0) {
+ device_printf(bus,
+ "failed to activate resource for %s\n",
+ device_get_nameunit(child));
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+
+ if (rman_get_flags(res) & RF_ACTIVE) {
+ int error = bus_deactivate_resource(child, type, rid, res);
+ if (error)
+ return error;
+ }
+
+ return (rman_release_resource(res));
+}
+
+static int
+ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct ofw_pci_softc *sc;
+ bus_space_handle_t handle;
+ bus_space_tag_t tag;
+ int rv;
+
+ sc = device_get_softc(bus);
+
+ if (type == SYS_RES_IRQ) {
+ return (bus_activate_resource(bus, type, rid, res));
+ }
+ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+ struct ofw_pci_range *rp;
+ vm_paddr_t start;
+ int space;
+
+ start = (vm_paddr_t)rman_get_start(res);
+
+ /*
+ * Map this through the ranges list
+ */
+ for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
+ rp->pci_hi != 0; rp++) {
+ if (start < rp->pci || start >= rp->pci + rp->size)
+ continue;
+
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ space = SYS_RES_IOPORT;
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ space = SYS_RES_MEMORY;
+ break;
+ default:
+ space = -1;
+ }
+
+ if (type == space) {
+ start += (rp->host - rp->pci);
+ break;
+ }
+ }
+
+ if (bootverbose)
+ printf("ofw_pci mapdev: start %jx, len %jd\n",
+ (rman_res_t)start, rman_get_size(res));
+
+ tag = BUS_GET_BUS_TAG(child, child);
+ if (tag == NULL)
+ return (ENOMEM);
+
+ rman_set_bustag(res, tag);
+ rv = bus_space_map(tag, start,
+ rman_get_size(res), 0, &handle);
+ if (rv != 0)
+ return (ENOMEM);
+
+ rman_set_bushandle(res, handle);
+ rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
+ }
+
+ return (rman_activate_resource(res));
+}
+
+#ifdef __powerpc__
+static bus_space_tag_t
+ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
+{
+
+ return (&bs_le_tag);
+}
+#endif
+
+static int
+ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+
+ /*
+ * If this is a memory resource, unmap it.
+ */
+ if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
+ u_int32_t psize;
+
+ psize = rman_get_size(res);
+ pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
+ }
+
+ return (rman_deactivate_resource(res));
+}
+
+static int
+ofw_pci_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *res, rman_res_t start, rman_res_t end)
+{
+ struct rman *rm = NULL;
+ struct ofw_pci_softc *sc = device_get_softc(bus);
+
+ KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
+ ("active resources cannot be adjusted"));
+ if (rman_get_flags(res) & RF_ACTIVE)
+ return (EINVAL);
+
+ switch (type) {
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ if (!rman_is_region_manager(res, rm))
+ return (EINVAL);
+
+ return (rman_adjust_resource(res, start, end));
+}
+
+static phandle_t
+ofw_pci_get_node(device_t bus, device_t dev)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+ /* We only have one child, the PCI bus, which needs our own node. */
+
+ return (sc->sc_node);
+}
+
+static int
+ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
+{
+ int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int nranges;
+ int i, j, k;
+
+ OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
+ sizeof(host_address_cells));
+ OF_getencprop(node, "#address-cells", &pci_address_cells,
+ sizeof(pci_address_cells));
+ OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+ nranges = nbase_ranges / sizeof(cell_t) /
+ (pci_address_cells + host_address_cells + size_cells);
+
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < nranges; i++) {
+ ranges[i].pci_hi = base_ranges[j++];
+ ranges[i].pci = 0;
+ for (k = 0; k < pci_address_cells - 1; k++) {
+ ranges[i].pci <<= 32;
+ ranges[i].pci |= base_ranges[j++];
+ }
+ ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ ranges[i].host <<= 32;
+ ranges[i].host |= base_ranges[j++];
+ }
+ ranges[i].size = 0;
+ for (k = 0; k < size_cells; k++) {
+ ranges[i].size <<= 32;
+ ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (nranges);
+}
diff --git a/sys/dev/ofw/ofwpci.h b/sys/dev/ofw/ofwpci.h
new file mode 100644
index 0000000..e9825ad
--- /dev/null
+++ b/sys/dev/ofw/ofwpci.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_OFW_OFWPCI_H_
+#define _DEV_OFW_OFWPCI_H_
+
+/*
+ * Export class definition for inheritance purposes
+ */
+DECLARE_CLASS(ofw_pci_driver);
+
+struct ofw_pci_cell_info {
+ pcell_t host_address_cells;
+ pcell_t pci_address_cell;
+ pcell_t size_cells;
+ };
+
+struct ofw_pci_range {
+ uint32_t pci_hi;
+ uint64_t pci;
+ uint64_t host;
+ uint64_t size;
+};
+
+/*
+ * Quirks for some adapters
+ */
+enum {
+ OFW_PCI_QUIRK_RANGES_ON_CHILDREN = 1,
+};
+
+struct ofw_pci_softc {
+ device_t sc_dev;
+ phandle_t sc_node;
+ int sc_bus;
+ int sc_initialized;
+ int sc_quirks;
+
+ struct ofw_pci_range *sc_range;
+ int sc_nrange;
+ struct ofw_pci_cell_info *sc_cell_info;
+
+ struct rman sc_io_rman;
+ struct rman sc_mem_rman;
+ bus_space_tag_t sc_memt;
+ bus_dma_tag_t sc_dmat;
+
+ struct ofw_bus_iinfo sc_pci_iinfo;
+};
+
+int ofw_pci_init(device_t);
+int ofw_pci_attach(device_t);
+int ofw_pci_read_ivar(device_t, device_t, int, uintptr_t *);
+int ofw_pci_write_ivar(device_t, device_t, int, uintptr_t);
+int ofw_pci_route_interrupt(device_t, device_t, int);
+int ofw_pci_nranges(phandle_t, struct ofw_pci_cell_info *);
+
+#endif /* _DEV_OFW_OFWPCI_H_ */
diff --git a/sys/dev/pccard/pccard.c b/sys/dev/pccard/pccard.c
index 0681242..04dcc44 100644
--- a/sys/dev/pccard/pccard.c
+++ b/sys/dev/pccard/pccard.c
@@ -507,7 +507,7 @@ pccard_function_init(struct pccard_function *pf, int entry)
end = start + ios->length - 1;
else
end = ~0;
- DEVPRINTF((bus, "I/O rid %d start %#lx end %#lx\n",
+ DEVPRINTF((bus, "I/O rid %d start %#jx end %#jx\n",
i, start, end));
rid = i;
len = ios->length;
@@ -531,7 +531,7 @@ pccard_function_init(struct pccard_function *pf, int entry)
end = start + mems->length - 1;
else
end = ~0;
- DEVPRINTF((bus, "Memory rid %d start %#lx end %#lx\ncardaddr %#lx hostaddr %#lx length %#lx\n",
+ DEVPRINTF((bus, "Memory rid %d start %#jx end %#jx\ncardaddr %#jx hostaddr %#jx length %#jx\n",
i, start, end, mems->cardaddr, mems->hostaddr,
mems->length));
rid = i;
@@ -602,7 +602,7 @@ pccard_function_free(struct pccard_function *pf)
device_printf(pf->sc->dev,
"function_free: Resource still owned by "
"child, oops. "
- "(type=%d, rid=%d, addr=%#lx)\n",
+ "(type=%d, rid=%d, addr=%#jx)\n",
rle->type, rle->rid,
rman_get_start(rle->res));
BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
@@ -697,7 +697,7 @@ pccard_function_enable(struct pccard_function *pf)
&pf->ccr_rid, PCCARD_MEM_PAGE_SIZE, RF_ACTIVE);
if (!pf->ccr_res)
goto bad;
- DEVPRINTF((dev, "ccr_res == %#lx-%#lx, base=%#x\n",
+ DEVPRINTF((dev, "ccr_res == %#jx-%#jx, base=%#x\n",
rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
pf->ccr_base));
CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
@@ -1025,26 +1025,6 @@ pccard_child_location_str(device_t bus, device_t child, char *buf,
return (0);
}
-/* XXX Maybe this should be in subr_bus? */
-static void
-pccard_safe_quote(char *dst, const char *src, size_t len)
-{
- char *walker = dst, *ep = dst + len - 1;
-
- if (len == 0)
- return;
- while (src != NULL && walker < ep)
- {
- if (*src == '"') {
- if (ep - walker < 2)
- break;
- *walker++ = '\\';
- }
- *walker++ = *src++;
- }
- *walker = '\0';
-}
-
static int
pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
size_t buflen)
@@ -1054,8 +1034,8 @@ pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
struct pccard_softc *sc = PCCARD_SOFTC(bus);
char cis0[128], cis1[128];
- pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
- pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
+ devctl_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
+ devctl_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
"cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function);
@@ -1197,7 +1177,7 @@ pccard_release_resource(device_t dev, device_t child, int type, int rid,
if (!rle) {
device_printf(dev, "Allocated resource not found, "
- "%d %#x %#lx %#lx\n",
+ "%d %#x %#jx %#jx\n",
type, rid, rman_get_start(r), rman_get_size(r));
return ENOENT;
}
diff --git a/sys/dev/pccard/pccard_cis.c b/sys/dev/pccard/pccard_cis.c
index 4bd06b5..4bd5e77 100644
--- a/sys/dev/pccard/pccard_cis.c
+++ b/sys/dev/pccard/pccard_cis.c
@@ -151,7 +151,7 @@ pccard_scan_cis(device_t bus, device_t dev, pccard_scan_t fct, void *arg)
tuple.memh = rman_get_bushandle(res);
tuple.ptr = 0;
- DPRINTF(("cis mem map %#x (resource: %#lx)\n",
+ DPRINTF(("cis mem map %#x (resource: %#jx)\n",
(unsigned int) tuple.memh, rman_get_start(res)));
tuple.mult = 2;
@@ -576,9 +576,9 @@ pccard_print_cis(device_t dev)
printf("; iomask %#lx, iospace", cfe->iomask);
for (i = 0; i < cfe->num_iospace; i++) {
- printf(" %#lx", cfe->iospace[i].start);
+ printf(" %#jx", cfe->iospace[i].start);
if (cfe->iospace[i].length)
- printf("-%#lx",
+ printf("-%#jx",
cfe->iospace[i].start +
cfe->iospace[i].length - 1);
}
@@ -587,14 +587,14 @@ pccard_print_cis(device_t dev)
printf("; memspace");
for (i = 0; i < cfe->num_memspace; i++) {
- printf(" %#lx",
+ printf(" %#jx",
cfe->memspace[i].cardaddr);
if (cfe->memspace[i].length)
- printf("-%#lx",
+ printf("-%#jx",
cfe->memspace[i].cardaddr +
cfe->memspace[i].length - 1);
if (cfe->memspace[i].hostaddr)
- printf("@%#lx",
+ printf("@%#jx",
cfe->memspace[i].hostaddr);
}
}
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 9398771..067aa5a 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -229,7 +229,7 @@ cbb_destroy_res(struct cbb_softc *sc)
while ((rle = SLIST_FIRST(&sc->rl)) != NULL) {
device_printf(sc->dev, "Danger Will Robinson: Resource "
"left allocated! This is a bug... "
- "(rid=%x, type=%d, addr=%lx)\n", rle->rid, rle->type,
+ "(rid=%x, type=%d, addr=%jx)\n", rle->rid, rle->type,
rman_get_start(rle->res));
SLIST_REMOVE_HEAD(&sc->rl, link);
free(rle, M_DEVBUF);
@@ -1241,8 +1241,8 @@ cbb_cardbus_alloc_resource(device_t brdev, device_t child, int type,
case SYS_RES_IRQ:
tmp = rman_get_start(sc->irq_res);
if (start > tmp || end < tmp || count != 1) {
- device_printf(child, "requested interrupt %ld-%ld,"
- "count = %ld not supported by cbb\n",
+ device_printf(child, "requested interrupt %jd-%jd,"
+ "count = %jd not supported by cbb\n",
start, end, count);
return (NULL);
}
@@ -1425,8 +1425,8 @@ cbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid,
case SYS_RES_IRQ:
tmp = rman_get_start(sc->irq_res);
if (start > tmp || end < tmp || count != 1) {
- device_printf(child, "requested interrupt %ld-%ld,"
- "count = %ld not supported by cbb\n",
+ device_printf(child, "requested interrupt %jd-%jd,"
+ "count = %jd not supported by cbb\n",
start, end, count);
return (NULL);
}
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index e739027..4ec8d9b 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -313,7 +313,7 @@ cbb_pci_attach(device_t brdev)
mtx_destroy(&sc->mtx);
return (ENOMEM);
} else {
- DEVPRINTF((brdev, "Found memory at %08lx\n",
+ DEVPRINTF((brdev, "Found memory at %jx\n",
rman_get_start(sc->base_res)));
}
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 492efe0..8343181 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1643,7 +1643,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
if (bootverbose) {
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
if (actual == 1)
- device_printf(child, "using IRQ %lu for MSI-X\n",
+ device_printf(child, "using IRQ %ju for MSI-X\n",
rle->start);
else {
int run;
@@ -1653,7 +1653,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
* IRQ values as ranges. 'irq' is the previous IRQ.
* 'run' is true if we are in a range.
*/
- device_printf(child, "using IRQs %lu", rle->start);
+ device_printf(child, "using IRQs %ju", rle->start);
irq = rle->start;
run = 0;
for (i = 1; i < actual; i++) {
@@ -1674,7 +1674,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
}
/* Start new range. */
- printf(",%lu", rle->start);
+ printf(",%ju", rle->start);
irq = rle->start;
}
@@ -3572,13 +3572,13 @@ pci_alloc_secbus(device_t dev, device_t child, int *rid, rman_res_t start,
start, end, count, flags & ~RF_ACTIVE);
if (res == NULL) {
resource_list_delete(rl, PCI_RES_BUS, *rid);
- device_printf(child, "allocating %lu bus%s failed\n",
+ device_printf(child, "allocating %ju bus%s failed\n",
count, count == 1 ? "" : "es");
return (NULL);
}
if (bootverbose)
device_printf(child,
- "Lazy allocation of %lu bus%s at %lu\n", count,
+ "Lazy allocation of %ju bus%s at %ju\n", count,
count == 1 ? "" : "es", rman_get_start(res));
PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1);
PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1);
@@ -4391,9 +4391,9 @@ pci_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
if (device_get_flags(dev))
retval += printf(" flags %#x", device_get_flags(dev));
@@ -4971,13 +4971,13 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
if (res == NULL) {
resource_list_delete(rl, type, *rid);
device_printf(child,
- "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n",
+ "%#jx bytes of rid %#x res %d failed (%#jx, %#jx).\n",
count, *rid, type, start, end);
goto out;
}
if (bootverbose)
device_printf(child,
- "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n",
+ "Lazy allocation of %#jx bytes rid %#x type %d at %#jx\n",
count, *rid, type, rman_get_start(res));
map = rman_get_start(res);
pci_write_bar(child, pm, map);
@@ -5254,7 +5254,7 @@ pci_delete_resource(device_t dev, device_t child, int type, int rid)
resource_list_busy(rl, type, rid)) {
device_printf(dev, "delete_resource: "
"Resource still owned by child, oops. "
- "(type=%d, rid=%d, addr=%lx)\n",
+ "(type=%d, rid=%d, addr=%jx)\n",
type, rid, rman_get_start(rle->res));
return;
}
diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c
index f0c8d45..110ee68 100644
--- a/sys/dev/pci/pci_host_generic.c
+++ b/sys/dev/pci/pci_host_generic.c
@@ -540,7 +540,7 @@ generic_pcie_alloc_resource_pcie(device_t dev, device_t child, int type, int *ri
if (bootverbose) {
device_printf(dev,
- "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
+ "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
start, end, count);
}
@@ -560,7 +560,7 @@ generic_pcie_alloc_resource_pcie(device_t dev, device_t child, int type, int *ri
fail:
device_printf(dev, "%s FAIL: type=%d, rid=%d, "
- "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
+ "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
__func__, type, *rid, start, end, count, flags);
return (NULL);
@@ -744,7 +744,7 @@ generic_pcie_alloc_resource_ofw(device_t bus, device_t child, int type, int *rid
if (i == MAX_RANGES_TUPLES) {
device_printf(bus, "Could not map resource "
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
}
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 24f9b3a..112b198 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -247,7 +247,7 @@ pcib_is_isa_range(struct pcib_softc *sc, rman_res_t start, rman_res_t end,
alias:
if (bootverbose)
device_printf(sc->dev,
- "I/O range %#lx-%#lx overlaps with an ISA alias\n", start,
+ "I/O range %#jx-%#jx overlaps with an ISA alias\n", start,
end);
return (1);
}
@@ -339,7 +339,7 @@ alloc_ranges(rman_res_t start, rman_res_t end, void *arg)
rid = w->reg;
if (bootverbose)
device_printf(as->sc->dev,
- "allocating non-ISA range %#lx-%#lx\n", start, end);
+ "allocating non-ISA range %#jx-%#jx\n", start, end);
as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
&rid, start, end, end - start + 1, 0);
if (as->res[as->count] == NULL)
@@ -621,7 +621,7 @@ pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
if (bootverbose)
device_printf(bus->dev,
- "allocated bus range (%lu-%lu) for rid %d of %s\n",
+ "allocated bus range (%ju-%ju) for rid %d of %s\n",
rman_get_start(res), rman_get_end(res), *rid,
pcib_child_name(child));
rman_set_rid(res, *rid);
@@ -646,7 +646,7 @@ pcib_grow_subbus(struct pcib_secbus *bus, rman_res_t new_end)
if (error)
return (error);
if (bootverbose)
- device_printf(bus->dev, "grew bus range to %lu-%lu\n",
+ device_printf(bus->dev, "grew bus range to %ju-%ju\n",
rman_get_start(bus->res), rman_get_end(bus->res));
error = rman_manage_region(&bus->rman, old_end + 1,
rman_get_end(bus->res));
@@ -694,8 +694,8 @@ pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
/* Finally, attempt to grow the existing resource. */
if (bootverbose) {
device_printf(bus->dev,
- "attempting to grow bus range for %lu buses\n", count);
- printf("\tback candidate range: %lu-%lu\n", start_free,
+ "attempting to grow bus range for %ju buses\n", count);
+ printf("\tback candidate range: %ju-%ju\n", start_free,
new_end);
}
if (pcib_grow_subbus(bus, new_end) == 0)
@@ -1174,7 +1174,7 @@ pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w,
if (bootverbose)
device_printf(sc->dev,
- "allocated %s range (%#lx-%#lx) for rid %x of %s\n",
+ "allocated %s range (%#jx-%#jx) for rid %x of %s\n",
w->name, rman_get_start(res), rman_get_end(res), *rid,
pcib_child_name(child));
rman_set_rid(res, *rid);
@@ -1401,7 +1401,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
if (error) {
if (bootverbose)
device_printf(sc->dev,
- "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n",
+ "failed to allocate initial %s window (%#jx-%#jx,%#jx)\n",
w->name, start, end, count);
return (error);
}
@@ -1433,7 +1433,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (bootverbose)
device_printf(sc->dev,
- "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
+ "attempting to grow %s window for (%#jx-%#jx,%#jx)\n",
w->name, start, end, count);
align = (rman_res_t)1 << RF_ALIGNMENT(flags);
if (start < w->base) {
@@ -1457,7 +1457,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (front >= start && front <= end_free) {
if (bootverbose)
- printf("\tfront candidate range: %#lx-%#lx\n",
+ printf("\tfront candidate range: %#jx-%#jx\n",
front, end_free);
front &= ~wmask;
front = w->base - front;
@@ -1485,7 +1485,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (back <= end && start_free <= back) {
if (bootverbose)
- printf("\tback candidate range: %#lx-%#lx\n",
+ printf("\tback candidate range: %#jx-%#jx\n",
start_free, back);
back |= wmask;
back -= w->limit;
@@ -1709,7 +1709,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
#endif
}
if (end < start) {
- device_printf(dev, "ioport: end (%lx) < start (%lx)\n",
+ device_printf(dev, "ioport: end (%jx) < start (%jx)\n",
end, start);
start = 0;
end = 0;
@@ -1717,13 +1717,13 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
}
if (!ok) {
device_printf(dev, "%s%srequested unsupported I/O "
- "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
+ "range 0x%jx-0x%jx (decoding 0x%x-0x%x)\n",
name, suffix, start, end, sc->iobase, sc->iolimit);
return (NULL);
}
if (bootverbose)
device_printf(dev,
- "%s%srequested I/O range 0x%lx-0x%lx: in range\n",
+ "%s%srequested I/O range 0x%jx-0x%jx: in range\n",
name, suffix, start, end);
break;
@@ -1778,7 +1778,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
#endif
}
if (end < start) {
- device_printf(dev, "memory: end (%lx) < start (%lx)\n",
+ device_printf(dev, "memory: end (%jx) < start (%jx)\n",
end, start);
start = 0;
end = 0;
@@ -1786,7 +1786,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
}
if (!ok && bootverbose)
device_printf(dev,
- "%s%srequested unsupported memory range %#lx-%#lx "
+ "%s%srequested unsupported memory range %#jx-%#jx "
"(decoding %#jx-%#jx, %#jx-%#jx)\n",
name, suffix, start, end,
(uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
@@ -1795,7 +1795,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (NULL);
if (bootverbose)
device_printf(dev,"%s%srequested memory range "
- "0x%lx-0x%lx: good\n",
+ "0x%jx-0x%jx: good\n",
name, suffix, start, end);
break;
diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c
index 77c60c3..f281117 100644
--- a/sys/dev/pci/pci_subr.c
+++ b/sys/dev/pci/pci_subr.c
@@ -185,7 +185,7 @@ pcib_host_res_decodes(struct pcib_host_resources *hr, int type, rman_res_t start
int rid;
if (bootverbose)
- device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n",
+ device_printf(hr->hr_pcib, "decoding %d %srange %#jx-%#jx\n",
type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
end);
rid = resource_list_add_next(&hr->hr_rl, type, start, end,
@@ -229,8 +229,8 @@ restart:
if (((flags & RF_PREFETCHABLE) != 0) !=
((rle->flags & RLE_PREFETCH) != 0))
continue;
- new_start = ulmax(start, rle->start);
- new_end = ulmin(end, rle->end);
+ new_start = ummax(start, rle->start);
+ new_end = ummin(end, rle->end);
if (new_start > new_end ||
new_start + count - 1 > new_end ||
new_start + count < new_start)
@@ -240,7 +240,7 @@ restart:
if (r != NULL) {
if (bootverbose)
device_printf(hr->hr_pcib,
- "allocated type %d (%#lx-%#lx) for rid %x of %s\n",
+ "allocated type %d (%#jx-%#jx) for rid %x of %s\n",
type, rman_get_start(r), rman_get_end(r),
*rid, pcib_child_name(dev));
return (r);
diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c
index 9c9054f..f508275 100644
--- a/sys/dev/ppbus/vpo.c
+++ b/sys/dev/ppbus/vpo.c
@@ -187,17 +187,19 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
#ifdef VP0_DEBUG
int i;
#endif
+ uint8_t *ptr;
+ ptr = scsiio_cdb_ptr(csio);
if (vpo->vpo_isplus) {
errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
csio->ccb_h.target_id,
- (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
+ ptr, csio->cdb_len,
(char *)csio->data_ptr, csio->dxfer_len,
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
} else {
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
csio->ccb_h.target_id,
- (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
+ ptr, csio->cdb_len,
(char *)csio->data_ptr, csio->dxfer_len,
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
}
@@ -208,7 +210,7 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
/* dump of command */
for (i=0; i<csio->cdb_len; i++)
- printf("%x ", ((char *)&csio->cdb_io.cdb_bytes)[i]);
+ printf("%x ", ((char *)ptr)[i]);
printf("\n");
#endif
@@ -307,11 +309,15 @@ vpo_action(struct cam_sim *sim, union ccb *ccb)
csio = &ccb->csio;
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
#ifdef VP0_DEBUG
device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n",
- csio->cdb_io.cdb_bytes[0]);
+ *scsiio_cdb_ptr(csio));
#endif
-
vpo_intr(vpo, csio);
xpt_done(ccb);
diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c
index a23f06c..4c6761f 100644
--- a/sys/dev/ppc/ppc.c
+++ b/sys/dev/ppc/ppc.c
@@ -1699,7 +1699,7 @@ ppc_probe(device_t dev, int rid)
next_bios_ppc += 1;
if (bootverbose)
device_printf(dev,
- "parallel port found at 0x%lx\n", port);
+ "parallel port found at 0x%jx\n", port);
}
#else
if ((next_bios_ppc < BIOS_MAX_PPC) &&
@@ -1707,7 +1707,7 @@ ppc_probe(device_t dev, int rid)
port = *(BIOS_PORTS + next_bios_ppc++);
if (bootverbose)
device_printf(dev,
- "parallel port found at 0x%lx\n", port);
+ "parallel port found at 0x%jx\n", port);
} else {
device_printf(dev, "parallel port not found.\n");
return (ENXIO);
diff --git a/sys/dev/proto/proto_bus_isa.c b/sys/dev/proto/proto_bus_isa.c
index e7438bf..4dad91c 100644
--- a/sys/dev/proto/proto_bus_isa.c
+++ b/sys/dev/proto/proto_bus_isa.c
@@ -80,7 +80,7 @@ proto_isa_probe(device_t dev)
return (ENODEV);
sb = sbuf_new_auto();
- sbuf_printf(sb, "%s:%#lx", proto_isa_prefix, rman_get_start(res));
+ sbuf_printf(sb, "%s:%#jx", proto_isa_prefix, rman_get_start(res));
sbuf_finish(sb);
device_set_desc_copy(dev, sbuf_data(sb));
sbuf_delete(sb);
diff --git a/sys/dev/qlxgb/qla_isr.c b/sys/dev/qlxgb/qla_isr.c
index 3169fd1..983fc12 100644
--- a/sys/dev/qlxgb/qla_isr.c
+++ b/sys/dev/qlxgb/qla_isr.c
@@ -267,7 +267,6 @@ qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
uint32_t comp_idx, desc_count;
q80_stat_desc_t *sdesc;
struct lro_ctrl *lro;
- struct lro_entry *queued;
uint32_t ret = 0;
dev = ha->pci_dev;
@@ -324,11 +323,7 @@ qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
}
}
- while((!SLIST_EMPTY(&lro->lro_active))) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
if (hw->sds[sds_idx].sdsr_next != comp_idx) {
QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
diff --git a/sys/dev/qlxge/qls_isr.c b/sys/dev/qlxge/qls_isr.c
index 03b3a3c..4cca895 100644
--- a/sys/dev/qlxge/qls_isr.c
+++ b/sys/dev/qlxge/qls_isr.c
@@ -232,7 +232,6 @@ qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
uint32_t i, cq_comp_idx;
int ret = 0, tx_comp_done = 0;
struct lro_ctrl *lro;
- struct lro_entry *queued;
cq_b = ha->rx_ring[cq_idx].cq_base_vaddr;
lro = &ha->rx_ring[cq_idx].lro;
@@ -287,11 +286,7 @@ qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
}
}
- while((!SLIST_EMPTY(&lro->lro_active))) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
ha->rx_ring[cq_idx].cq_next = cq_comp_idx;
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index c56d1ec..081ba83 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -183,7 +183,8 @@ random_kthread(void)
/* NOTREACHED */
}
/* This happens well after SI_SUB_RANDOM */
-SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp);
+SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start,
+ &random_proc_kp);
/*
* Run through all fast sources reading entropy for the given
diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c
index e49eda8..27709d0 100644
--- a/sys/dev/sdhci/sdhci_fdt.c
+++ b/sys/dev/sdhci/sdhci_fdt.c
@@ -308,3 +308,4 @@ DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, sdhci_fdt_devclass,
NULL, NULL);
MODULE_DEPEND(sdhci_fdt, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_fdt, mmc, 1, 1, 1);
diff --git a/sys/dev/sdhci/sdhci_pci.c b/sys/dev/sdhci/sdhci_pci.c
index e0fd29c..3ed43ab 100644
--- a/sys/dev/sdhci/sdhci_pci.c
+++ b/sys/dev/sdhci/sdhci_pci.c
@@ -475,3 +475,4 @@ DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, NULL,
NULL);
MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_pci, mmc, 1, 1, 1);
diff --git a/sys/dev/sfxge/sfxge_mcdi.c b/sys/dev/sfxge/sfxge_mcdi.c
index 3a85c28..85d7997 100644
--- a/sys/dev/sfxge/sfxge_mcdi.c
+++ b/sys/dev/sfxge/sfxge_mcdi.c
@@ -250,10 +250,6 @@ sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
}
mcdibuf = malloc(SFXGE_MCDI_MAX_PAYLOAD, M_TEMP, M_WAITOK | M_ZERO);
- if (mcdibuf == NULL) {
- rc = ENOMEM;
- goto fail4;
- }
if ((rc = copyin(ip->u.mcdi.payload, mcdibuf, ip->u.mcdi.len)) != 0) {
goto fail5;
}
@@ -292,7 +288,6 @@ sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
fail6:
fail5:
free(mcdibuf, M_TEMP);
-fail4:
fail3:
fail2:
fail1:
diff --git a/sys/dev/sfxge/sfxge_nvram.c b/sys/dev/sfxge/sfxge_nvram.c
index c4fa224..9113a89 100644
--- a/sys/dev/sfxge/sfxge_nvram.c
+++ b/sys/dev/sfxge/sfxge_nvram.c
@@ -75,10 +75,6 @@ sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
goto fail1;
buf = malloc(chunk_size, M_TEMP, M_WAITOK);
- if (buf == NULL) {
- rc = ENOMEM;
- goto fail2;
- }
off = 0;
while (total_size) {
@@ -108,7 +104,6 @@ sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
fail3:
free(buf, M_TEMP);
-fail2:
efx_nvram_rw_finish(enp, type);
fail1:
return (rc);
diff --git a/sys/dev/siba/siba.c b/sys/dev/siba/siba.c
index 3489ddc..f0bcd9f 100644
--- a/sys/dev/siba/siba.c
+++ b/sys/dev/siba/siba.c
@@ -597,8 +597,8 @@ siba_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return (retval);
}
diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c
index 9ceb444..cb9d800 100644
--- a/sys/dev/siis/siis.c
+++ b/sys/dev/siis/siis.c
@@ -320,7 +320,7 @@ siis_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct siis_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = unit << 13;
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/sound/isa/ad1816.c b/sys/dev/sound/isa/ad1816.c
index f3bb89a..2ae39cf 100644
--- a/sys/dev/sound/isa/ad1816.c
+++ b/sys/dev/sound/isa/ad1816.c
@@ -624,11 +624,11 @@ ad1816_attach(device_t dev)
goto no;
}
if (ad1816->drq2)
- snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2));
+ snprintf(status2, SND_STATUSLEN, ":%jd", rman_get_start(ad1816->drq2));
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
rman_get_start(ad1816->io_base),
rman_get_start(ad1816->irq),
rman_get_start(ad1816->drq1),
diff --git a/sys/dev/sound/isa/ess.c b/sys/dev/sound/isa/ess.c
index 5fd9529..e4032de 100644
--- a/sys/dev/sound/isa/ess.c
+++ b/sys/dev/sound/isa/ess.c
@@ -867,12 +867,12 @@ ess_attach(device_t dev)
}
if (sc->drq2)
- snprintf(buf, SND_STATUSLEN, ":%ld", rman_get_start(sc->drq2));
+ snprintf(buf, SND_STATUSLEN, ":%jd", rman_get_start(sc->drq2));
else
buf[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
- rman_get_start(sc->io_base), rman_get_start(sc->irq),
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
+ rman_get_start(sc->io_base), rman_get_start(sc->irq),
rman_get_start(sc->drq1), buf, sc->bufsize,
PCM_KLDSTRING(snd_ess));
diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c
index 7aaef06..62f6617 100644
--- a/sys/dev/sound/isa/mss.c
+++ b/sys/dev/sound/isa/mss.c
@@ -1326,7 +1326,7 @@ mss_probe(device_t dev)
}
tmp &= 0x3f;
if (!(tmp == 0x04 || tmp == 0x0f || tmp == 0x00 || tmp == 0x05)) {
- BVDDB(printf("No MSS signature detected on port 0x%lx (0x%x)\n",
+ BVDDB(printf("No MSS signature detected on port 0x%jx (0x%x)\n",
rman_get_start(mss->io_base), tmpx));
goto no;
}
@@ -1767,7 +1767,7 @@ mss_doattach(device_t dev, struct mss_info *mss)
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d%s bufsz %u",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %d%s bufsz %u",
rman_get_start(mss->io_base), rman_get_start(mss->irq), pdma, status2, mss->bufsize);
if (pcm_register(dev, mss, 1, 1)) goto no;
diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c
index 536de77..946c6bf 100644
--- a/sys/dev/sound/isa/sb16.c
+++ b/sys/dev/sound/isa/sb16.c
@@ -854,11 +854,11 @@ sb16_attach(device_t dev)
}
if (!(pcm_getflags(dev) & SD_F_SIMPLEX))
- snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(sb->drq2));
+ snprintf(status2, SND_STATUSLEN, ":%jd", rman_get_start(sb->drq2));
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
rman_get_start(sb->io_base), rman_get_start(sb->irq),
rman_get_start(sb->drq1), status2, sb->bufsize,
PCM_KLDSTRING(snd_sb16));
diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c
index 7c39515..c9ed746 100644
--- a/sys/dev/sound/isa/sb8.c
+++ b/sys/dev/sound/isa/sb8.c
@@ -749,7 +749,7 @@ sb_attach(device_t dev)
goto no;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd bufsz %u %s",
rman_get_start(sb->io_base), rman_get_start(sb->irq),
rman_get_start(sb->drq), sb->bufsize, PCM_KLDSTRING(snd_sb8));
diff --git a/sys/dev/sound/pci/als4000.c b/sys/dev/sound/pci/als4000.c
index b214333..bb38749 100644
--- a/sys/dev/sound/pci/als4000.c
+++ b/sys/dev/sound/pci/als4000.c
@@ -848,7 +848,7 @@ als_pci_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &alsrchan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_als4000));
pcm_setstatus(dev, status);
return 0;
diff --git a/sys/dev/sound/pci/atiixp.c b/sys/dev/sound/pci/atiixp.c
index 8df67aa..ca9a539 100644
--- a/sys/dev/sound/pci/atiixp.c
+++ b/sys/dev/sound/pci/atiixp.c
@@ -1097,7 +1097,7 @@ atiixp_chip_post_init(void *arg)
"polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
sysctl_atiixp_polling, "I", "Enable polling mode");
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_atiixp));
diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c
index 67af075..f990f43 100644
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -645,7 +645,7 @@ au_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(type[0] == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal));
diff --git a/sys/dev/sound/pci/cmi.c b/sys/dev/sound/pci/cmi.c
index 6075a92..9e62659 100644
--- a/sys/dev/sound/pci/cmi.c
+++ b/sys/dev/sound/pci/cmi.c
@@ -995,7 +995,7 @@ cmi_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cmi));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/cs4281.c b/sys/dev/sound/pci/cs4281.c
index 929b9d7..4750daf 100644
--- a/sys/dev/sound/pci/cs4281.c
+++ b/sys/dev/sound/pci/cs4281.c
@@ -849,7 +849,7 @@ cs4281_pci_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc);
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cs4281));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index 89ffd2b..5a1544d 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -821,7 +821,7 @@ pcmcsa_attach(device_t dev)
return (ENXIO);
}
- snprintf(status, SND_STATUSLEN, "at irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at irq %jd %s",
rman_get_start(resp->irq),PCM_KLDSTRING(snd_csa));
/* Enable interrupt. */
diff --git a/sys/dev/sound/pci/ds1.c b/sys/dev/sound/pci/ds1.c
index 302271a..23f3d5c 100644
--- a/sys/dev/sound/pci/ds1.c
+++ b/sys/dev/sound/pci/ds1.c
@@ -1010,7 +1010,7 @@ ds_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_ds1));
if (pcm_register(dev, sc, DS1_CHANS, 2))
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c
index c4a13f3..f1d77ee 100644
--- a/sys/dev/sound/pci/emu10k1.c
+++ b/sys/dev/sound/pci/emu10k1.c
@@ -2132,7 +2132,7 @@ emu_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_emu10k1));
diff --git a/sys/dev/sound/pci/emu10kx.c b/sys/dev/sound/pci/emu10kx.c
index b2eaf2c..bd97ab8 100644
--- a/sys/dev/sound/pci/emu10kx.c
+++ b/sys/dev/sound/pci/emu10kx.c
@@ -3225,7 +3225,7 @@ emu_pci_attach(device_t dev)
device_printf(dev, "unable to create control device\n");
goto bad;
}
- snprintf(status, 255, "rev %d at io 0x%lx irq %ld", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
+ snprintf(status, 255, "rev %d at io 0x%jx irq %jd", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
/* Voices */
for (i = 0; i < NUM_G; i++) {
diff --git a/sys/dev/sound/pci/envy24.c b/sys/dev/sound/pci/envy24.c
index c4eaa10..9272a95 100644
--- a/sys/dev/sound/pci/envy24.c
+++ b/sys/dev/sound/pci/envy24.c
@@ -2599,7 +2599,7 @@ envy24_pci_attach(device_t dev)
/* set status iformation */
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
+ "at io 0x%jx:%jd,0x%jx:%jd,0x%jx:%jd,0x%jx:%jd irq %jd",
rman_get_start(sc->cs),
rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
rman_get_start(sc->ddma),
diff --git a/sys/dev/sound/pci/envy24ht.c b/sys/dev/sound/pci/envy24ht.c
index 85a36c2..fe1fb19 100644
--- a/sys/dev/sound/pci/envy24ht.c
+++ b/sys/dev/sound/pci/envy24ht.c
@@ -2507,7 +2507,7 @@ envy24ht_pci_attach(device_t dev)
/* set status iformation */
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
+ "at io 0x%jx:%jd,0x%jx:%jd irq %jd",
rman_get_start(sc->cs),
rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
rman_get_start(sc->mt),
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index 0dd88a8..7032c84 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -1856,7 +1856,7 @@ es_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(es->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(es->reg), rman_get_start(es->irq),
PCM_KLDSTRING(snd_es137x));
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c
index 82b1d77..252e714 100644
--- a/sys/dev/sound/pci/fm801.c
+++ b/sys/dev/sound/pci/fm801.c
@@ -639,7 +639,7 @@ fm801_pci_attach(device_t dev)
goto oops;
}
- snprintf(status, 64, "at %s 0x%lx irq %ld %s",
+ snprintf(status, 64, "at %s 0x%jx irq %jd %s",
(fm801->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(fm801->reg), rman_get_start(fm801->irq),PCM_KLDSTRING(snd_fm801));
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index b0f250c..c761acb 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -159,6 +159,7 @@ static const struct {
{ HDA_ATI_RV940, "ATI RV940", 0, 0 },
{ HDA_ATI_RV970, "ATI RV970", 0, 0 },
{ HDA_ATI_R1000, "ATI R1000", 0, 0 },
+ { HDA_AMD_HUDSON2, "AMD Hudson-2", 0, 0 },
{ HDA_RDC_M3010, "RDC M3010", 0, 0 },
{ HDA_VIA_VT82XX, "VIA VT8251/8237A",0, 0 },
{ HDA_SIS_966, "SiS 966", 0, 0 },
@@ -167,6 +168,7 @@ static const struct {
{ HDA_INTEL_ALL, "Intel", 0, 0 },
{ HDA_NVIDIA_ALL, "NVIDIA", 0, 0 },
{ HDA_ATI_ALL, "ATI", 0, 0 },
+ { HDA_AMD_ALL, "AMD", 0, 0 },
{ HDA_VIA_ALL, "VIA", 0, 0 },
{ HDA_SIS_ALL, "SiS", 0, 0 },
{ HDA_ULI_ALL, "ULI", 0, 0 },
diff --git a/sys/dev/sound/pci/hda/hdac.h b/sys/dev/sound/pci/hda/hdac.h
index 9538b307..1fc265a 100644
--- a/sys/dev/sound/pci/hda/hdac.h
+++ b/sys/dev/sound/pci/hda/hdac.h
@@ -136,6 +136,10 @@
#define HDA_ATI_R1000 HDA_MODEL_CONSTRUCT(ATI, 0xaaa0)
#define HDA_ATI_ALL HDA_MODEL_CONSTRUCT(ATI, 0xffff)
+#define AMD_VENDORID 0x1022
+#define HDA_AMD_HUDSON2 HDA_MODEL_CONSTRUCT(AMD, 0x780d)
+#define HDA_AMD_ALL HDA_MODEL_CONSTRUCT(AMD, 0xffff)
+
/* RDC */
#define RDC_VENDORID 0x17f3
#define HDA_RDC_M3010 HDA_MODEL_CONSTRUCT(RDC, 0x3010)
diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
index dc62377..d84712d 100644
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -668,7 +668,7 @@ hdspe_pcm_attach(device_t dev)
scp->chnum++;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(scp->sc->cs),
rman_get_start(scp->sc->irq),
PCM_KLDSTRING(snd_hdspe));
diff --git a/sys/dev/sound/pci/ich.c b/sys/dev/sound/pci/ich.c
index 4895ad6..61b6781 100644
--- a/sys/dev/sound/pci/ich.c
+++ b/sys/dev/sound/pci/ich.c
@@ -687,7 +687,7 @@ ich_setstatus(struct sc_info *sc)
char status[SND_STATUSLEN];
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx, 0x%lx irq %ld bufsz %u %s",
+ "at io 0x%jx, 0x%jx irq %jd bufsz %u %s",
rman_get_start(sc->nambar), rman_get_start(sc->nabmbar),
rman_get_start(sc->irq), sc->bufsz,PCM_KLDSTRING(snd_ich));
diff --git a/sys/dev/sound/pci/maestro.c b/sys/dev/sound/pci/maestro.c
index c7cbb35..fbadf3b 100644
--- a/sys/dev/sound/pci/maestro.c
+++ b/sys/dev/sound/pci/maestro.c
@@ -1917,7 +1917,7 @@ agg_attach(device_t dev)
adjust_pchbase(ess->pch, ess->playchns, ess->bufsz);
snprintf(status, SND_STATUSLEN,
- "port 0x%lx-0x%lx irq %ld at device %d.%d on pci%d",
+ "port 0x%jx-0x%jx irq %jd at device %d.%d on pci%d",
rman_get_start(reg), rman_get_end(reg), rman_get_start(irq),
pci_get_slot(dev), pci_get_function(dev), pci_get_bus(dev));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/maestro3.c b/sys/dev/sound/pci/maestro3.c
index 20a9bda..5bab021 100644
--- a/sys/dev/sound/pci/maestro3.c
+++ b/sys/dev/sound/pci/maestro3.c
@@ -1440,7 +1440,7 @@ m3_pci_attach(device_t dev)
goto bad;
}
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_maestro3));
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 71c1bf1..8a78bf7 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -702,7 +702,7 @@ nm_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx, 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx, 0x%jx irq %jd %s",
rman_get_start(sc->buf), rman_get_start(sc->reg),
rman_get_start(sc->irq),PCM_KLDSTRING(snd_neomagic));
diff --git a/sys/dev/sound/pci/solo.c b/sys/dev/sound/pci/solo.c
index 534d810..dc46ac8 100644
--- a/sys/dev/sound/pci/solo.c
+++ b/sys/dev/sound/pci/solo.c
@@ -1051,7 +1051,7 @@ ess_attach(device_t dev)
if (mixer_init(dev, &solomixer_class, sc))
goto no;
- snprintf(status, SND_STATUSLEN, "at io 0x%lx,0x%lx,0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx,0x%jx,0x%jx irq %jd %s",
rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc),
rman_get_start(sc->irq),PCM_KLDSTRING(snd_solo));
diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c
index ef48890..32ddd00 100644
--- a/sys/dev/sound/pci/t4dwave.c
+++ b/sys/dev/sound/pci/t4dwave.c
@@ -948,7 +948,7 @@ tr_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, 64, "at io 0x%lx irq %ld %s",
+ snprintf(status, 64, "at io 0x%jx irq %jd %s",
rman_get_start(tr->reg), rman_get_start(tr->irq),PCM_KLDSTRING(snd_t4dwave));
if (pcm_register(dev, tr, dacn, 1))
diff --git a/sys/dev/sound/pci/via8233.c b/sys/dev/sound/pci/via8233.c
index 0694cef..45fe175 100644
--- a/sys/dev/sound/pci/via8233.c
+++ b/sys/dev/sound/pci/via8233.c
@@ -1348,7 +1348,7 @@ via_attach(device_t dev)
ac97_setextmode(via->codec, ext);
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(via->reg), rman_get_start(via->irq),
PCM_KLDSTRING(snd_via8233));
diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c
index 6b615e8..4484d6e 100644
--- a/sys/dev/sound/pci/via82c686.c
+++ b/sys/dev/sound/pci/via82c686.c
@@ -590,7 +590,7 @@ via_attach(device_t dev)
NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0) != 0)
goto bad;
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(via->reg), rman_get_start(via->irq),
PCM_KLDSTRING(snd_via82c686));
diff --git a/sys/dev/sound/pci/vibes.c b/sys/dev/sound/pci/vibes.c
index f16e3ef..22c84c8 100644
--- a/sys/dev/sound/pci/vibes.c
+++ b/sys/dev/sound/pci/vibes.c
@@ -815,7 +815,7 @@ sv_attach(device_t dev) {
((mu - ml) % 0x200)) {
device_printf(dev, "sv_attach: resource assumptions not met "
"(midi 0x%08lx, games 0x%08lx)\n",
- midi_start, games_start);
+ (u_long)midi_start, (u_long)games_start);
goto fail;
}
@@ -874,7 +874,7 @@ sv_attach(device_t dev) {
pcm_addchan(dev, PCMDIR_PLAY, &svpchan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &svrchan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->enh_reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_vibes));
pcm_setstatus(dev, status);
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index cb52ce7..a36afef 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -398,7 +398,6 @@ struct uart_class uart_ns8250_class = {
static struct ofw_compat_data compat_data[] = {
{"ns16550", (uintptr_t)&uart_ns8250_class},
{"ns16550a", (uintptr_t)&uart_ns8250_class},
- {"snps,dw-apb-uart", (uintptr_t)&uart_ns8250_class},
{NULL, (uintptr_t)NULL},
};
UART_FDT_CLASS_AND_DEVICE(compat_data);
@@ -451,19 +450,9 @@ ns8250_bus_attach(struct uart_softc *sc)
pcell_t cell;
#endif
- ns8250->busy_detect = 0;
-
#ifdef FDT
- /*
- * Check whether uart requires to read USR reg when IIR_BUSY and
- * has broken txfifo.
- */
- ns8250->busy_detect = ofw_bus_is_compatible(sc->sc_dev, "snps,dw-apb-uart");
+ /* Check whether uart has a broken txfifo. */
node = ofw_bus_get_node(sc->sc_dev);
- /* XXX: This is kept for a short time for compatibility with older device trees */
- if ((OF_getencprop(node, "busy-detect", &cell, sizeof(cell))) > 0
- && cell != 0)
- ns8250->busy_detect = 1;
if ((OF_getencprop(node, "broken-txfifo", &cell, sizeof(cell))) > 0)
broken_txfifo = cell ? 1 : 0;
#endif
diff --git a/sys/dev/uart/uart_dev_snps.c b/sys/dev/uart/uart_dev_snps.c
new file mode 100644
index 0000000..af4000f
--- /dev/null
+++ b/sys/dev/uart/uart_dev_snps.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * 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 AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu_fdt.h>
+#include <dev/uart/uart_dev_ns8250.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#endif
+
+#include "uart_if.h"
+
+struct snps_softc {
+ struct ns8250_softc ns8250;
+
+#ifdef EXT_RESOURCES
+ clk_t baudclk;
+ clk_t apb_pclk;
+ hwreset_t reset;
+#endif
+};
+
+static int
+snps_uart_attach(struct uart_softc *uart_sc)
+{
+ struct snps_softc *sc;
+
+ sc = (struct snps_softc *)uart_sc;
+
+ /* UART requires to read USR reg when IIR_BUSY */
+ sc->ns8250.busy_detect = 1;
+
+ return (ns8250_bus_attach(uart_sc));
+}
+
+static kobj_method_t snps_methods[] = {
+ KOBJMETHOD(uart_probe, ns8250_bus_probe),
+ KOBJMETHOD(uart_attach, snps_uart_attach),
+ KOBJMETHOD(uart_detach, ns8250_bus_detach),
+ KOBJMETHOD(uart_flush, ns8250_bus_flush),
+ KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
+ KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl),
+ KOBJMETHOD(uart_ipend, ns8250_bus_ipend),
+ KOBJMETHOD(uart_param, ns8250_bus_param),
+ KOBJMETHOD(uart_receive, ns8250_bus_receive),
+ KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
+ KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_grab, ns8250_bus_grab),
+ KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
+ KOBJMETHOD_END
+};
+
+struct uart_class uart_snps_class = {
+ "snps",
+ snps_methods,
+ sizeof(struct snps_softc),
+ .uc_ops = &uart_ns8250_ops,
+ .uc_range = 8,
+ .uc_rclk = 0,
+};
+
+static struct ofw_compat_data compat_data[] = {
+ { "snps,dw-apb-uart", (uintptr_t)&uart_snps_class },
+ { NULL, (uintptr_t)NULL }
+};
+UART_FDT_CLASS(compat_data);
+
+#ifdef EXT_RESOURCES
+static int
+snps_get_clocks(device_t dev, clk_t *baudclk, clk_t *apb_pclk)
+{
+ struct snps_softc *sc;
+
+ sc = device_get_softc(dev);
+ *baudclk = NULL;
+ *apb_pclk = NULL;
+
+ /* Baud clock is either named "baudclk", or there is a single
+ * unnamed clock.
+ */
+ if (clk_get_by_ofw_name(dev, "baudclk", baudclk) != 0 &&
+ clk_get_by_ofw_index(dev, 0, baudclk) != 0)
+ return (ENOENT);
+
+ /* APB peripheral clock is optional */
+ (void)clk_get_by_ofw_name(dev, "apb_pclk", apb_pclk);
+
+ return (0);
+}
+#endif
+
+static int
+snps_probe(device_t dev)
+{
+ struct snps_softc *sc;
+ struct uart_class *uart_class;
+ phandle_t node;
+ uint32_t shift, clock;
+ uint64_t freq;
+ int error;
+#ifdef EXT_RESOURCES
+ clk_t baudclk, apb_pclk;
+ hwreset_t reset;
+#endif
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ uart_class = (struct uart_class *)ofw_bus_search_compatible(dev,
+ compat_data)->ocd_data;
+ if (uart_class == NULL)
+ return (ENXIO);
+
+ freq = 0;
+ sc = device_get_softc(dev);
+ sc->ns8250.base.sc_class = uart_class;
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getencprop(node, "reg-shift", &shift, sizeof(shift)) <= 0)
+ shift = 0;
+ if (OF_getencprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0)
+ clock = 0;
+
+#ifdef EXT_RESOURCES
+ if (hwreset_get_by_ofw_idx(dev, 0, &reset) == 0) {
+ error = hwreset_deassert(reset);
+ if (error != 0) {
+ device_printf(dev, "cannot de-assert reset\n");
+ return (error);
+ }
+ }
+
+ if (snps_get_clocks(dev, &baudclk, &apb_pclk) == 0) {
+ error = clk_enable(baudclk);
+ if (error != 0) {
+ device_printf(dev, "cannot enable baud clock\n");
+ return (error);
+ }
+ if (apb_pclk != NULL) {
+ error = clk_enable(apb_pclk);
+ if (error != 0) {
+ device_printf(dev,
+ "cannot enable peripheral clock\n");
+ return (error);
+ }
+ }
+
+ if (clock == 0) {
+ error = clk_get_freq(baudclk, &freq);
+ if (error != 0) {
+ device_printf(dev, "cannot get frequency\n");
+ return (error);
+ }
+ clock = (uint32_t)freq;
+ }
+ }
+#endif
+
+ if (bootverbose && clock == 0)
+ device_printf(dev, "could not determine frequency\n");
+
+ error = uart_bus_probe(dev, (int)shift, (int)clock, 0, 0);
+ if (error != 0)
+ return (error);
+
+#ifdef EXT_RESOURCES
+ /* XXX uart_bus_probe has changed the softc, so refresh it */
+ sc = device_get_softc(dev);
+
+ /* Store clock and reset handles for detach */
+ sc->baudclk = baudclk;
+ sc->apb_pclk = apb_pclk;
+ sc->reset = reset;
+#endif
+
+ return (0);
+}
+
+static int
+snps_detach(device_t dev)
+{
+#ifdef EXT_RESOURCES
+ struct snps_softc *sc;
+ clk_t baudclk, apb_pclk;
+ hwreset_t reset;
+#endif
+ int error;
+
+#ifdef EXT_RESOURCES
+ sc = device_get_softc(dev);
+ baudclk = sc->baudclk;
+ apb_pclk = sc->apb_pclk;
+ reset = sc->reset;
+#endif
+
+ error = uart_bus_detach(dev);
+ if (error != 0)
+ return (error);
+
+#ifdef EXT_RESOURCES
+ if (reset != NULL) {
+ error = hwreset_assert(reset);
+ if (error != 0) {
+ device_printf(dev, "cannot assert reset\n");
+ return (error);
+ }
+ hwreset_release(reset);
+ }
+ if (apb_pclk != NULL) {
+ error = clk_release(apb_pclk);
+ if (error != 0) {
+ device_printf(dev, "cannot release peripheral clock\n");
+ return (error);
+ }
+ }
+ if (baudclk != NULL) {
+ error = clk_release(baudclk);
+ if (error != 0) {
+ device_printf(dev, "cannot release baud clock\n");
+ return (error);
+ }
+ }
+#endif
+
+ return (0);
+}
+
+static device_method_t snps_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, snps_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, snps_detach),
+ DEVMETHOD_END
+};
+
+static driver_t snps_uart_driver = {
+ uart_driver_name,
+ snps_bus_methods,
+ sizeof(struct snps_softc)
+};
+
+DRIVER_MODULE(uart_snps, simplebus, snps_uart_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/urtwn/if_urtwn.c
index 8b56847..95de7ce 100644
--- a/sys/dev/usb/wlan/if_urtwn.c
+++ b/sys/dev/urtwn/if_urtwn.c
@@ -78,8 +78,8 @@ __FBSDID("$FreeBSD$");
#include <dev/usb/usb_debug.h>
-#include <dev/usb/wlan/if_urtwnreg.h>
-#include <dev/usb/wlan/if_urtwnvar.h>
+#include <dev/urtwn/if_urtwnreg.h>
+#include <dev/urtwn/if_urtwnvar.h>
#ifdef USB_DEBUG
enum {
@@ -95,6 +95,7 @@ enum {
URTWN_DEBUG_ROM = 0x00000200, /* various ROM info */
URTWN_DEBUG_KEY = 0x00000400, /* crypto keys management */
URTWN_DEBUG_TXPWR = 0x00000800, /* dump Tx power values */
+ URTWN_DEBUG_RSSI = 0x00001000, /* dump RSSI lookups */
URTWN_DEBUG_ANY = 0xffffffff
};
@@ -109,6 +110,9 @@ enum {
#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh)
+static int urtwn_enable_11n = 1;
+TUNABLE_INT("hw.usb.urtwn.enable_11n", &urtwn_enable_11n);
+
/* various supported device vendors/products */
static const STRUCT_USB_HOST_ID urtwn_devs[] = {
#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
@@ -465,6 +469,19 @@ urtwn_match(device_t self)
return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa));
}
+static void
+urtwn_update_chw(struct ieee80211com *ic)
+{
+}
+
+static int
+urtwn_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+
+ /* We're driving this ourselves (eventually); don't involve net80211 */
+ return (0);
+}
+
static int
urtwn_attach(device_t self)
{
@@ -555,7 +572,9 @@ urtwn_attach(device_t self)
| IEEE80211_C_HOSTAP /* hostap mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
+#if 0
| IEEE80211_C_BGSCAN /* capable of bg scanning */
+#endif
| IEEE80211_C_WPA /* 802.11i */
| IEEE80211_C_WME /* 802.11e */
;
@@ -565,9 +584,27 @@ urtwn_attach(device_t self)
IEEE80211_CRYPTO_TKIP |
IEEE80211_CRYPTO_AES_CCM;
+ /* Assume they're all 11n capable for now */
+ if (urtwn_enable_11n) {
+ device_printf(self, "enabling 11n\n");
+ ic->ic_htcaps = IEEE80211_HTC_HT |
+ IEEE80211_HTC_AMPDU |
+ IEEE80211_HTC_AMSDU |
+ IEEE80211_HTCAP_MAXAMSDU_3839 |
+ IEEE80211_HTCAP_SMPS_OFF;
+ /* no HT40 just yet */
+ // ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40;
+
+ /* XXX TODO: verify chains versus streams for urtwn */
+ ic->ic_txstream = sc->ntxchains;
+ ic->ic_rxstream = sc->nrxchains;
+ }
+
memset(bands, 0, sizeof(bands));
setbit(bands, IEEE80211_MODE_11B);
setbit(bands, IEEE80211_MODE_11G);
+ if (urtwn_enable_11n)
+ setbit(bands, IEEE80211_MODE_11NG);
ieee80211_init_channels(ic, NULL, bands);
ieee80211_ifattach(ic);
@@ -589,6 +626,8 @@ urtwn_attach(device_t self)
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = urtwn_r88e_node_free;
}
+ ic->ic_update_chw = urtwn_update_chw;
+ ic->ic_ampdu_enable = urtwn_ampdu_enable;
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT,
@@ -1005,6 +1044,9 @@ urtwn_rx_frame(struct urtwn_softc *sc, struct mbuf *m, int8_t *rssi_p)
tap->wr_tsft &= 0xffffffff00000000;
tap->wr_tsft += stat->rxdw5;
+ /* XXX 20/40? */
+ /* XXX shortgi? */
+
/* Map HW rate index to 802.11 rate. */
if (!(rxdw3 & R92C_RXDW3_HT)) {
tap->wr_rate = ridx2rate[rate];
@@ -1081,6 +1123,8 @@ tr_setup:
nf = URTWN_NOISE_FLOOR;
if (ni != NULL) {
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ m->m_flags |= M_AMPDU;
(void)ieee80211_input(ni, m, rssi - nf, nf);
ieee80211_free_node(ni);
} else {
@@ -1827,7 +1871,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
struct ieee80211_node *ni;
- struct ieee80211_rateset *rs;
+ struct ieee80211_rateset *rs, *rs_ht;
struct r92c_fw_cmd_macid_cfg cmd;
uint32_t rates, basicrates;
uint8_t mode;
@@ -1835,10 +1879,13 @@ urtwn_ra_init(struct urtwn_softc *sc)
ni = ieee80211_ref_node(vap->iv_bss);
rs = &ni->ni_rates;
+ rs_ht = (struct ieee80211_rateset *) &ni->ni_htrates;
/* Get normal and basic rates mask. */
rates = basicrates = 0;
maxrate = maxbasicrate = 0;
+
+ /* This is for 11bg */
for (i = 0; i < rs->rs_nrates; i++) {
/* Convert 802.11 rate to HW rate index. */
for (j = 0; j < nitems(ridx2rate); j++)
@@ -1856,10 +1903,32 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxbasicrate = j;
}
}
+
+ /* If we're doing 11n, enable 11n rates */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ for (i = 0; i < rs_ht->rs_nrates; i++) {
+ if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
+ continue;
+ /* 11n rates start at index 12 */
+ j = ((rs_ht->rs_rates[i]) & 0xf) + 12;
+ rates |= (1 << j);
+
+ /* Guard against the rate table being oddly ordered */
+ if (j > maxrate)
+ maxrate = j;
+ }
+ }
+
+#if 0
+ if (ic->ic_curmode == IEEE80211_MODE_11NG)
+ raid = R92C_RAID_11GN;
+#endif
+ /* NB: group addressed frames are done at 11bg rates for now */
if (ic->ic_curmode == IEEE80211_MODE_11B)
mode = R92C_RAID_11B;
else
mode = R92C_RAID_11BG;
+ /* XXX misleading 'mode' value here for unicast frames */
URTWN_DPRINTF(sc, URTWN_DEBUG_RA,
"%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
mode, rates, basicrates);
@@ -1874,6 +1943,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
"could not add broadcast station\n");
return (error);
}
+
/* Set initial MRR rate. */
URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxbasicrate %d\n", __func__,
maxbasicrate);
@@ -1881,6 +1951,12 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxbasicrate);
/* Set rates mask for unicast frames. */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mode = R92C_RAID_11GN;
+ else if (ic->ic_curmode == IEEE80211_MODE_11B)
+ mode = R92C_RAID_11B;
+ else
+ mode = R92C_RAID_11BG;
cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID;
cmd.mask = htole32(mode << 28 | rates);
error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
@@ -1896,7 +1972,11 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxrate);
/* Indicate highest supported rate. */
- ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ni->ni_txrate = rs_ht->rs_rates[rs_ht->rs_nrates - 1]
+ | IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
ieee80211_free_node(ni);
return (0);
@@ -2559,7 +2639,7 @@ urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi)
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
else
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
- URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: PWDB %d, EMA %d\n", __func__,
+ URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: PWDB %d, EMA %d\n", __func__,
pwdb, sc->avg_pwdb);
}
@@ -2643,7 +2723,12 @@ urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
static __inline uint8_t
rate2ridx(uint8_t rate)
{
+ if (rate & IEEE80211_RATE_MCS) {
+ /* 11n rates start at idx 12 */
+ return ((rate & 0xf) + 12);
+ }
switch (rate) {
+ /* 11g */
case 12: return 4;
case 18: return 5;
case 24: return 6;
@@ -2652,6 +2737,7 @@ rate2ridx(uint8_t rate)
case 72: return 9;
case 96: return 10;
case 108: return 11;
+ /* 11b */
case 2: return 0;
case 4: return 1;
case 11: return 2;
@@ -2711,15 +2797,24 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
} else {
- if (ic->ic_curmode != IEEE80211_MODE_11B)
+ /* XXX TODO: drop the default rate for 11b/11g? */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
+ else if (ic->ic_curmode != IEEE80211_MODE_11B)
rate = 108;
else
rate = 22;
}
}
+ /*
+ * XXX TODO: this should be per-node, for 11b versus 11bg
+ * nodes in hostap mode
+ */
ridx = rate2ridx(rate);
- if (ic->ic_curmode != IEEE80211_MODE_11B)
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ raid = R92C_RAID_11GN;
+ else if (ic->ic_curmode != IEEE80211_MODE_11B)
raid = R92C_RAID_11BG;
else
raid = R92C_RAID_11B;
@@ -2763,7 +2858,10 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
} else
txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
- if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ /* protmode, non-HT */
+ /* XXX TODO: noack frames? */
+ if ((rate & 0x80) == 0 &&
+ (ic->ic_flags & IEEE80211_F_USEPROT)) {
switch (ic->ic_protmode) {
case IEEE80211_PROT_CTSONLY:
txd->txdw4 |= htole32(
@@ -2779,8 +2877,21 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
break;
}
}
+
+ /* protmode, HT */
+ /* XXX TODO: noack frames? */
+ if ((rate & 0x80) &&
+ (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) {
+ txd->txdw4 |= htole32(
+ R92C_TXDW4_RTSEN |
+ R92C_TXDW4_HWRTSEN);
+ }
+
+ /* XXX TODO: rtsrate is configurable? 24mbit may
+ * be a bit high for RTS rate? */
txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
URTWN_RIDX_OFDM24));
+
txd->txdw5 |= htole32(0x0001ff00);
} else /* IEEE80211_FC0_TYPE_MGT */
qsel = R92C_TXDW1_QSEL_MGNT;
@@ -2793,14 +2904,21 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
SM(R92C_TXDW1_QSEL, qsel) |
SM(R92C_TXDW1_RAID, raid));
+ /* XXX TODO: 40MHZ flag? */
+ /* XXX TODO: AMPDU flag? (AGG_ENABLE or AGG_BREAK?) Density shift? */
+ /* XXX Short preamble? */
+ /* XXX Short-GI? */
+
if (sc->chip & URTWN_CHIP_88E)
txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid));
else
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid));
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+
/* Force this rate if needed. */
if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast ||
+ (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) ||
(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA)
txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
@@ -2888,6 +3006,8 @@ urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni,
}
}
+ /* XXX TODO: 11n checks, matching urtwn_tx_data() */
+
wh = mtod(m, struct ieee80211_frame *);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
@@ -2916,6 +3036,7 @@ urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni,
else
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC));
+ /* XXX TODO: rate index/config (RAID) for 11n? */
txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/urtwn/if_urtwnreg.h
index 72835f3..72835f3 100644
--- a/sys/dev/usb/wlan/if_urtwnreg.h
+++ b/sys/dev/urtwn/if_urtwnreg.h
diff --git a/sys/dev/usb/wlan/if_urtwnvar.h b/sys/dev/urtwn/if_urtwnvar.h
index ba8ca81..ba8ca81 100644
--- a/sys/dev/usb/wlan/if_urtwnvar.h
+++ b/sys/dev/urtwn/if_urtwnvar.h
diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c
index 3a6f725..cad351c 100644
--- a/sys/dev/usb/controller/ehci_pci.c
+++ b/sys/dev/usb/controller/ehci_pci.c
@@ -112,6 +112,8 @@ ehci_pci_match(device_t self)
case 0x20951022:
return ("AMD CS5536 (Geode) USB 2.0 controller");
+ case 0x78081022:
+ return ("AMD FCH USB 2.0 controller");
case 0x43451002:
return "ATI SB200 USB 2.0 controller";
@@ -168,6 +170,10 @@ ehci_pci_match(device_t self)
return ("Intel Wildcat Point USB 2.0 controller USB-A");
case 0x8cad8086:
return ("Intel Wildcat Point USB 2.0 controller USB-B");
+ case 0x8d268086:
+ return ("Intel Wellsburg USB 2.0 controller");
+ case 0x8d2d8086:
+ return ("Intel Wellsburg USB 2.0 controller");
case 0x9c268086:
return ("Intel Lynx Point LP USB 2.0 controller USB");
diff --git a/sys/dev/usb/controller/ohci_pci.c b/sys/dev/usb/controller/ohci_pci.c
index c50de54..96950a7 100644
--- a/sys/dev/usb/controller/ohci_pci.c
+++ b/sys/dev/usb/controller/ohci_pci.c
@@ -124,9 +124,10 @@ ohci_pci_match(device_t self)
case 0x740c1022:
return ("AMD-756 USB Controller");
-
case 0x74141022:
return ("AMD-766 USB Controller");
+ case 0x78071022:
+ return ("AMD FCH USB Controller");
case 0x43741002:
return "ATI SB400 USB Controller";
diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c
index e7e4412..5916996 100644
--- a/sys/dev/usb/controller/uhci_pci.c
+++ b/sys/dev/usb/controller/uhci_pci.c
@@ -161,6 +161,12 @@ uhci_pci_match(device_t self)
case 0x24de8086:
return ("Intel 82801EB (ICH5) USB controller USB-D");
+ case 0x25a98086:
+ return ("Intel 6300ESB USB controller USB-A");
+
+ case 0x25aa8086:
+ return ("Intel 6300ESB USB controller USB-B");
+
case 0x26588086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-A");
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index 0a8a95b..d4355e9 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -95,6 +95,9 @@ xhci_pci_match(device_t self)
uint32_t device_id = pci_get_devid(self);
switch (device_id) {
+ case 0x78141022:
+ return ("AMD FCH USB 3.0 controller");
+
case 0x01941033:
return ("NEC uPD720200 USB 3.0 controller");
@@ -115,6 +118,8 @@ xhci_pci_match(device_t self)
return ("Intel Lynx Point USB 3.0 controller");
case 0x8cb18086:
return ("Intel Wildcat Point USB 3.0 controller");
+ case 0x8d318086:
+ return ("Intel Wellsburg USB 3.0 controller");
case 0x9cb18086:
return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller");
diff --git a/sys/dev/usb/usb_busdma.c b/sys/dev/usb/usb_busdma.c
index 821e0fb..75378a2 100644
--- a/sys/dev/usb/usb_busdma.c
+++ b/sys/dev/usb/usb_busdma.c
@@ -472,17 +472,22 @@ usb_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
pc->page_offset_buf = rem;
pc->page_offset_end += rem;
#ifdef USB_DEBUG
- if (nseg > 1 &&
- ((segs->ds_addr + segs->ds_len) & (USB_PAGE_SIZE - 1)) !=
- ((segs + 1)->ds_addr & (USB_PAGE_SIZE - 1))) {
- /*
- * This check verifies there is no page offset hole
- * between the first and second segment. See the
- * BUS_DMA_KEEP_PG_OFFSET flag.
- */
- DPRINTFN(0, "Page offset was not preserved\n");
- error = 1;
- goto done;
+ if (nseg > 1) {
+ int x;
+
+ for (x = 0; x != nseg - 1; x++) {
+ if (((segs[x].ds_addr + segs[x].ds_len) & (USB_PAGE_SIZE - 1)) ==
+ ((segs[x + 1].ds_addr & (USB_PAGE_SIZE - 1))))
+ continue;
+ /*
+ * This check verifies there is no page offset
+ * hole between any of the segments. See the
+ * BUS_DMA_KEEP_PG_OFFSET flag.
+ */
+ DPRINTFN(0, "Page offset was not preserved\n");
+ error = 1;
+ goto done;
+ }
}
#endif
while (pc->ismultiseg) {
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 07b3f73..7f75d5a 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -1700,6 +1700,7 @@ product DISPLAYLINK UM7X0 0x401a nanovision MiMo
product DISPLAYLINK LT1421 0x03e0 Lenovo ThinkVision LT1421
product DISPLAYLINK POLARIS2 0x0117 Polaris2 USB dock
product DISPLAYLINK PLUGABLE 0x0377 Plugable docking station
+product DISPLAYLINK ITEC 0x02e9 i-tec USB 2.0 Docking Station
/* DMI products */
product DMI CFSM_RW 0xa109 CF/SM Reader/Writer
diff --git a/sys/dev/usb/video/udl.c b/sys/dev/usb/video/udl.c
index 0d7c504..1096ed3 100644
--- a/sys/dev/usb/video/udl.c
+++ b/sys/dev/usb/video/udl.c
@@ -177,7 +177,8 @@ static const STRUCT_USB_HOST_ID udl_devs[] = {
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_PLUGABLE, DL160)},
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70, DL125)},
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2, DLUNK)},
- {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)}
+ {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)},
+ {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_ITEC, DL165)},
};
static void
diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c
index e428a8f..08be717 100644
--- a/sys/dev/usb/wlan/if_rum.c
+++ b/sys/dev/usb/wlan/if_rum.c
@@ -154,6 +154,7 @@ static usb_callback_t rum_bulk_write_callback;
static usb_error_t rum_do_request(struct rum_softc *sc,
struct usb_device_request *req, void *data);
+static usb_error_t rum_do_mcu_request(struct rum_softc *sc, int);
static struct ieee80211vap *rum_vap_create(struct ieee80211com *,
const char [IFNAMSIZ], int, enum ieee80211_opmode,
int, const uint8_t [IEEE80211_ADDR_LEN],
@@ -165,6 +166,11 @@ static int rum_cmd_sleepable(struct rum_softc *, const void *,
static void rum_tx_free(struct rum_tx_data *, int);
static void rum_setup_tx_list(struct rum_softc *);
static void rum_unsetup_tx_list(struct rum_softc *);
+static void rum_beacon_miss(struct ieee80211vap *);
+static void rum_sta_recv_mgmt(struct ieee80211_node *,
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *, int, int);
+static int rum_set_power_state(struct rum_softc *, int);
static int rum_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static uint8_t rum_crypto_mode(struct rum_softc *, u_int, int);
@@ -232,6 +238,8 @@ static int rum_init(struct rum_softc *);
static void rum_stop(struct rum_softc *);
static void rum_load_microcode(struct rum_softc *, const uint8_t *,
size_t);
+static int rum_set_sleep_time(struct rum_softc *, uint16_t);
+static int rum_reset(struct ieee80211vap *, u_long);
static int rum_set_beacon(struct rum_softc *,
struct ieee80211vap *);
static int rum_alloc_beacon(struct rum_softc *,
@@ -530,6 +538,8 @@ rum_attach(device_t self)
| IEEE80211_C_BGSCAN /* bg scanning supported */
| IEEE80211_C_WPA /* 802.11i */
| IEEE80211_C_WME /* 802.11e */
+ | IEEE80211_C_PMGT /* Station-side power mgmt */
+ | IEEE80211_C_SWSLEEP /* net80211 managed power mgmt */
;
ic->ic_cryptocaps =
@@ -629,6 +639,20 @@ rum_do_request(struct rum_softc *sc,
return (err);
}
+static usb_error_t
+rum_do_mcu_request(struct rum_softc *sc, int request)
+{
+ struct usb_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2573_MCU_CNTL;
+ USETW(req.wValue, request);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+
+ return (rum_do_request(sc, &req, NULL));
+}
+
static struct ieee80211vap *
rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
enum ieee80211_opmode opmode, int flags,
@@ -659,8 +683,24 @@ rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
vap->iv_key_set = rum_key_set;
vap->iv_key_delete = rum_key_delete;
vap->iv_update_beacon = rum_update_beacon;
+ vap->iv_reset = rum_reset;
vap->iv_max_aid = RT2573_ADDR_MAX;
+ if (opmode == IEEE80211_M_STA) {
+ /*
+ * Move device to the sleep state when
+ * beacon is received and there is no data for us.
+ *
+ * Used only for IEEE80211_S_SLEEP state.
+ */
+ rvp->recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = rum_sta_recv_mgmt;
+
+ /* Ignored while sleeping. */
+ rvp->bmiss = vap->iv_bmiss;
+ vap->iv_bmiss = rum_beacon_miss;
+ }
+
usb_callout_init_mtx(&rvp->ratectl_ch, &sc->sc_mtx, 0);
TASK_INIT(&rvp->ratectl_task, 0, rum_ratectl_task, rvp);
ieee80211_ratectl_init(vap);
@@ -795,6 +835,89 @@ rum_unsetup_tx_list(struct rum_softc *sc)
}
}
+static void
+rum_beacon_miss(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct rum_softc *sc = ic->ic_softc;
+ struct rum_vap *rvp = RUM_VAP(vap);
+ int sleep;
+
+ RUM_LOCK(sc);
+ if (sc->sc_sleeping && sc->sc_sleep_end < ticks) {
+ DPRINTFN(12, "dropping 'sleeping' bit, "
+ "device must be awake now\n");
+
+ sc->sc_sleeping = 0;
+ }
+
+ sleep = sc->sc_sleeping;
+ RUM_UNLOCK(sc);
+
+ if (!sleep)
+ rvp->bmiss(vap);
+#ifdef USB_DEBUG
+ else
+ DPRINTFN(13, "bmiss event is ignored whilst sleeping\n");
+#endif
+}
+
+static void
+rum_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
+ const struct ieee80211_rx_stats *rxs,
+ int rssi, int nf)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct rum_softc *sc = vap->iv_ic->ic_softc;
+ struct rum_vap *rvp = RUM_VAP(vap);
+
+ if (vap->iv_state == IEEE80211_S_SLEEP &&
+ subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
+ RUM_LOCK(sc);
+ DPRINTFN(12, "beacon, mybss %d (flags %02X)\n",
+ !!(sc->last_rx_flags & RT2573_RX_MYBSS),
+ sc->last_rx_flags);
+
+ if ((sc->last_rx_flags & (RT2573_RX_MYBSS | RT2573_RX_BC)) ==
+ (RT2573_RX_MYBSS | RT2573_RX_BC)) {
+ /*
+ * Put it to sleep here; in case if there is a data
+ * for us, iv_recv_mgmt() will wakeup the device via
+ * SLEEP -> RUN state transition.
+ */
+ rum_set_power_state(sc, 1);
+ }
+ RUM_UNLOCK(sc);
+ }
+
+ rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
+}
+
+static int
+rum_set_power_state(struct rum_softc *sc, int sleep)
+{
+ usb_error_t uerror;
+
+ RUM_LOCK_ASSERT(sc);
+
+ DPRINTFN(12, "moving to %s state (sleep time %u)\n",
+ sleep ? "sleep" : "awake", sc->sc_sleep_time);
+
+ uerror = rum_do_mcu_request(sc,
+ sleep ? RT2573_MCU_SLEEP : RT2573_MCU_WAKEUP);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ device_printf(sc->sc_dev,
+ "%s: could not change power state: %s\n",
+ __func__, usbd_errstr(uerror));
+ return (EIO);
+ }
+
+ sc->sc_sleeping = !!sleep;
+ sc->sc_sleep_end = sleep ? ticks + sc->sc_sleep_time : 0;
+
+ return (0);
+}
+
static int
rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
@@ -804,7 +927,8 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
const struct ieee80211_txparam *tp;
enum ieee80211_state ostate;
struct ieee80211_node *ni;
- int ret;
+ usb_error_t uerror;
+ int ret = 0;
ostate = vap->iv_state;
DPRINTF("%s -> %s\n",
@@ -815,6 +939,17 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
RUM_LOCK(sc);
usb_callout_stop(&rvp->ratectl_ch);
+ if (ostate == IEEE80211_S_SLEEP && vap->iv_opmode == IEEE80211_M_STA) {
+ rum_clrbits(sc, RT2573_TXRX_CSR4, RT2573_ACKCTS_PWRMGT);
+ rum_clrbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+
+ /*
+ * Ignore any errors;
+ * any subsequent TX will wakeup it anyway
+ */
+ (void) rum_set_power_state(sc, 0);
+ }
+
switch (nstate) {
case IEEE80211_S_INIT:
if (ostate == IEEE80211_S_RUN)
@@ -823,6 +958,9 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
break;
case IEEE80211_S_RUN:
+ if (ostate == IEEE80211_S_SLEEP)
+ break; /* already handled */
+
ni = ieee80211_ref_node(vap->iv_bss);
if (vap->iv_opmode != IEEE80211_M_MONITOR) {
@@ -857,20 +995,39 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
rum_ratectl_start(sc, ni);
+run_fail:
ieee80211_free_node(ni);
break;
+ case IEEE80211_S_SLEEP:
+ /* Implemented for STA mode only. */
+ if (vap->iv_opmode != IEEE80211_M_STA)
+ break;
+
+ uerror = rum_setbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ ret = EIO;
+ break;
+ }
+
+ uerror = rum_setbits(sc, RT2573_TXRX_CSR4, RT2573_ACKCTS_PWRMGT);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ ret = EIO;
+ break;
+ }
+
+ ret = rum_set_power_state(sc, 1);
+ if (ret != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not move to the SLEEP state: %s\n",
+ __func__, usbd_errstr(uerror));
+ }
+ break;
default:
break;
}
RUM_UNLOCK(sc);
IEEE80211_LOCK(ic);
- return (rvp->newstate(vap, nstate, arg));
-
-run_fail:
- RUM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- ieee80211_free_node(ni);
- return ret;
+ return (ret == 0 ? rvp->newstate(vap, nstate, arg) : ret);
}
static void
@@ -1001,6 +1158,7 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
rssi = rum_get_rssi(sc, sc->sc_rx_desc.rssi);
flags = le32toh(sc->sc_rx_desc.flags);
+ sc->last_rx_flags = flags;
if (flags & RT2573_RX_CRC_ERROR) {
/*
* This should not happen since we did not
@@ -1995,6 +2153,7 @@ rum_enable_tsf_sync(struct rum_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
uint32_t tmp;
+ uint16_t bintval;
if (vap->iv_opmode != IEEE80211_M_STA) {
/*
@@ -2008,7 +2167,8 @@ rum_enable_tsf_sync(struct rum_softc *sc)
tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000;
/* set beacon interval (in 1/16ms unit) */
- tmp |= vap->iv_bss->ni_intval * 16;
+ bintval = vap->iv_bss->ni_intval;
+ tmp |= bintval * 16;
tmp |= RT2573_TSF_TIMER_EN | RT2573_TBTT_TIMER_EN;
switch (vap->iv_opmode) {
@@ -2042,7 +2202,8 @@ rum_enable_tsf_sync(struct rum_softc *sc)
if (rum_write(sc, RT2573_TXRX_CSR9, tmp) != 0)
return EIO;
- return 0;
+ /* refresh current sleep time */
+ return (rum_set_sleep_time(sc, bintval));
}
static void
@@ -2460,7 +2621,6 @@ rum_stop(struct rum_softc *sc)
static void
rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
{
- struct usb_device_request req;
uint16_t reg = RT2573_MCU_CODE_BASE;
usb_error_t err;
@@ -2475,14 +2635,8 @@ rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
}
}
- req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
- req.bRequest = RT2573_MCU_CNTL;
- USETW(req.wValue, RT2573_MCU_RUN);
- USETW(req.wIndex, 0);
- USETW(req.wLength, 0);
-
- err = rum_do_request(sc, &req, NULL);
- if (err != 0) {
+ err = rum_do_mcu_request(sc, RT2573_MCU_RUN);
+ if (err != USB_ERR_NORMAL_COMPLETION) {
device_printf(sc->sc_dev, "could not run firmware: %s\n",
usbd_errstr(err));
}
@@ -2492,6 +2646,72 @@ rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
}
static int
+rum_set_sleep_time(struct rum_softc *sc, uint16_t bintval)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ usb_error_t uerror;
+ int exp, delay;
+
+ RUM_LOCK_ASSERT(sc);
+
+ exp = ic->ic_lintval / bintval;
+ delay = ic->ic_lintval % bintval;
+
+ if (exp > RT2573_TBCN_EXP_MAX)
+ exp = RT2573_TBCN_EXP_MAX;
+ if (delay > RT2573_TBCN_DELAY_MAX)
+ delay = RT2573_TBCN_DELAY_MAX;
+
+ uerror = rum_modbits(sc, RT2573_MAC_CSR11,
+ RT2573_TBCN_EXP(exp) |
+ RT2573_TBCN_DELAY(delay),
+ RT2573_TBCN_EXP(RT2573_TBCN_EXP_MAX) |
+ RT2573_TBCN_DELAY(RT2573_TBCN_DELAY_MAX));
+
+ if (uerror != USB_ERR_NORMAL_COMPLETION)
+ return (EIO);
+
+ sc->sc_sleep_time = IEEE80211_TU_TO_TICKS(exp * bintval + delay);
+
+ return (0);
+}
+
+static int
+rum_reset(struct ieee80211vap *vap, u_long cmd)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_node *ni;
+ struct rum_softc *sc = ic->ic_softc;
+ int error;
+
+ switch (cmd) {
+ case IEEE80211_IOC_POWERSAVE:
+ error = 0;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ ni = ieee80211_ref_node(vap->iv_bss);
+
+ RUM_LOCK(sc);
+ error = rum_set_sleep_time(sc, ni->ni_intval);
+ if (vap->iv_state == IEEE80211_S_SLEEP) {
+ /* Use new values for wakeup timer. */
+ rum_clrbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ rum_setbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ }
+ /* XXX send reassoc */
+ RUM_UNLOCK(sc);
+
+ ieee80211_free_node(ni);
+ break;
+ default:
+ error = ENETRESET;
+ break;
+ }
+
+ return (error);
+}
+
+static int
rum_set_beacon(struct rum_softc *sc, struct ieee80211vap *vap)
{
struct ieee80211com *ic = vap->iv_ic;
@@ -2924,14 +3144,15 @@ rum_scan_end(struct ieee80211com *ic)
{
struct rum_softc *sc = ic->ic_softc;
- RUM_LOCK(sc);
- if (ic->ic_opmode != IEEE80211_M_AHDEMO)
- rum_enable_tsf_sync(sc);
- else
- rum_enable_tsf(sc);
- rum_set_bssid(sc, sc->sc_bssid);
- RUM_UNLOCK(sc);
-
+ if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) {
+ RUM_LOCK(sc);
+ if (ic->ic_opmode != IEEE80211_M_AHDEMO)
+ rum_enable_tsf_sync(sc);
+ else
+ rum_enable_tsf(sc);
+ rum_set_bssid(sc, sc->sc_bssid);
+ RUM_UNLOCK(sc);
+ }
}
static void
diff --git a/sys/dev/usb/wlan/if_rumreg.h b/sys/dev/usb/wlan/if_rumreg.h
index 06c0a81..96726b1 100644
--- a/sys/dev/usb/wlan/if_rumreg.h
+++ b/sys/dev/usb/wlan/if_rumreg.h
@@ -136,6 +136,13 @@
/* possible flags for register MAC_CSR5 */
#define RT2573_NUM_BSSID_MSK(n) (((n * 3) & 3) << 16)
+/* possible flags for register MAC_CSR11 */
+#define RT2573_AUTO_WAKEUP (1 << 15)
+#define RT2573_TBCN_EXP(n) ((n) << 8)
+#define RT2573_TBCN_EXP_MAX 0x7f
+#define RT2573_TBCN_DELAY(t) (t)
+#define RT2573_TBCN_DELAY_MAX 0xff
+
/* possible flags for register TXRX_CSR0 */
/* Tx filter flags are in the low 16 bits */
#define RT2573_AUTO_TX_SEQ (1 << 15)
@@ -152,6 +159,7 @@
#define RT2573_DROP_ACKCTS (1 << 25)
/* possible flags for register TXRX_CSR4 */
+#define RT2573_ACKCTS_PWRMGT (1 << 16)
#define RT2573_SHORT_PREAMBLE (1 << 18)
#define RT2573_MRR_ENABLED (1 << 19)
#define RT2573_MRR_CCK_FALLBACK (1 << 22)
@@ -188,7 +196,10 @@
#define RT2573_LED_ON 0x1e1e
#define RT2573_LED_OFF 0x0
-#define RT2573_MCU_RUN (1 << 3)
+/* USB vendor requests */
+#define RT2573_MCU_SLEEP 7
+#define RT2573_MCU_RUN 8
+#define RT2573_MCU_WAKEUP 9
#define RT2573_SMART_MODE (1 << 0)
diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h
index d494468..6c42569 100644
--- a/sys/dev/usb/wlan/if_rumvar.h
+++ b/sys/dev/usb/wlan/if_rumvar.h
@@ -96,6 +96,11 @@ struct rum_vap {
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
+ void (*bmiss)(struct ieee80211vap *);
+ void (*recv_mgmt)(struct ieee80211_node *,
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *,
+ int, int);
};
#define RUM_VAP(vap) ((struct rum_vap *)(vap))
@@ -124,6 +129,10 @@ struct rum_softc {
struct mtx sc_mtx;
+ int sc_sleep_end;
+ int sc_sleep_time;
+ uint8_t last_rx_flags;
+
struct rum_cmdq cmdq[RUM_CMDQ_SIZE];
struct mtx cmdq_mtx;
struct task cmdq_task;
@@ -135,6 +144,7 @@ struct rum_softc {
uint8_t txpow[44];
u_int sc_detached:1,
sc_running:1,
+ sc_sleeping:1,
sc_clr_shkeys:1;
uint8_t sc_bssid[IEEE80211_ADDR_LEN];
diff --git a/sys/dev/vnic/nic_main.c b/sys/dev/vnic/nic_main.c
index 0b21952..ae04326 100644
--- a/sys/dev/vnic/nic_main.c
+++ b/sys/dev/vnic/nic_main.c
@@ -119,7 +119,7 @@ static int nicpf_detach(device_t);
#ifdef PCI_IOV
static int nicpf_iov_init(device_t, uint16_t, const nvlist_t *);
static void nicpf_iov_uninit(device_t);
-static int nicpf_iov_addr_vf(device_t, uint16_t, const nvlist_t *);
+static int nicpf_iov_add_vf(device_t, uint16_t, const nvlist_t *);
#endif
static device_method_t nicpf_methods[] = {
@@ -131,7 +131,7 @@ static device_method_t nicpf_methods[] = {
#ifdef PCI_IOV
DEVMETHOD(pci_iov_init, nicpf_iov_init),
DEVMETHOD(pci_iov_uninit, nicpf_iov_uninit),
- DEVMETHOD(pci_iov_add_vf, nicpf_iov_addr_vf),
+ DEVMETHOD(pci_iov_add_vf, nicpf_iov_add_vf),
#endif
DEVMETHOD_END,
};
@@ -269,18 +269,9 @@ nicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
nic = device_get_softc(dev);
- nic->num_vf_en = 0;
if (num_vfs == 0)
return (ENXIO);
- if (num_vfs > MAX_NUM_VFS_SUPPORTED)
- return (EINVAL);
- /*
- * Just set variables here.
- * The number of VFs will be written to configuration
- * space later in PCI_ADD_VF().
- */
- nic->num_vf_en = num_vfs;
nic->flags |= NIC_SRIOV_ENABLED;
return (0);
@@ -294,7 +285,7 @@ nicpf_iov_uninit(device_t dev)
}
static int
-nicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
+nicpf_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
{
const void *mac;
struct nicpf *nic;
@@ -306,6 +297,9 @@ nicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
if ((nic->flags & NIC_SRIOV_ENABLED) == 0)
return (ENXIO);
+ if (vfnum > (nic->num_vf_en - 1))
+ return (EINVAL);
+
if (nvlist_exists_binary(params, "mac-addr") != 0) {
mac = nvlist_get_binary(params, "mac-addr", &size);
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
@@ -1094,11 +1088,8 @@ static int nic_sriov_init(device_t dev, struct nicpf *nic)
}
/* Fix-up the number of enabled VFs */
total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2);
- if (total_vf_cnt < nic->num_vf_en)
- nic->num_vf_en = total_vf_cnt;
-
if (total_vf_cnt == 0)
- return (0);
+ return (ENXIO);
/* Attach SR-IOV */
pf_schema = pci_iov_schema_alloc_node();
@@ -1116,7 +1107,6 @@ static int nic_sriov_init(device_t dev, struct nicpf *nic)
device_printf(dev,
"Failed to initialize SR-IOV (error=%d)\n",
err);
- nic->num_vf_en = 0;
return (err);
}
#endif
diff --git a/sys/dev/vnic/nicvf_main.c b/sys/dev/vnic/nicvf_main.c
index 4625846..5b74ac9 100644
--- a/sys/dev/vnic/nicvf_main.c
+++ b/sys/dev/vnic/nicvf_main.c
@@ -661,12 +661,6 @@ nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf)
sq = &qs->sq[qidx];
- if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING) {
- err = drbr_enqueue(ifp, sq->br, mbuf);
- return (err);
- }
-
if (mbuf->m_next != NULL &&
(mbuf->m_pkthdr.csum_flags &
(CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)) != 0) {
@@ -679,17 +673,23 @@ nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf)
}
}
+ err = drbr_enqueue(ifp, sq->br, mbuf);
+ if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING) || !nic->link_up || (err != 0)) {
+ /*
+ * Try to enqueue packet to the ring buffer.
+ * If the driver is not active, link down or enqueue operation
+ * failed, return with the appropriate error code.
+ */
+ return (err);
+ }
+
if (NICVF_TX_TRYLOCK(sq) != 0) {
- err = nicvf_tx_mbuf_locked(sq, mbuf);
+ err = nicvf_xmit_locked(sq);
NICVF_TX_UNLOCK(sq);
return (err);
- } else {
- err = drbr_enqueue(ifp, sq->br, mbuf);
- if (err != 0)
- return (err);
-
+ } else
taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
- }
return (0);
}
diff --git a/sys/dev/vnic/nicvf_queues.c b/sys/dev/vnic/nicvf_queues.c
index 13ea636..9b46d7c 100644
--- a/sys/dev/vnic/nicvf_queues.c
+++ b/sys/dev/vnic/nicvf_queues.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sockio.h>
#include <sys/socket.h>
-#include <sys/stdatomic.h>
#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -61,11 +60,12 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/vmparam.h>
-#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_media.h>
#include <net/ifq.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
@@ -106,6 +106,8 @@ static void nicvf_cmp_queue_config(struct nicvf *, struct queue_set *, int,
boolean_t);
static void nicvf_sq_free_used_descs(struct nicvf *, struct snd_queue *, int);
+static int nicvf_tx_mbuf_locked(struct snd_queue *, struct mbuf **);
+
static void nicvf_rbdr_task(void *, int);
static void nicvf_rbdr_task_nowait(void *, int);
@@ -740,10 +742,10 @@ nicvf_cq_intr_handler(struct nicvf *nic, uint8_t cq_idx)
int cqe_count, cqe_head;
struct queue_set *qs = nic->qs;
struct cmp_queue *cq = &qs->cq[cq_idx];
+ struct snd_queue *sq = &qs->sq[cq_idx];
struct rcv_queue *rq;
struct cqe_rx_t *cq_desc;
struct lro_ctrl *lro;
- struct lro_entry *queued;
int rq_idx;
int cmp_err;
@@ -819,6 +821,7 @@ done:
((if_getdrvflags(nic->ifp) & IFF_DRV_RUNNING) != 0)) {
/* Reenable TXQ if its stopped earlier due to SQ full */
if_setdrvflagbits(nic->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
+ taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
}
out:
/*
@@ -827,10 +830,7 @@ out:
rq_idx = cq_idx;
rq = &nic->qs->rq[rq_idx];
lro = &rq->lro;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
NICVF_CMP_UNLOCK(cq);
@@ -992,25 +992,62 @@ nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq)
memset(cq->mtx_name, 0, sizeof(cq->mtx_name));
}
-static void
-nicvf_snd_task(void *arg, int pending)
+int
+nicvf_xmit_locked(struct snd_queue *sq)
{
- struct snd_queue *sq = (struct snd_queue *)arg;
- struct mbuf *mbuf;
+ struct nicvf *nic;
+ struct ifnet *ifp;
+ struct mbuf *next;
+ int err;
- NICVF_TX_LOCK(sq);
- while (1) {
- mbuf = drbr_dequeue(NULL, sq->br);
- if (mbuf == NULL)
- break;
+ NICVF_TX_LOCK_ASSERT(sq);
+
+ nic = sq->nic;
+ ifp = nic->ifp;
+ err = 0;
+
+ while ((next = drbr_peek(ifp, sq->br)) != NULL) {
+ err = nicvf_tx_mbuf_locked(sq, &next);
+ if (err != 0) {
+ if (next == NULL)
+ drbr_advance(ifp, sq->br);
+ else
+ drbr_putback(ifp, sq->br, next);
- if (nicvf_tx_mbuf_locked(sq, mbuf) != 0) {
- /* XXX ARM64TODO: Increase Tx drop counter */
- m_freem(mbuf);
break;
}
+ drbr_advance(ifp, sq->br);
+ /* Send a copy of the frame to the BPF listener */
+ ETHER_BPF_MTAP(ifp, next);
}
+ return (err);
+}
+
+static void
+nicvf_snd_task(void *arg, int pending)
+{
+ struct snd_queue *sq = (struct snd_queue *)arg;
+ struct nicvf *nic;
+ struct ifnet *ifp;
+ int err;
+
+ nic = sq->nic;
+ ifp = nic->ifp;
+
+ /*
+ * Skip sending anything if the driver is not running,
+ * SQ full or link is down.
+ */
+ if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING) || !nic->link_up)
+ return;
+
+ NICVF_TX_LOCK(sq);
+ err = nicvf_xmit_locked(sq);
NICVF_TX_UNLOCK(sq);
+ /* Try again */
+ if (err != 0)
+ taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
}
/* Initialize transmit queue */
@@ -1048,7 +1085,7 @@ nicvf_init_snd_queue(struct nicvf *nic, struct snd_queue *sq, int q_len,
sq->desc = sq->dmem.base;
sq->head = sq->tail = 0;
- atomic_store_rel_int(&sq->free_cnt, q_len - 1);
+ sq->free_cnt = q_len - 1;
sq->thresh = SND_QUEUE_THRESH;
sq->idx = qidx;
sq->nic = nic;
@@ -1640,7 +1677,7 @@ nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt)
int qentry;
qentry = sq->tail;
- atomic_subtract_int(&sq->free_cnt, desc_cnt);
+ sq->free_cnt -= desc_cnt;
sq->tail += desc_cnt;
sq->tail &= (sq->dmem.q_len - 1);
@@ -1652,7 +1689,7 @@ static void
nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt)
{
- atomic_add_int(&sq->free_cnt, desc_cnt);
+ sq->free_cnt += desc_cnt;
sq->head += desc_cnt;
sq->head &= (sq->dmem.q_len - 1);
}
@@ -1772,7 +1809,6 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
}
ip = (struct ip *)(mbuf->m_data + ehdrlen);
- ip->ip_sum = 0;
iphlen = ip->ip_hl << 2;
poff = ehdrlen + iphlen;
@@ -1864,8 +1900,8 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
}
/* Put an mbuf to a SQ for packet transfer. */
-int
-nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
+static int
+nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf **mbufp)
{
bus_dma_segment_t segs[256];
struct nicvf *nic;
@@ -1883,15 +1919,17 @@ nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
snd_buff = &sq->snd_buff[sq->tail];
err = bus_dmamap_load_mbuf_sg(sq->snd_buff_dmat, snd_buff->dmap,
- mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
- if (err != 0) {
+ *mbufp, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (__predict_false(err != 0)) {
/* ARM64TODO: Add mbuf defragmenting if we lack maps */
+ m_freem(*mbufp);
+ *mbufp = NULL;
return (err);
}
/* Set how many subdescriptors is required */
nic = sq->nic;
- if (mbuf->m_pkthdr.tso_segsz != 0 && nic->hw_tso)
+ if ((*mbufp)->m_pkthdr.tso_segsz != 0 && nic->hw_tso)
subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
else
subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT + nsegs - 1;
@@ -1905,10 +1943,15 @@ nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
/* Add SQ header subdesc */
- err = nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, mbuf,
- mbuf->m_pkthdr.len);
+ err = nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, *mbufp,
+ (*mbufp)->m_pkthdr.len);
if (err != 0) {
+ nicvf_put_sq_desc(sq, subdesc_cnt);
bus_dmamap_unload(sq->snd_buff_dmat, snd_buff->dmap);
+ if (err == ENOBUFS) {
+ m_freem(*mbufp);
+ *mbufp = NULL;
+ }
return (err);
}
@@ -1985,19 +2028,23 @@ nicvf_get_rcv_mbuf(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
/*
* HW by default verifies IP & TCP/UDP/SCTP checksums
*/
-
- /* XXX: Do we need to include IP with options too? */
- if (__predict_true(cqe_rx->l3_type == L3TYPE_IPV4 ||
- cqe_rx->l3_type == L3TYPE_IPV6)) {
+ if (__predict_true(cqe_rx->l3_type == L3TYPE_IPV4)) {
mbuf->m_pkthdr.csum_flags =
(CSUM_IP_CHECKED | CSUM_IP_VALID);
}
- if (cqe_rx->l4_type == L4TYPE_TCP ||
- cqe_rx->l4_type == L4TYPE_UDP ||
- cqe_rx->l4_type == L4TYPE_SCTP) {
+
+ switch (cqe_rx->l4_type) {
+ case L4TYPE_UDP:
+ case L4TYPE_TCP: /* fall through */
mbuf->m_pkthdr.csum_flags |=
(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
- mbuf->m_pkthdr.csum_data = htons(0xffff);
+ mbuf->m_pkthdr.csum_data = 0xffff;
+ break;
+ case L4TYPE_SCTP:
+ mbuf->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+ break;
+ default:
+ break;
}
}
}
diff --git a/sys/dev/vnic/nicvf_queues.h b/sys/dev/vnic/nicvf_queues.h
index 8a27880..0fe8e3b 100644
--- a/sys/dev/vnic/nicvf_queues.h
+++ b/sys/dev/vnic/nicvf_queues.h
@@ -388,7 +388,7 @@ void nicvf_disable_intr(struct nicvf *, int, int);
void nicvf_clear_intr(struct nicvf *, int, int);
int nicvf_is_intr_enabled(struct nicvf *, int, int);
-int nicvf_tx_mbuf_locked(struct snd_queue *, struct mbuf *);
+int nicvf_xmit_locked(struct snd_queue *sq);
/* Register access APIs */
void nicvf_reg_write(struct nicvf *, uint64_t, uint64_t);
diff --git a/sys/dev/vnic/thunder_bgx_fdt.c b/sys/dev/vnic/thunder_bgx_fdt.c
index ec6e68f..b4d77cf 100644
--- a/sys/dev/vnic/thunder_bgx_fdt.c
+++ b/sys/dev/vnic/thunder_bgx_fdt.c
@@ -285,18 +285,9 @@ bgx_fdt_init_phy(struct bgx *bgx)
continue;
}
- if (OF_getencprop(child, "phy-handle", &phy,
- sizeof(phy)) <= 0) {
- if (bootverbose) {
- device_printf(bgx->dev,
- "No phy-handle in PHY node. Skipping...\n");
- }
- continue;
- }
/* Acquire PHY address */
- phy = OF_node_from_xref(phy);
- if (OF_getencprop(phy, "reg", &bgx->lmac[lmac].phyaddr,
+ if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr,
sizeof(bgx->lmac[lmac].phyaddr)) <= 0) {
if (bootverbose) {
device_printf(bgx->dev,
@@ -305,6 +296,15 @@ bgx_fdt_init_phy(struct bgx *bgx)
bgx->lmac[lmac].phyaddr = MII_PHY_ANY;
}
+ if (OF_getencprop(child, "phy-handle", &phy,
+ sizeof(phy)) <= 0) {
+ if (bootverbose) {
+ device_printf(bgx->dev,
+ "No phy-handle in PHY node. Skipping...\n");
+ }
+ continue;
+ }
+ phy = OF_instance_to_package(phy);
/*
* Get PHY interface (MDIO bus) device.
* Driver must be already attached.
@@ -321,7 +321,7 @@ bgx_fdt_init_phy(struct bgx *bgx)
}
/* Get mac address from FDT */
- bgx_fdt_get_macaddr(phy, bgx->lmac[lmac].mac);
+ bgx_fdt_get_macaddr(child, bgx->lmac[lmac].mac);
bgx->lmac[lmac].lmacid = lmac;
lmac++;
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 4661f35..62c9bf3 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -1214,7 +1214,6 @@ vga_init(struct vt_device *vd)
if (vd->vd_softc == NULL)
vd->vd_softc = (void *)&vga_conssoftc;
sc = vd->vd_softc;
- textmode = 0;
if (vd->vd_flags & VDF_DOWNGRADE && vd->vd_video_dev != NULL)
vga_pci_repost(vd->vd_video_dev);
@@ -1229,6 +1228,13 @@ vga_init(struct vt_device *vd)
bus_space_map(sc->vga_reg_tag, VGA_REG_BASE, VGA_REG_SIZE, 0,
&sc->vga_reg_handle);
+ /*
+ * If "hw.vga.textmode" is not set and we're running on hypervisor,
+ * we use text mode by default, this is because when we're on
+ * hypervisor, vt(4) is usually much slower in graphics mode than
+ * in text mode, especially when we're on Hyper-V.
+ */
+ textmode = vm_guest != VM_GUEST_NO;
TUNABLE_INT_FETCH("hw.vga.textmode", &textmode);
if (textmode) {
vd->vd_flags |= VDF_TEXTMODE;
diff --git a/sys/dev/vxge/vxge.c b/sys/dev/vxge/vxge.c
index 9a3cab6..84320f6 100644
--- a/sys/dev/vxge/vxge.c
+++ b/sys/dev/vxge/vxge.c
@@ -996,7 +996,6 @@ vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
vxge_dev_t *vdev = vpath->vdev;
- struct lro_entry *queued = NULL;
struct lro_ctrl *lro = &vpath->lro;
/* get the interface pointer */
@@ -1083,12 +1082,8 @@ vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
&dtr_priv, &t_code) == VXGE_HAL_OK);
/* Flush any outstanding LRO work */
- if (vpath->lro_enable && vpath->lro.lro_cnt) {
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
- }
+ if (vpath->lro_enable && vpath->lro.lro_cnt)
+ tcp_lro_flush_all(lro);
return (status);
}
diff --git a/sys/dev/wbwd/wbwd.c b/sys/dev/wbwd/wbwd.c
index 484b5bf..53e9084 100644
--- a/sys/dev/wbwd/wbwd.c
+++ b/sys/dev/wbwd/wbwd.c
@@ -91,8 +91,11 @@ __FBSDID("$FreeBSD$");
#define WB_LDN8_CRF7_FORCE 0x20 /* 1: force timeout (self-clear) */
#define WB_LDN8_CRF7_TS 0x10 /* 0: counting, 1: fired */
#define WB_LDN8_CRF7_IRQS 0x0f /* irq source for watchdog, 2 == SMI */
-#define WB_LDN8_CRF7_CLEAR_MASK \
- (WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_KEYB|WB_LDN8_CRF7_TS|WB_LDN8_CRF7_IRQS)
+
+enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
+ w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg,
+ w83627dhg_p, w83667hg_b, nct6775, nct6776, nct6779, nct6791,
+ nct6792, nct6102 };
struct wb_softc {
device_t dev;
@@ -103,6 +106,10 @@ struct wb_softc {
eventhandler_tag ev_tag;
int (*ext_cfg_enter_f)(struct wb_softc *, u_short);
void (*ext_cfg_exit_f)(struct wb_softc *, u_short);
+ enum chips chip;
+ uint8_t ctl_reg;
+ uint8_t time_reg;
+ uint8_t csr_reg;
int debug_verbose;
/*
@@ -144,46 +151,104 @@ struct winbond_superio_cfg {
};
struct winbond_vendor_device_id {
- uint16_t vendor_id;
uint8_t device_id;
- uint8_t device_rev;
+ enum chips chip;
const char * descr;
} wb_devs[] = {
{
- .vendor_id = 0x5ca3,
.device_id = 0x52,
- .device_rev = 0x17,
- .descr = "Winbond 83627HF/F/HG/G Rev. G",
+ .chip = w83627hf,
+ .descr = "Winbond 83627HF/F/HG/G",
},
{
- .vendor_id = 0x5ca3,
- .device_id = 0x52,
- .device_rev = 0x3a,
- .descr = "Winbond 83627HF/F/HG/G Rev. J",
+ .device_id = 0x59,
+ .chip = w83627s,
+ .descr = "Winbond 83627S",
},
{
- .vendor_id = 0x5ca3,
- .device_id = 0x52,
- .device_rev = 0x41,
- .descr = "Winbond 83627HF/F/HG/G Rev. UD-A",
+ .device_id = 0x60,
+ .chip = w83697hf,
+ .descr = "Winbond 83697HF",
+ },
+ {
+ .device_id = 0x68,
+ .chip = w83697ug,
+ .descr = "Winbond 83697UG",
+ },
+ {
+ .device_id = 0x70,
+ .chip = w83637hf,
+ .descr = "Winbond 83637HF",
+ },
+ {
+ .device_id = 0x82,
+ .chip = w83627thf,
+ .descr = "Winbond 83627THF",
+ },
+ {
+ .device_id = 0x85,
+ .chip = w83687thf,
+ .descr = "Winbond 83687THF",
+ },
+ {
+ .device_id = 0x88,
+ .chip = w83627ehf,
+ .descr = "Winbond 83627EHF",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xa0,
- .device_rev = 0x25,
- .descr = "Winbond 83627DHG IC ver. 5",
+ .chip = w83627dhg,
+ .descr = "Winbond 83627DHG",
+ },
+ {
+ .device_id = 0xa2,
+ .chip = w83627uhg,
+ .descr = "Winbond 83627UHG",
+ },
+ {
+ .device_id = 0xa5,
+ .chip = w83667hg,
+ .descr = "Winbond 83667HG",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xb0,
- .device_rev = 0x73,
- .descr = "Winbond 83627DHG-P",
+ .chip = w83627dhg_p,
+ .descr = "Winbond 83627DHG-P",
+ },
+ {
+ .device_id = 0xb3,
+ .chip = w83667hg_b,
+ .descr = "Winbond 83667HG-B",
+ },
+ {
+ .device_id = 0xb4,
+ .chip = nct6775,
+ .descr = "Nuvoton NCT6775",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xc3,
- .device_rev = 0x33,
- .descr = "Nuvoton WPCM450RA0BX",
+ .chip = nct6776,
+ .descr = "Nuvoton NCT6776",
+ },
+ {
+ .device_id = 0xc4,
+ .chip = nct6102,
+ .descr = "Nuvoton NCT6102",
+ },
+ {
+ .device_id = 0xc5,
+ .chip = nct6779,
+ .descr = "Nuvoton NCT6779",
+ },
+ {
+ .device_id = 0xc8,
+ .chip = nct6791,
+ .descr = "Nuvoton NCT6791",
+ },
+ {
+ .device_id = 0xc9,
+ .chip = nct6792,
+ .descr = "Nuvoton NCT6792",
},
};
@@ -231,6 +296,22 @@ read_efdr_1(struct wb_softc *sc, u_short baseport)
return (inb(baseport + 1));
}
+static void
+write_reg(struct wb_softc *sc, uint8_t reg, uint8_t value)
+{
+
+ write_efir_1(sc, 0, reg);
+ write_efdr_1(sc, 0, value);
+}
+
+static uint8_t
+read_reg(struct wb_softc *sc, uint8_t reg)
+{
+
+ write_efir_1(sc, 0, reg);
+ return (read_efdr_1(sc, 0));
+}
+
/*
* Return the watchdog related registers as we last read them. This will
* usually not give the current timeout or state on whether the watchdog
@@ -248,9 +329,9 @@ sysctl_wb_debug(SYSCTL_HANDLER_ARGS)
sbuf_new_for_sysctl(&sb, NULL, 64, req);
sbuf_printf(&sb, "LDN8 (GPIO2, Watchdog): ");
- sbuf_printf(&sb, "CRF5 0x%02x ", sc->reg_1);
- sbuf_printf(&sb, "CRF6 0x%02x ", sc->reg_timeout);
- sbuf_printf(&sb, "CRF7 0x%02x", sc->reg_2);
+ sbuf_printf(&sb, "CR%02X 0x%02x ", sc->ctl_reg, sc->reg_1);
+ sbuf_printf(&sb, "CR%02X 0x%02x ", sc->time_reg, sc->reg_timeout);
+ sbuf_printf(&sb, "CR%02X 0x%02x", sc->csr_reg, sc->reg_2);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
@@ -269,23 +350,17 @@ sysctl_wb_debug_current(SYSCTL_HANDLER_ARGS)
sc = arg1;
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
+
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ (*sc->ext_cfg_exit_f)(sc, 0);
return (sysctl_wb_debug(oidp, arg1, arg2, req));
}
@@ -326,10 +401,6 @@ sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
}
#endif
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
@@ -343,16 +414,14 @@ sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
#endif
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
/* Force watchdog to fire. */
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
sc->reg_2 |= WB_LDN8_CRF7_FORCE;
+ write_reg(sc, sc->csr_reg, sc->reg_2);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ (*sc->ext_cfg_exit_f)(sc, 0);
return (0);
}
@@ -414,30 +483,36 @@ static int
wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
{
+ if (timeout != 0) {
+ /*
+ * In case an override is set, let it override. It may lead
+ * to strange results as we do not check the input of the sysctl.
+ */
+ if (sc->timeout_override > 0)
+ timeout = sc->timeout_override;
+
+ /* Make sure we support the requested timeout. */
+ if (timeout > 255 * 60)
+ return (EINVAL);
+ }
+
if (sc->debug_verbose)
wb_print_state(sc, "Before watchdog counter (re)load");
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog) */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
/* Disable and validate or arm/reset watchdog. */
if (timeout == 0) {
/* Disable watchdog. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- write_efdr_1(sc, 0, 0x00);
+ write_reg(sc, sc->time_reg, 0x00);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ (*sc->ext_cfg_exit_f)(sc, 0);
/* Re-check. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
-
if (sc->reg_timeout != 0x00) {
device_printf(sc->dev, "Failed to disable watchdog: "
"0x%02x.\n", sc->reg_timeout);
@@ -445,20 +520,8 @@ wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
}
} else {
- /*
- * In case an override is set, let it override. It may lead
- * to strange results as we do not check the input of the sysctl.
- */
- if (sc->timeout_override > 0)
- timeout = sc->timeout_override;
-
- /* Make sure we support the requested timeout. */
- if (timeout > 255 * 60)
- return (EINVAL);
-
/* Read current scaling factor. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
if (timeout > 255) {
/* Set scaling factor to 60s. */
@@ -473,21 +536,18 @@ wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
}
/* In case we fired before we need to clear to fire again. */
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
if (sc->reg_2 & WB_LDN8_CRF7_TS) {
sc->reg_2 &= ~WB_LDN8_CRF7_TS;
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ write_reg(sc, sc->csr_reg, sc->reg_2);
}
/* Write back scaling factor. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- write_efdr_1(sc, 0, sc->reg_1);
+ write_reg(sc, sc->ctl_reg, sc->reg_1);
/* Set timer and arm/reset the watchdog. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- write_efdr_1(sc, 0, sc->reg_timeout);
+ write_reg(sc, sc->time_reg, sc->reg_timeout);
+ (*sc->ext_cfg_exit_f)(sc, 0);
}
if (sc->debug_verbose)
@@ -556,6 +616,7 @@ wb_probe_enable(device_t dev, int probe)
struct wb_softc *sc;
int error, found, i, j;
uint8_t dev_id, dev_rev, cr26;
+ char buf[128];
if (dev == NULL)
sc = NULL;
@@ -566,6 +627,7 @@ wb_probe_enable(device_t dev, int probe)
}
error = ENXIO;
+ found = 0;
for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) {
if (sc != NULL) {
@@ -578,7 +640,6 @@ wb_probe_enable(device_t dev, int probe)
sc->bsh = rman_get_bushandle(sc->portres);
}
- found = 0;
error = (*probe_addrs[i].ext_cfg_enter_f)(sc, probe_addrs[i].efer);
if (error != 0)
goto cleanup;
@@ -591,6 +652,9 @@ wb_probe_enable(device_t dev, int probe)
write_efir_1(sc, probe_addrs[i].efer, WB_CR26);
cr26 = read_efdr_1(sc, probe_addrs[i].efer);
+ if (dev_id == 0xff && dev_rev == 0xff)
+ goto cleanup;
+
/* HEFRAS of 0 means EFER at 0x2e, 1 means EFER at 0x4e. */
if (((cr26 & 0x40) == 0x00 && probe_addrs[i].efer != 0x2e) ||
((cr26 & 0x40) == 0x40 && probe_addrs[i].efer != 0x4e)) {
@@ -602,36 +666,30 @@ wb_probe_enable(device_t dev, int probe)
goto cleanup;
}
- if (dev_id == 0xff && dev_rev == 0xff)
- goto cleanup;
-
for (j = 0; j < sizeof(wb_devs) / sizeof(*wb_devs); j++) {
- if (wb_devs[j].device_id == dev_id &&
- wb_devs[j].device_rev == dev_rev) {
- if (probe && dev != NULL)
- device_set_desc(dev, wb_devs[j].descr);
- found++;
+ if (wb_devs[j].device_id == dev_id) {
+ found = 1;
break;
}
}
- if (!found) {
- if (probe && dev != NULL) {
- device_set_desc(dev, "Unknown Winbond/Nuvoton model");
- device_printf(dev, "DevID 0x%02x DevRev 0x%02x, "
- "please report this.\n", dev_id, dev_rev);
- }
- found++;
+ if (probe && dev != NULL) {
+ snprintf(buf, sizeof(buf),
+ "%s (0x%02x/0x%02x) Watchdog Timer",
+ found ? wb_devs[j].descr :
+ "Unknown Winbond/Nuvoton", dev_id, dev_rev);
+ device_set_desc_copy(dev, buf);
+ }
+
+ /* If this is hinted attach, try to guess the model. */
+ if (dev != NULL && !found) {
+ found = 1;
+ j = 0;
}
- if (probe && found && bootverbose && dev != NULL)
- device_printf(dev, "%s EFER 0x%02x ID 0x%02x Rev 0x%02x"
- " CR26 0x%02x (probing)\n", device_get_desc(dev),
- probe_addrs[i].efer, dev_id, dev_rev, cr26);
cleanup:
if (probe || !found) {
(*probe_addrs[i].ext_cfg_exit_f)(sc, probe_addrs[i].efer);
-
if (sc != NULL)
(void) bus_release_resource(dev, SYS_RES_IOPORT,
sc->rid, sc->portres);
@@ -646,9 +704,21 @@ cleanup:
if (sc != NULL) {
sc->ext_cfg_enter_f = probe_addrs[i].ext_cfg_enter_f;
sc->ext_cfg_exit_f = probe_addrs[i].ext_cfg_exit_f;
+ sc->chip = wb_devs[j].chip;
+ sc->ctl_reg = 0xf5;
+ sc->time_reg = 0xf6;
+ sc->csr_reg = 0xf7;
+ if (sc->chip == w83697hf ||
+ sc->chip == w83697ug) {
+ sc->ctl_reg = 0xf3;
+ sc->time_reg = 0xf4;
+ } else if (sc->chip == nct6102) {
+ sc->ctl_reg = 0xf0;
+ sc->time_reg = 0xf1;
+ sc->csr_reg = 0xf2;
+ }
}
- error = BUS_PROBE_DEFAULT;
- break;
+ return (BUS_PROBE_SPECIFIC);
} else
error = ENXIO;
}
@@ -659,15 +729,10 @@ cleanup:
static void
wb_identify(driver_t *driver, device_t parent)
{
- device_t dev;
- if ((dev = device_find_child(parent, driver->name, 0)) == NULL) {
- if (wb_probe_enable(dev, 1) != BUS_PROBE_DEFAULT) {
- if (bootverbose)
- device_printf(dev, "can not find compatible Winbond chip.\n");
- } else
- dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);
- return;
+ if (device_find_child(parent, driver->name, 0) == NULL) {
+ if (wb_probe_enable(NULL, 1) <= 0)
+ BUS_ADD_CHILD(parent, 0, driver->name, 0);
}
}
@@ -690,6 +755,7 @@ wb_attach(device_t dev)
struct sysctl_oid *soid;
unsigned long timeout;
int error;
+ uint8_t t;
error = wb_probe_enable(dev, 0);
if (error > 0)
@@ -700,37 +766,95 @@ wb_attach(device_t dev)
("%s: successfull probe result but not setup correctly", __func__));
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
-
- /* Make sure LDN8 is enabled (Do we need to? Also affects GPIO). */
- write_efir_1(sc, 0, WB_LDN8_CR30);
- write_efdr_1(sc, 0, WB_LDN8_CR30_ACTIVE);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
+
+ /* Make sure WDT is enabled. */
+ write_reg(sc, WB_LDN8_CR30,
+ read_reg(sc, WB_LDN8_CR30) | WB_LDN8_CR30_ACTIVE);
+
+ switch (sc->chip) {
+ case w83627hf:
+ case w83627s:
+ t = read_reg(sc, 0x2B) & ~0x10;
+ write_reg(sc, 0x2B, t); /* set GPIO24 to WDT0 */
+ break;
+ case w83697hf:
+ /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
+ t = read_reg(sc, 0x29) & ~0x60;
+ t |= 0x20;
+ write_reg(sc, 0x29, t);
+ break;
+ case w83697ug:
+ /* Set pin 118 to WDTO# mode */
+ t = read_reg(sc, 0x2b) & ~0x04;
+ write_reg(sc, 0x2b, t);
+ break;
+ case w83627thf:
+ t = (read_reg(sc, 0x2B) & ~0x08) | 0x04;
+ write_reg(sc, 0x2B, t); /* set GPIO3 to WDT0 */
+ break;
+ case w83627dhg:
+ case w83627dhg_p:
+ t = read_reg(sc, 0x2D) & ~0x01; /* PIN77 -> WDT0# */
+ write_reg(sc, 0x2D, t); /* set GPIO5 to WDT0 */
+ t = read_reg(sc, sc->ctl_reg);
+ t |= 0x02; /* enable the WDTO# output low pulse
+ * to the KBRST# pin */
+ write_reg(sc, sc->ctl_reg, t);
+ break;
+ case w83637hf:
+ break;
+ case w83687thf:
+ t = read_reg(sc, 0x2C) & ~0x80; /* PIN47 -> WDT0# */
+ write_reg(sc, 0x2C, t);
+ break;
+ case w83627ehf:
+ case w83627uhg:
+ case w83667hg:
+ case w83667hg_b:
+ case nct6775:
+ case nct6776:
+ case nct6779:
+ case nct6791:
+ case nct6792:
+ case nct6102:
+ /*
+ * These chips have a fixed WDTO# output pin (W83627UHG),
+ * or support more than one WDTO# output pin.
+ * Don't touch its configuration, and hope the BIOS
+ * does the right thing.
+ */
+ t = read_reg(sc, sc->ctl_reg);
+ t |= 0x02; /* enable the WDTO# output low pulse
+ * to the KBRST# pin */
+ write_reg(sc, sc->ctl_reg, t);
+ break;
+ default:
+ break;
+ }
/* Read the current watchdog configuration. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
/* Print current state if bootverbose or watchdog already enabled. */
if (bootverbose || (sc->reg_timeout > 0x00))
wb_print_state(sc, "Before watchdog attach");
+ sc->reg_1 &= ~WB_LDN8_CRF5_KEYB_P20;
+ sc->reg_1 |= WB_LDN8_CRF5_KBRST;
+ write_reg(sc, sc->ctl_reg, sc->reg_1);
+
/*
- * Clear a previous watchdog timeout event (if (still) set).
- * Disable all all interrupt reset sources (defaults).
+ * Clear a previous watchdog timeout event (if still set).
+ * Disable timer reset on mouse interrupts. Leave reset on keyboard,
+ * since one of my boards is getting stuck in reboot without it.
*/
- sc->reg_1 &= ~(WB_LDN8_CRF5_KEYB_P20);
- sc->reg_1 |= WB_LDN8_CRF5_KBRST;
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- write_efdr_1(sc, 0, sc->reg_1);
+ sc->reg_2 &= ~(WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_TS);
+ write_reg(sc, sc->csr_reg, sc->reg_2);
- sc->reg_2 &= ~WB_LDN8_CRF7_CLEAR_MASK;
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ (*sc->ext_cfg_exit_f)(sc, 0);
/* Read global timeout override tunable, Add per device sysctls. */
if (TUNABLE_ULONG_FETCH("hw.wbwd.timeout_override", &timeout)) {
diff --git a/sys/dev/wl/if_wl.c b/sys/dev/wl/if_wl.c
index 7146a25..6414d33 100644
--- a/sys/dev/wl/if_wl.c
+++ b/sys/dev/wl/if_wl.c
@@ -495,7 +495,7 @@ wlattach(device_t device)
}
#ifdef WLDEBUG
- printf("wlattach: base %lx, unit %d\n", rman_get_start(sc->res_ioport),
+ printf("wlattach: base %jx, unit %d\n", rman_get_start(sc->res_ioport),
device_get_unit(device));
#endif
diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c
index 824f75b..e435096 100644
--- a/sys/dev/wpi/if_wpi.c
+++ b/sys/dev/wpi/if_wpi.c
@@ -284,7 +284,6 @@ static void wpi_scan_end(struct ieee80211com *);
static void wpi_set_channel(struct ieee80211com *);
static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long);
static void wpi_scan_mindwell(struct ieee80211_scan_state *);
-static void wpi_hw_reset(void *, int);
static device_method_t wpi_methods[] = {
/* Device interface */
@@ -531,18 +530,9 @@ wpi_attach(device_t dev)
callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0);
callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0);
callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0);
- TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc);
TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc);
TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc);
- sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK,
- taskqueue_thread_enqueue, &sc->sc_tq);
- error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq");
- if (error != 0) {
- device_printf(dev, "can't start threads, error %d\n", error);
- goto fail;
- }
-
wpi_sysctlattach(sc);
/*
@@ -695,14 +685,10 @@ wpi_detach(device_t dev)
if (ic->ic_vap_create == wpi_vap_create) {
ieee80211_draintask(ic, &sc->sc_radioon_task);
+ ieee80211_draintask(ic, &sc->sc_radiooff_task);
wpi_stop(sc);
- if (sc->sc_tq != NULL) {
- taskqueue_drain_all(sc->sc_tq);
- taskqueue_free(sc->sc_tq);
- }
-
callout_drain(&sc->watchdog_rfkill);
callout_drain(&sc->tx_timeout);
callout_drain(&sc->scan_timeout);
@@ -1517,7 +1503,8 @@ wpi_find_eeprom_channel(struct wpi_softc *sc, struct ieee80211_channel *c)
for (j = 0; j < WPI_CHAN_BANDS_COUNT; j++)
for (i = 0; i < wpi_bands[j].nchan; i++)
- if (wpi_bands[j].chan[i] == c->ic_ieee)
+ if (wpi_bands[j].chan[i] == c->ic_ieee &&
+ ((j == 0) ^ IEEE80211_IS_CHAN_A(c)) == 1)
return &sc->eeprom_channels[j][i];
return NULL;
@@ -2332,7 +2319,7 @@ wpi_notif_intr(struct wpi_softc *sc)
WPI_NT_LOCK(sc);
wpi_clear_node_table(sc);
WPI_NT_UNLOCK(sc);
- taskqueue_enqueue(sc->sc_tq,
+ ieee80211_runtask(ic,
&sc->sc_radiooff_task);
return;
}
@@ -2569,6 +2556,8 @@ wpi_intr(void *arg)
WPI_WRITE(sc, WPI_FH_INT, r2);
if (__predict_false(r1 & (WPI_INT_SW_ERR | WPI_INT_HW_ERR))) {
+ struct ieee80211com *ic = &sc->sc_ic;
+
device_printf(sc->sc_dev, "fatal firmware error\n");
#ifdef WPI_DEBUG
wpi_debug_registers(sc);
@@ -2577,7 +2566,7 @@ wpi_intr(void *arg)
DPRINTF(sc, WPI_DEBUG_HW,
"(%s)\n", (r1 & WPI_INT_SW_ERR) ? "(Software Error)" :
"(Hardware Error)");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
goto end;
}
@@ -3200,7 +3189,7 @@ wpi_scan_timeout(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
ic_printf(ic, "scan timeout\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
}
static void
@@ -3210,7 +3199,7 @@ wpi_tx_timeout(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
ic_printf(ic, "device timeout\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
}
static void
@@ -3227,8 +3216,10 @@ wpi_parent(struct ieee80211com *ic)
ieee80211_notify_radio(ic, 0);
ieee80211_stop(vap);
}
- } else
+ } else {
+ ieee80211_notify_radio(ic, 0);
wpi_stop(sc);
+ }
}
/*
@@ -5654,23 +5645,3 @@ wpi_scan_mindwell(struct ieee80211_scan_state *ss)
{
/* NB: don't try to abort scan; wait for firmware to finish */
}
-
-static void
-wpi_hw_reset(void *arg, int pending)
-{
- struct wpi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-
- DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__);
-
- ieee80211_notify_radio(ic, 0);
- if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN))
- ieee80211_cancel_scan(vap);
-
- wpi_stop(sc);
- if (vap != NULL) {
- ieee80211_stop(vap);
- ieee80211_init(vap);
- }
-}
diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h
index 1957740..437f1d8 100644
--- a/sys/dev/wpi/if_wpivar.h
+++ b/sys/dev/wpi/if_wpivar.h
@@ -228,13 +228,9 @@ struct wpi_softc {
struct wpi_dma_info fw_dma;
/* Tasks used by the driver. */
- struct task sc_reinittask;
struct task sc_radiooff_task;
struct task sc_radioon_task;
- /* Taskqueue */
- struct taskqueue *sc_tq;
-
/* Eeprom info. */
uint8_t cap;
uint16_t rev;
diff --git a/sys/dev/xe/if_xe.c b/sys/dev/xe/if_xe.c
index d6ccae9..e18af8c 100644
--- a/sys/dev/xe/if_xe.c
+++ b/sys/dev/xe/if_xe.c
@@ -1984,7 +1984,7 @@ xe_activate(device_t dev)
sc->port_res);
start = (rman_get_start(sc->port_res) + 15) & ~0xf;
} while (1);
- DEVPRINTF(1, (dev, "RealPort port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "RealPort port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
} else if (sc->ce2) {
@@ -2024,7 +2024,7 @@ xe_activate(device_t dev)
sc->port_res);
sc->port_res = NULL;
}
- DEVPRINTF(1, (dev, "CEM2/CEM3 port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "CEM2/CEM3 port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
}
diff --git a/sys/dev/xe/if_xe_pccard.c b/sys/dev/xe/if_xe_pccard.c
index bbe6253..fb2cff6 100644
--- a/sys/dev/xe/if_xe_pccard.c
+++ b/sys/dev/xe/if_xe_pccard.c
@@ -140,7 +140,7 @@ xe_cemfix(device_t dev)
DEVPRINTF(2, (dev, "cemfix\n"));
- DEVPRINTF(1, (dev, "CEM I/O port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "CEM I/O port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
diff --git a/sys/dev/xen/blkfront/blkfront.c b/sys/dev/xen/blkfront/blkfront.c
index d35e04a..ef36b94 100644
--- a/sys/dev/xen/blkfront/blkfront.c
+++ b/sys/dev/xen/blkfront/blkfront.c
@@ -855,6 +855,20 @@ xbd_feature_string(struct xbd_softc *sc, char *features, size_t len)
feature_cnt++;
}
+ if ((sc->xbd_flags & XBDF_DISCARD) != 0) {
+ if (feature_cnt != 0)
+ sbuf_printf(&sb, ", ");
+ sbuf_printf(&sb, "discard");
+ feature_cnt++;
+ }
+
+ if ((sc->xbd_flags & XBDF_PERSISTENT) != 0) {
+ if (feature_cnt != 0)
+ sbuf_printf(&sb, ", ");
+ sbuf_printf(&sb, "persistent_grants");
+ feature_cnt++;
+ }
+
(void) sbuf_finish(&sb);
return (sbuf_len(&sb));
}
@@ -985,7 +999,8 @@ xbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name)
int
xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
- int vdevice, uint16_t vdisk_info, unsigned long sector_size)
+ int vdevice, uint16_t vdisk_info, unsigned long sector_size,
+ unsigned long phys_sector_size)
{
char features[80];
int unit, error = 0;
@@ -1013,6 +1028,8 @@ xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
sc->xbd_disk->d_name = name;
sc->xbd_disk->d_drv1 = sc;
sc->xbd_disk->d_sectorsize = sector_size;
+ sc->xbd_disk->d_stripesize = phys_sector_size;
+ sc->xbd_disk->d_stripeoffset = 0;
sc->xbd_disk->d_mediasize = sectors * sector_size;
sc->xbd_disk->d_maxsize = sc->xbd_max_request_size;
@@ -1206,7 +1223,7 @@ static void
xbd_connect(struct xbd_softc *sc)
{
device_t dev = sc->xbd_dev;
- unsigned long sectors, sector_size;
+ unsigned long sectors, sector_size, phys_sector_size;
unsigned int binfo;
int err, feature_barrier, feature_flush;
int i, j;
@@ -1229,6 +1246,11 @@ xbd_connect(struct xbd_softc *sc)
return;
}
err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
+ "physical-sector-size", "%lu", &phys_sector_size,
+ NULL);
+ if (err || phys_sector_size <= sector_size)
+ phys_sector_size = 0;
+ err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
"feature-barrier", "%lu", &feature_barrier,
NULL);
if (err == 0 && feature_barrier != 0)
@@ -1330,7 +1352,7 @@ xbd_connect(struct xbd_softc *sc)
bus_print_child_footer(device_get_parent(dev), dev);
xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo,
- sector_size);
+ sector_size, phys_sector_size);
}
(void)xenbus_set_state(dev, XenbusStateConnected);
diff --git a/sys/dev/xen/blkfront/block.h b/sys/dev/xen/blkfront/block.h
index 28c6ff2..ddb4088 100644
--- a/sys/dev/xen/blkfront/block.h
+++ b/sys/dev/xen/blkfront/block.h
@@ -159,10 +159,12 @@ typedef enum {
XBDF_READY = 1 << 3, /* Is ready */
XBDF_CM_SHORTAGE = 1 << 4, /* Free cm resource shortage active. */
XBDF_GNT_SHORTAGE = 1 << 5, /* Grant ref resource shortage active */
- XBDF_WAIT_IDLE = 1 << 6 /*
+ XBDF_WAIT_IDLE = 1 << 6, /*
* No new work until oustanding work
* completes.
*/
+ XBDF_DISCARD = 1 << 7, /* backend supports discard */
+ XBDF_PERSISTENT = 1 << 8 /* backend supports persistent grants */
} xbd_flag_t;
/*
@@ -200,7 +202,8 @@ struct xbd_softc {
};
int xbd_instance_create(struct xbd_softc *, blkif_sector_t sectors, int device,
- uint16_t vdisk_info, unsigned long sector_size);
+ uint16_t vdisk_info, unsigned long sector_size,
+ unsigned long phys_sector_size);
static inline void
xbd_added_qentry(struct xbd_softc *sc, xbd_q_index_t index)
diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c
index 22ca81c..7add70a 100644
--- a/sys/dev/xen/netfront/netfront.c
+++ b/sys/dev/xen/netfront/netfront.c
@@ -1202,7 +1202,6 @@ xn_rxeof(struct netfront_rxq *rxq)
struct netfront_info *np = rxq->info;
#if (defined(INET) || defined(INET6))
struct lro_ctrl *lro = &rxq->lro;
- struct lro_entry *queued;
#endif
struct netfront_rx_info rinfo;
struct netif_rx_response *rx = &rinfo.rx;
@@ -1296,11 +1295,7 @@ xn_rxeof(struct netfront_rxq *rxq)
/*
* Flush any outstanding LRO work
*/
- while (!SLIST_EMPTY(&lro->lro_active)) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
#endif
xn_alloc_rx_buffers(rxq);
diff --git a/sys/fs/autofs/autofs.c b/sys/fs/autofs/autofs.c
index c4b1ec3..eee74ea 100644
--- a/sys/fs/autofs/autofs.c
+++ b/sys/fs/autofs/autofs.c
@@ -77,6 +77,7 @@
#include <sys/sysctl.h>
#include <sys/syscallsubr.h>
#include <sys/taskqueue.h>
+#include <sys/tree.h>
#include <sys/vnode.h>
#include <machine/atomic.h>
#include <vm/uma.h>
@@ -149,6 +150,15 @@ TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible);
SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN,
&autofs_interruptible, 1, "Allow requests to be interrupted by signal");
+static int
+autofs_node_cmp(const struct autofs_node *a, const struct autofs_node *b)
+{
+
+ return (strcmp(a->an_name, b->an_name));
+}
+
+RB_GENERATE(autofs_node_tree, autofs_node, an_link, autofs_node_cmp);
+
int
autofs_init(struct vfsconf *vfsp)
{
diff --git a/sys/fs/autofs/autofs.h b/sys/fs/autofs/autofs.h
index 27e380b..bab2282 100644
--- a/sys/fs/autofs/autofs.h
+++ b/sys/fs/autofs/autofs.h
@@ -65,11 +65,12 @@ extern int autofs_mount_on_stat;
#define AUTOFS_ASSERT_UNLOCKED(X) sx_assert(&X->am_lock, SA_UNLOCKED)
struct autofs_node {
- TAILQ_ENTRY(autofs_node) an_next;
+ RB_ENTRY(autofs_node) an_link;
char *an_name;
int an_fileno;
struct autofs_node *an_parent;
- TAILQ_HEAD(, autofs_node) an_children;
+ RB_HEAD(autofs_node_tree,
+ autofs_node) an_children;
struct autofs_mount *an_mount;
struct vnode *an_vnode;
struct sx an_vnode_lock;
@@ -136,4 +137,6 @@ void autofs_node_delete(struct autofs_node *anp);
int autofs_node_vn(struct autofs_node *anp, struct mount *mp,
int flags, struct vnode **vpp);
+RB_PROTOTYPE(autofs_node_tree, autofs_node, an_link, autofs_node_cmp);
+
#endif /* !AUTOFS_H */
diff --git a/sys/fs/autofs/autofs_vfsops.c b/sys/fs/autofs/autofs_vfsops.c
index 722ff24..b427a7f 100644
--- a/sys/fs/autofs/autofs_vfsops.c
+++ b/sys/fs/autofs/autofs_vfsops.c
@@ -42,6 +42,7 @@
#include <sys/stat.h>
#include <sys/sx.h>
#include <sys/taskqueue.h>
+#include <sys/tree.h>
#include <sys/vnode.h>
#include <fs/autofs/autofs.h>
@@ -158,10 +159,10 @@ autofs_unmount(struct mount *mp, int mntflags)
/*
* Not terribly efficient, but at least not recursive.
*/
- while (!TAILQ_EMPTY(&amp->am_root->an_children)) {
- anp = TAILQ_FIRST(&amp->am_root->an_children);
- while (!TAILQ_EMPTY(&anp->an_children))
- anp = TAILQ_FIRST(&anp->an_children);
+ while (!RB_EMPTY(&amp->am_root->an_children)) {
+ anp = RB_MIN(autofs_node_tree, &amp->am_root->an_children);
+ while (!RB_EMPTY(&anp->an_children))
+ anp = RB_MIN(autofs_node_tree, &anp->an_children);
autofs_node_delete(anp);
}
autofs_node_delete(amp->am_root);
diff --git a/sys/fs/autofs/autofs_vnops.c b/sys/fs/autofs/autofs_vnops.c
index 515d228..0ab6ec1 100644
--- a/sys/fs/autofs/autofs_vnops.c
+++ b/sys/fs/autofs/autofs_vnops.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
+#include <sys/tree.h>
#include <sys/vnode.h>
#include <machine/atomic.h>
#include <vm/uma.h>
@@ -371,7 +372,7 @@ autofs_dirent_reclen(const char *name)
{
size_t reclen;
- autofs_readdir_one(NULL, name, -1, &reclen);
+ (void)autofs_readdir_one(NULL, name, -1, &reclen);
return (reclen);
}
@@ -450,7 +451,7 @@ autofs_readdir(struct vop_readdir_args *ap)
* Write out the directory entries for subdirectories.
*/
AUTOFS_SLOCK(amp);
- TAILQ_FOREACH(child, &anp->an_children, an_next) {
+ RB_FOREACH(child, autofs_node_tree, &anp->an_children) {
/*
* Check the offset to skip entries returned by previous
* calls to getdents().
@@ -575,8 +576,8 @@ autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp,
anp->an_parent = parent;
anp->an_mount = amp;
if (parent != NULL)
- TAILQ_INSERT_TAIL(&parent->an_children, anp, an_next);
- TAILQ_INIT(&anp->an_children);
+ RB_INSERT(autofs_node_tree, &parent->an_children, anp);
+ RB_INIT(&anp->an_children);
*anpp = anp;
return (0);
@@ -586,27 +587,28 @@ int
autofs_node_find(struct autofs_node *parent, const char *name,
int namelen, struct autofs_node **anpp)
{
- struct autofs_node *anp;
+ struct autofs_node *anp, find;
+ int error;
AUTOFS_ASSERT_LOCKED(parent->an_mount);
- TAILQ_FOREACH(anp, &parent->an_children, an_next) {
- if (namelen >= 0) {
- if (strlen(anp->an_name) != namelen)
- continue;
- if (strncmp(anp->an_name, name, namelen) != 0)
- continue;
- } else {
- if (strcmp(anp->an_name, name) != 0)
- continue;
- }
+ if (namelen >= 0)
+ find.an_name = strndup(name, namelen, M_AUTOFS);
+ else
+ find.an_name = strdup(name, M_AUTOFS);
+ anp = RB_FIND(autofs_node_tree, &parent->an_children, &find);
+ if (anp != NULL) {
+ error = 0;
if (anpp != NULL)
*anpp = anp;
- return (0);
+ } else {
+ error = ENOENT;
}
- return (ENOENT);
+ free(find.an_name, M_AUTOFS);
+
+ return (error);
}
void
@@ -615,13 +617,13 @@ autofs_node_delete(struct autofs_node *anp)
struct autofs_node *parent;
AUTOFS_ASSERT_XLOCKED(anp->an_mount);
- KASSERT(TAILQ_EMPTY(&anp->an_children), ("have children"));
+ KASSERT(RB_EMPTY(&anp->an_children), ("have children"));
callout_drain(&anp->an_callout);
parent = anp->an_parent;
if (parent != NULL)
- TAILQ_REMOVE(&parent->an_children, anp, an_next);
+ RB_REMOVE(autofs_node_tree, &parent->an_children, anp);
sx_destroy(&anp->an_vnode_lock);
free(anp->an_name, M_AUTOFS);
uma_zfree(autofs_node_zone, anp);
diff --git a/sys/fs/cd9660/cd9660_vnops.c b/sys/fs/cd9660/cd9660_vnops.c
index 47d4f75..cab8db7 100644
--- a/sys/fs/cd9660/cd9660_vnops.c
+++ b/sys/fs/cd9660/cd9660_vnops.c
@@ -341,11 +341,9 @@ cd9660_read(ap)
} else
error = bread(vp, lbn, size, NOCRED, &bp);
}
- n = MIN(n, size - bp->b_resid);
- if (error) {
- brelse(bp);
+ if (error != 0)
return (error);
- }
+ n = MIN(n, size - bp->b_resid);
error = uiomove(bp->b_data + on, (int)n, uio);
brelse(bp);
diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c
index 12067d2..9d5417c 100644
--- a/sys/fs/ext2fs/ext2_alloc.c
+++ b/sys/fs/ext2fs/ext2_alloc.c
@@ -406,10 +406,8 @@ ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp)
/*
* Set up a new generation number for this inode.
- * XXX check if this makes sense in ext2
*/
- if (ip->i_gen == 0 || ++ip->i_gen == 0)
- ip->i_gen = random() / 2 + 1;
+ ip->i_gen = arc4random();
vfs_timestamp(&ts);
ip->i_birthtime = ts.tv_sec;
diff --git a/sys/fs/ext2fs/ext2_dinode.h b/sys/fs/ext2fs/ext2_dinode.h
index 3f5ddef..a172a5b 100644
--- a/sys/fs/ext2fs/ext2_dinode.h
+++ b/sys/fs/ext2fs/ext2_dinode.h
@@ -131,6 +131,7 @@ struct ext2fs_dinode {
uint32_t e2di_crtime; /* 144: Creation (birth)time */
uint32_t e2di_crtime_extra; /* 148: Extra creation (birth)time */
uint32_t e2di_version_hi; /* 152: High bits of inode version */
+ uint32_t e2di_projid; /* 156: Project ID */
};
#endif /* !_FS_EXT2FS_EXT2_DINODE_H_ */
diff --git a/sys/fs/ext2fs/ext2fs.h b/sys/fs/ext2fs/ext2fs.h
index b8c4701..c23f2a2 100644
--- a/sys/fs/ext2fs/ext2fs.h
+++ b/sys/fs/ext2fs/ext2fs.h
@@ -72,7 +72,7 @@ struct ext2fs {
uint32_t e2fs_first_ino; /* first non-reserved inode */
uint16_t e2fs_inode_size; /* size of inode structure */
uint16_t e2fs_block_group_nr; /* block grp number of this sblk*/
- uint32_t e2fs_features_compat; /* compatible feature set */
+ uint32_t e2fs_features_compat; /* compatible feature set */
uint32_t e2fs_features_incompat; /* incompatible feature set */
uint32_t e2fs_features_rocompat; /* RO-compatible feature set */
uint8_t e2fs_uuid[16]; /* 128-bit uuid for volume */
@@ -88,25 +88,54 @@ struct ext2fs {
uint32_t e3fs_last_orphan; /* start of list of inodes to delete */
uint32_t e3fs_hash_seed[4]; /* HTREE hash seed */
char e3fs_def_hash_version; /* Default hash version to use */
- char e3fs_reserved_char_pad;
+ char e3fs_jnl_backup_type;
+ uint16_t e3fs_desc_size; /* size of group descriptor */
uint32_t e3fs_default_mount_opts;
uint32_t e3fs_first_meta_bg; /* First metablock block group */
- uint32_t e3fs_mkfs_time; /* when the fs was created */
- uint32_t e3fs_jnl_blks[17]; /* backup of the journal inode */
- uint32_t e4fs_bcount_hi; /* block count */
- uint32_t e4fs_rbcount_hi; /* reserved blocks count */
- uint32_t e4fs_fbcount_hi; /* free blocks count */
- uint16_t e4fs_min_extra_isize;/* all inodes have at least some bytes */
+ uint32_t e3fs_mkfs_time; /* when the fs was created */
+ uint32_t e3fs_jnl_blks[17]; /* backup of the journal inode */
+ uint32_t e4fs_bcount_hi; /* high bits of blocks count */
+ uint32_t e4fs_rbcount_hi; /* high bits of reserved blocks count */
+ uint32_t e4fs_fbcount_hi; /* high bits of free blocks count */
+ uint16_t e4fs_min_extra_isize; /* all inodes have at least some bytes */
uint16_t e4fs_want_extra_isize; /* inodes must reserve some bytes */
- uint32_t e4fs_flags; /* miscellaneous flags */
- uint16_t e4fs_raid_stride; /* RAID stride */
- uint16_t e4fs_mmpintv; /* number of seconds to wait in MMP checking */
- uint64_t e4fs_mmpblk; /* block for multi-mount protection */
- uint32_t e4fs_raid_stripe_wid;/* blocks on all data disks (N * stride) */
- uint8_t e4fs_log_gpf; /* FLEX_BG group size */
- uint8_t e4fs_char_pad2;
- uint16_t e4fs_pad;
- uint32_t reserved2[162]; /* Padding to the end of the block */
+ uint32_t e4fs_flags; /* miscellaneous flags */
+ uint16_t e4fs_raid_stride; /* RAID stride */
+ uint16_t e4fs_mmpintv; /* number of seconds to wait in MMP checking */
+ uint64_t e4fs_mmpblk; /* block for multi-mount protection */
+ uint32_t e4fs_raid_stripe_wid; /* blocks on all data disks (N * stride) */
+ uint8_t e4fs_log_gpf; /* FLEX_BG group size */
+ uint8_t e4fs_chksum_type; /* metadata checksum algorithm used */
+ uint8_t e4fs_encrypt; /* versioning level for encryption */
+ uint8_t e4fs_reserved_pad;
+ uint64_t e4fs_kbytes_written; /* number of lifetime kilobytes */
+ uint32_t e4fs_snapinum; /* inode number of active snapshot */
+ uint32_t e4fs_snapid; /* sequential ID of active snapshot */
+ uint64_t e4fs_snaprbcount; /* reserved blocks for active snapshot */
+ uint32_t e4fs_snaplist; /* inode number for on-disk snapshot */
+ uint32_t e4fs_errcount; /* number of file system errors */
+ uint32_t e4fs_first_errtime; /* first time an error happened */
+ uint32_t e4fs_first_errino; /* inode involved in first error */
+ uint64_t e4fs_first_errblk; /* block involved of first error */
+ uint8_t e4fs_first_errfunc[32]; /* function where error happened */
+ uint32_t e4fs_first_errline; /* line number where error happened */
+ uint32_t e4fs_last_errtime; /* most recent time of an error */
+ uint32_t e4fs_last_errino; /* inode involved in last error */
+ uint32_t e4fs_last_errline; /* line number where error happened */
+ uint64_t e4fs_last_errblk; /* block involved of last error */
+ uint8_t e4fs_last_errfunc[32]; /* function where error happened */
+ uint8_t e4fs_mount_opts[64];
+ uint32_t e4fs_usrquota_inum; /* inode for tracking user quota */
+ uint32_t e4fs_grpquota_inum; /* inode for tracking group quota */
+ uint32_t e4fs_overhead_clusters; /* overhead blocks/clusters */
+ uint32_t e4fs_backup_bgs[2]; /* groups with sparse_super2 SBs */
+ uint8_t e4fs_encrypt_algos[4]; /* encryption algorithms in use */
+ uint8_t e4fs_encrypt_pw_salt[16]; /* salt used for string2key */
+ uint32_t e4fs_lpf_ino; /* location of the lost+found inode */
+ uint32_t e4fs_proj_quota_inum; /* inode for tracking project quota */
+ uint32_t e4fs_chksum_seed; /* checksum seed */
+ uint32_t e4fs_reserved[98]; /* padding to the end of the block */
+ uint32_t e4fs_sbchksum; /* superblock checksum */
};
/*
diff --git a/sys/geom/sched/g_sched.c b/sys/geom/sched/g_sched.c
index ea1fd41..d4e3ca0 100644
--- a/sys/geom/sched/g_sched.c
+++ b/sys/geom/sched/g_sched.c
@@ -1316,7 +1316,8 @@ g_sched_destroy(struct g_geom *gp, boolean_t force)
gsp->gs_fini(sc->sc_data);
g_gsched_unref(gsp);
sc->sc_gsched = NULL;
- }
+ } else
+ error = 0;
if ((sc->sc_flags & G_SCHED_PROXYING) && oldpp) {
error = g_destroy_proxy(gp, oldpp);
diff --git a/sys/i386/conf/GENERIC.hints b/sys/i386/conf/GENERIC.hints
index fb30240..ffd10a6 100644
--- a/sys/i386/conf/GENERIC.hints
+++ b/sys/i386/conf/GENERIC.hints
@@ -38,6 +38,5 @@ hint.atrtc.0.irq="8"
hint.attimer.0.at="isa"
hint.attimer.0.port="0x40"
hint.attimer.0.irq="0"
-hint.wbwd.0.at="isa"
hint.acpi_throttle.0.disabled="1"
hint.p4tcc.0.disabled="1"
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 62e99aa..fe6297a 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -127,8 +127,8 @@ get_pcb_user_save_td(struct thread *td)
vm_offset_t p;
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
- cpu_max_ext_state_size;
- KASSERT((p % 64) == 0, ("Unaligned pcb_user_save area"));
+ roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN);
+ KASSERT((p % XSAVE_AREA_ALIGN) == 0, ("Unaligned pcb_user_save area"));
return ((union savefpu *)p);
}
@@ -147,7 +147,8 @@ get_pcb_td(struct thread *td)
vm_offset_t p;
p = td->td_kstack + td->td_kstack_pages * PAGE_SIZE -
- cpu_max_ext_state_size - sizeof(struct pcb);
+ roundup2(cpu_max_ext_state_size, XSAVE_AREA_ALIGN) -
+ sizeof(struct pcb);
return ((struct pcb *)p);
}
diff --git a/sys/i386/include/intr_machdep.h b/sys/i386/include/intr_machdep.h
index 0a2a6d5..d1be076 100644
--- a/sys/i386/include/intr_machdep.h
+++ b/sys/i386/include/intr_machdep.h
@@ -83,7 +83,7 @@
#ifndef LOCORE
-typedef void inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
+typedef void inthand_t(void);
#define IDTVEC(name) __CONCAT(X,name)
diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h
index f854373..c4c9ca9 100644
--- a/sys/i386/include/md_var.h
+++ b/sys/i386/include/md_var.h
@@ -46,7 +46,6 @@ extern int szosigcode;
#endif
extern uint32_t *vm_page_dump;
-typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
struct segment_descriptor;
union savefpu;
diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c
index 4c0cad0..fd73c9d 100644
--- a/sys/i386/linux/linux_dummy.c
+++ b/sys/i386/linux/linux_dummy.c
@@ -71,7 +71,6 @@ DUMMY(pivot_root);
DUMMY(mincore);
DUMMY(lookup_dcookie);
DUMMY(remap_file_pages);
-DUMMY(fstatfs64);
DUMMY(mbind);
DUMMY(get_mempolicy);
DUMMY(set_mempolicy);
diff --git a/sys/i386/linux/linux_proto.h b/sys/i386/linux/linux_proto.h
index 884292f..7e260d8 100644
--- a/sys/i386/linux/linux_proto.h
+++ b/sys/i386/linux/linux_proto.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#ifndef _LINUX_SYSPROTO_H_
@@ -848,7 +848,9 @@ struct linux_statfs64_args {
char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)];
};
struct linux_fstatfs64_args {
- register_t dummy;
+ char fd_l_[PADL_(l_uint)]; l_uint fd; char fd_r_[PADR_(l_uint)];
+ char bufsize_l_[PADL_(size_t)]; size_t bufsize; char bufsize_r_[PADR_(size_t)];
+ char buf_l_[PADL_(struct l_statfs64_buf *)]; struct l_statfs64_buf * buf; char buf_r_[PADR_(struct l_statfs64_buf *)];
};
struct linux_tgkill_args {
char tgid_l_[PADL_(int)]; int tgid; char tgid_r_[PADR_(int)];
diff --git a/sys/i386/linux/linux_syscall.h b/sys/i386/linux/linux_syscall.h
index 1be670a..918f838 100644
--- a/sys/i386/linux/linux_syscall.h
+++ b/sys/i386/linux/linux_syscall.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#define LINUX_SYS_linux_exit 1
diff --git a/sys/i386/linux/linux_syscalls.c b/sys/i386/linux/linux_syscalls.c
index 68a81ef..4a5cd4c 100644
--- a/sys/i386/linux/linux_syscalls.c
+++ b/sys/i386/linux/linux_syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
const char *linux_syscallnames[] = {
diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c
index d853d1d..181141d 100644
--- a/sys/i386/linux/linux_sysent.c
+++ b/sys/i386/linux/linux_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/i386/linux/syscalls.master 293907 2016-01-14 10:13:58Z glebius
+ * created from FreeBSD: head/sys/i386/linux/syscalls.master 297061 2016-03-20 13:21:20Z dchagin
*/
#include <sys/param.h>
@@ -287,7 +287,7 @@ struct sysent linux_sysent[] = {
{ AS(linux_clock_getres_args), (sy_call_t *)linux_clock_getres, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 266 = linux_clock_getres */
{ AS(linux_clock_nanosleep_args), (sy_call_t *)linux_clock_nanosleep, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 267 = linux_clock_nanosleep */
{ AS(linux_statfs64_args), (sy_call_t *)linux_statfs64, AUE_STATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 268 = linux_statfs64 */
- { 0, (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */
+ { AS(linux_fstatfs64_args), (sy_call_t *)linux_fstatfs64, AUE_FSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 269 = linux_fstatfs64 */
{ AS(linux_tgkill_args), (sy_call_t *)linux_tgkill, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 270 = linux_tgkill */
{ AS(linux_utimes_args), (sy_call_t *)linux_utimes, AUE_UTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 271 = linux_utimes */
{ AS(linux_fadvise64_64_args), (sy_call_t *)linux_fadvise64_64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 272 = linux_fadvise64_64 */
diff --git a/sys/i386/linux/linux_systrace_args.c b/sys/i386/linux/linux_systrace_args.c
index 85fc9ca..7feba47 100644
--- a/sys/i386/linux/linux_systrace_args.c
+++ b/sys/i386/linux/linux_systrace_args.c
@@ -1870,7 +1870,11 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
}
/* linux_fstatfs64 */
case 269: {
- *n_args = 0;
+ struct linux_fstatfs64_args *p = params;
+ iarg[0] = p->fd; /* l_uint */
+ uarg[1] = p->bufsize; /* size_t */
+ uarg[2] = (intptr_t) p->buf; /* struct l_statfs64_buf * */
+ *n_args = 3;
break;
}
/* linux_tgkill */
@@ -5265,6 +5269,19 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_fstatfs64 */
case 269:
+ switch(ndx) {
+ case 0:
+ p = "l_uint";
+ break;
+ case 1:
+ p = "size_t";
+ break;
+ case 2:
+ p = "struct l_statfs64_buf *";
+ break;
+ default:
+ break;
+ };
break;
/* linux_tgkill */
case 270:
@@ -7138,6 +7155,9 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* linux_fstatfs64 */
case 269:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* linux_tgkill */
case 270:
if (ndx == 0 || ndx == 1)
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index 248770c..1032ef0 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -452,7 +452,7 @@
267 AUE_NULL STD { int linux_clock_nanosleep(clockid_t which, int flags, \
struct l_timespec *rqtp, struct l_timespec *rmtp); }
268 AUE_STATFS STD { int linux_statfs64(char *path, size_t bufsize, struct l_statfs64_buf *buf); }
-269 AUE_FSTATFS STD { int linux_fstatfs64(void); }
+269 AUE_FSTATFS STD { int linux_fstatfs64(l_uint fd, size_t bufsize, struct l_statfs64_buf *buf); }
270 AUE_NULL STD { int linux_tgkill(int tgid, int pid, int sig); }
271 AUE_UTIMES STD { int linux_utimes(char *fname, \
struct l_timeval *tptr); }
diff --git a/sys/isa/isa_common.c b/sys/isa/isa_common.c
index d2c8113..83e988c 100644
--- a/sys/isa/isa_common.c
+++ b/sys/isa/isa_common.c
@@ -629,10 +629,10 @@ isa_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl) || device_get_flags(dev))
retval += printf(" at");
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
- retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
+ retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd");
if (device_get_flags(dev))
retval += printf(" flags %#x", device_get_flags(dev));
#ifdef ISAPNP
diff --git a/sys/kern/imgact_binmisc.c b/sys/kern/imgact_binmisc.c
index dd57717..39ca156 100644
--- a/sys/kern/imgact_binmisc.c
+++ b/sys/kern/imgact_binmisc.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-15, Stacey D. Son
+ * Copyright (c) 2013-16, Stacey D. Son
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -220,16 +220,17 @@ imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe)
{
imgact_binmisc_entry_t *ibe;
char *p;
+ int cnt;
if (xbe->xbe_msize > IBE_MAGIC_MAX)
return (EINVAL);
- for(p = xbe->xbe_name; *p != 0; p++)
- if (!isascii((int)*p))
+ for(cnt = 0, p = xbe->xbe_name; *p != 0; cnt++, p++)
+ if (cnt >= IBE_NAME_MAX || !isascii((int)*p))
return (EINVAL);
- for(p = xbe->xbe_interpreter; *p != 0; p++)
- if (!isascii((int)*p))
+ for(cnt = 0, p = xbe->xbe_interpreter; *p != 0; cnt++, p++)
+ if (cnt >= IBE_INTERP_LEN_MAX || !isascii((int)*p))
return (EINVAL);
/* Make sure we don't have any invalid #'s. */
@@ -266,8 +267,6 @@ imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe)
/* Preallocate a new entry. */
ibe = imgact_binmisc_new_entry(xbe);
- if (!ibe)
- return (ENOMEM);
SLIST_INSERT_HEAD(&interpreter_list, ibe, link);
interp_list_entry_count++;
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 43d4800..0bed714 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -1370,10 +1370,6 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
* and write it out following the notes.
*/
hdr = malloc(hdrsize, M_TEMP, M_WAITOK);
- if (hdr == NULL) {
- error = EINVAL;
- goto done;
- }
error = __elfN(corehdr)(&params, seginfo.count, hdr, hdrsize, &notelst,
notesz);
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index 96c5229..47f2f90 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 296572 2016-03-09 19:05:11Z jhb
+ * created from FreeBSD: head/sys/kern/syscalls.master 297167 2016-03-21 21:37:33Z jhb
*/
#include "opt_compat.h"
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c
index 8061829..6f891e0 100644
--- a/sys/kern/kern_condvar.c
+++ b/sys/kern/kern_condvar.c
@@ -122,15 +122,8 @@ _cv_wait(struct cv *cvp, struct lock_object *lock)
"Waiting on \"%s\"", cvp->cv_description);
class = LOCK_CLASS(lock);
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * During autoconfiguration, just give interrupts
- * a chance, then just return. Don't run any other
- * thread or panic below, in case this is the idle
- * process and already asleep.
- */
+ if (SCHEDULER_STOPPED())
return;
- }
sleepq_lock(cvp);
@@ -183,13 +176,7 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
("cv_wait_unlock cannot be used with Giant"));
class = LOCK_CLASS(lock);
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * During autoconfiguration, just give interrupts
- * a chance, then just return. Don't run any other
- * thread or panic below, in case this is the idle
- * process and already asleep.
- */
+ if (SCHEDULER_STOPPED()) {
class->lc_unlock(lock);
return;
}
@@ -240,15 +227,8 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
"Waiting on \"%s\"", cvp->cv_description);
class = LOCK_CLASS(lock);
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * After a panic, or during autoconfiguration, just give
- * interrupts a chance, then just return; don't run any other
- * procs or panic below, in case this is the idle process and
- * already asleep.
- */
+ if (SCHEDULER_STOPPED())
return (0);
- }
sleepq_lock(cvp);
@@ -307,15 +287,8 @@ _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt,
"Waiting on \"%s\"", cvp->cv_description);
class = LOCK_CLASS(lock);
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * After a panic, or during autoconfiguration, just give
- * interrupts a chance, then just return; don't run any other
- * thread or panic below, in case this is the idle process and
- * already asleep.
- */
- return 0;
- }
+ if (SCHEDULER_STOPPED())
+ return (0);
sleepq_lock(cvp);
@@ -376,15 +349,8 @@ _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock,
"Waiting on \"%s\"", cvp->cv_description);
class = LOCK_CLASS(lock);
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * After a panic, or during autoconfiguration, just give
- * interrupts a chance, then just return; don't run any other
- * thread or panic below, in case this is the idle process and
- * already asleep.
- */
- return 0;
- }
+ if (SCHEDULER_STOPPED())
+ return (0);
sleepq_lock(cvp);
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 00bd54b..b37adcc 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -3958,7 +3958,7 @@ badfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
static int
badfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
- int kflags, struct thread *td)
+ struct thread *td)
{
return (EBADF);
@@ -4044,7 +4044,7 @@ invfo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
int
invfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
- int kflags, struct thread *td)
+ struct thread *td)
{
return (EINVAL);
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 69f0774..7c88fe0 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1570,8 +1570,6 @@ exec_register(execsw_arg)
for (es = execsw; *es; es++)
count++;
newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK);
- if (newexecsw == NULL)
- return (ENOMEM);
xs = newexecsw;
if (execsw)
for (es = execsw; *es; es++)
@@ -1604,8 +1602,6 @@ exec_unregister(execsw_arg)
if (*es != execsw_arg)
count++;
newexecsw = malloc(count * sizeof(*es), M_TEMP, M_WAITOK);
- if (newexecsw == NULL)
- return (ENOMEM);
xs = newexecsw;
for (es = execsw; *es; es++)
if (*es != execsw_arg)
diff --git a/sys/kern/kern_fail.c b/sys/kern/kern_fail.c
index 3737aa3..ec466dd 100644
--- a/sys/kern/kern_fail.c
+++ b/sys/kern/kern_fail.c
@@ -52,17 +52,25 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_stack.h"
+
#include <sys/ctype.h>
#include <sys/errno.h>
#include <sys/fail.h>
#include <sys/kernel.h>
#include <sys/libkern.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
+#include <sys/sleepqueue.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <machine/atomic.h>
#include <machine/stdarg.h>
#ifdef ILOG_DEFINE_FOR_FILE
@@ -72,11 +80,45 @@ ILOG_DEFINE_FOR_FILE(L_ISI_FAIL_POINT, L_ILOG, fail_point);
static MALLOC_DEFINE(M_FAIL_POINT, "Fail Points", "fail points system");
#define fp_free(ptr) free(ptr, M_FAIL_POINT)
#define fp_malloc(size, flags) malloc((size), M_FAIL_POINT, (flags))
+#define fs_free(ptr) fp_free(ptr)
+#define fs_malloc() fp_malloc(sizeof(struct fail_point_setting), \
+ M_WAITOK | M_ZERO)
+
+ /**
+ * These define the wchans that are used for sleeping, pausing respectively.
+ * They are chosen arbitrarily but need to be distinct to the failpoint and
+ * the sleep/pause distinction.
+ */
+#define FP_SLEEP_CHANNEL(fp) (void*)(fp)
+#define FP_PAUSE_CHANNEL(fp) __DEVOLATILE(void*, &fp->fp_setting)
+
+/**
+ * Don't allow more than this many entries in a fail point set by sysctl.
+ * The 99.99...% case is to have 1 entry. I can't imagine having this many
+ * entries, so it should not limit us. Saves on re-mallocs while holding
+ * a non-sleepable lock.
+ */
+#define FP_MAX_ENTRY_COUNT 20
+
+/* Used to drain sbufs to the sysctl output */
+int fail_sysctl_drain_func(void *, const char *, int);
+
+/* Head of tailq of struct fail_point_entry */
+TAILQ_HEAD(fail_point_entry_queue, fail_point_entry);
+
+/**
+ * fp entries garbage list; outstanding entries are cleaned up in the
+ * garbage collector
+ */
+STAILQ_HEAD(fail_point_setting_garbage, fail_point_setting);
+static struct fail_point_setting_garbage fp_setting_garbage =
+ STAILQ_HEAD_INITIALIZER(fp_setting_garbage);
+static struct mtx mtx_garbage_list;
+MTX_SYSINIT(mtx_garbage_list, &mtx_garbage_list, "fail point garbage mtx",
+ MTX_SPIN);
-static struct mtx g_fp_mtx;
-MTX_SYSINIT(g_fp_mtx, &g_fp_mtx, "fail point mtx", MTX_DEF);
-#define FP_LOCK() mtx_lock(&g_fp_mtx)
-#define FP_UNLOCK() mtx_unlock(&g_fp_mtx)
+static struct sx sx_fp_set;
+SX_SYSINIT(sx_fp_set, &sx_fp_set, "fail point set sx");
/**
* Failpoint types.
@@ -90,7 +132,11 @@ enum fail_point_t {
FAIL_POINT_BREAK, /**< break into the debugger */
FAIL_POINT_PRINT, /**< print a message */
FAIL_POINT_SLEEP, /**< sleep for some msecs */
- FAIL_POINT_NUMTYPES
+ FAIL_POINT_PAUSE, /**< sleep until failpoint is set to off */
+ FAIL_POINT_YIELD, /**< yield the cpu */
+ FAIL_POINT_DELAY, /**< busy wait the cpu */
+ FAIL_POINT_NUMTYPES,
+ FAIL_POINT_INVALID = -1
};
static struct {
@@ -104,53 +150,307 @@ static struct {
[FAIL_POINT_BREAK] = FP_TYPE_NM_LEN("break"),
[FAIL_POINT_PRINT] = FP_TYPE_NM_LEN("print"),
[FAIL_POINT_SLEEP] = FP_TYPE_NM_LEN("sleep"),
+ [FAIL_POINT_PAUSE] = FP_TYPE_NM_LEN("pause"),
+ [FAIL_POINT_YIELD] = FP_TYPE_NM_LEN("yield"),
+ [FAIL_POINT_DELAY] = FP_TYPE_NM_LEN("delay"),
};
+#define FE_COUNT_UNTRACKED (INT_MIN)
+
/**
* Internal structure tracking a single term of a complete failpoint.
* @ingroup failpoint_private
*/
struct fail_point_entry {
- enum fail_point_t fe_type; /**< type of entry */
+ volatile bool fe_stale;
+ enum fail_point_t fe_type; /**< type of entry */
int fe_arg; /**< argument to type (e.g. return value) */
int fe_prob; /**< likelihood of firing in millionths */
- int fe_count; /**< number of times to fire, 0 means always */
+ int fe_count; /**< number of times to fire, -1 means infinite */
pid_t fe_pid; /**< only fail for this process */
- TAILQ_ENTRY(fail_point_entry) fe_entries; /**< next entry in fail point */
+ struct fail_point *fe_parent; /**< backpointer to fp */
+ TAILQ_ENTRY(fail_point_entry) fe_entries; /**< next entry ptr */
};
+struct fail_point_setting {
+ STAILQ_ENTRY(fail_point_setting) fs_garbage_link;
+ struct fail_point_entry_queue fp_entry_queue;
+ struct fail_point * fs_parent;
+ struct mtx feq_mtx; /* Gives fail_point_pause something to do. */
+};
+
+/**
+ * Defines stating the equivalent of probablilty one (100%)
+ */
+enum {
+ PROB_MAX = 1000000, /* probability between zero and this number */
+ PROB_DIGITS = 6 /* number of zero's in above number */
+};
+
+/* Get a ref on an fp's fp_setting */
+static inline struct fail_point_setting *fail_point_setting_get_ref(
+ struct fail_point *fp);
+/* Release a ref on an fp_setting */
+static inline void fail_point_setting_release_ref(struct fail_point *fp);
+/* Allocate and initialize a struct fail_point_setting */
+static struct fail_point_setting *fail_point_setting_new(struct
+ fail_point *);
+/* Free a struct fail_point_setting */
+static void fail_point_setting_destroy(struct fail_point_setting *fp_setting);
+/* Allocate and initialize a struct fail_point_entry */
+static struct fail_point_entry *fail_point_entry_new(struct
+ fail_point_setting *);
+/* Free a struct fail_point_entry */
+static void fail_point_entry_destroy(struct fail_point_entry *fp_entry);
+/* Append fp setting to garbage list */
+static inline void fail_point_setting_garbage_append(
+ struct fail_point_setting *fp_setting);
+/* Swap fp's setting with fp_setting_new */
+static inline struct fail_point_setting *
+ fail_point_swap_settings(struct fail_point *fp,
+ struct fail_point_setting *fp_setting_new);
+/* Free up any zero-ref setting in the garbage queue */
+static void fail_point_garbage_collect(void);
+/* If this fail point's setting are empty, then swap it out to NULL. */
+static inline void fail_point_eval_swap_out(struct fail_point *fp,
+ struct fail_point_setting *fp_setting);
+
+bool
+fail_point_is_off(struct fail_point *fp)
+{
+ bool return_val;
+ struct fail_point_setting *fp_setting;
+ struct fail_point_entry *ent;
+
+ return_val = true;
+
+ fp_setting = fail_point_setting_get_ref(fp);
+ if (fp_setting != NULL) {
+ TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue,
+ fe_entries) {
+ if (!ent->fe_stale) {
+ return_val = false;
+ break;
+ }
+ }
+ }
+ fail_point_setting_release_ref(fp);
+
+ return (return_val);
+}
+
+/* Allocate and initialize a struct fail_point_setting */
+static struct fail_point_setting *
+fail_point_setting_new(struct fail_point *fp)
+{
+ struct fail_point_setting *fs_new;
+
+ fs_new = fs_malloc();
+ fs_new->fs_parent = fp;
+ TAILQ_INIT(&fs_new->fp_entry_queue);
+ mtx_init(&fs_new->feq_mtx, "fail point entries", NULL, MTX_SPIN);
+
+ fail_point_setting_garbage_append(fs_new);
+
+ return (fs_new);
+}
+
+/* Free a struct fail_point_setting */
+static void
+fail_point_setting_destroy(struct fail_point_setting *fp_setting)
+{
+ struct fail_point_entry *ent;
+
+ while (!TAILQ_EMPTY(&fp_setting->fp_entry_queue)) {
+ ent = TAILQ_FIRST(&fp_setting->fp_entry_queue);
+ TAILQ_REMOVE(&fp_setting->fp_entry_queue, ent, fe_entries);
+ fail_point_entry_destroy(ent);
+ }
+
+ fs_free(fp_setting);
+}
+
+/* Allocate and initialize a struct fail_point_entry */
+static struct fail_point_entry *
+fail_point_entry_new(struct fail_point_setting *fp_setting)
+{
+ struct fail_point_entry *fp_entry;
+
+ fp_entry = fp_malloc(sizeof(struct fail_point_entry),
+ M_WAITOK | M_ZERO);
+ fp_entry->fe_parent = fp_setting->fs_parent;
+ fp_entry->fe_prob = PROB_MAX;
+ fp_entry->fe_pid = NO_PID;
+ fp_entry->fe_count = FE_COUNT_UNTRACKED;
+ TAILQ_INSERT_TAIL(&fp_setting->fp_entry_queue, fp_entry,
+ fe_entries);
+
+ return (fp_entry);
+}
+
+/* Free a struct fail_point_entry */
+static void
+fail_point_entry_destroy(struct fail_point_entry *fp_entry)
+{
+
+ fp_free(fp_entry);
+}
+
+/* Get a ref on an fp's fp_setting */
+static inline struct fail_point_setting *
+fail_point_setting_get_ref(struct fail_point *fp)
+{
+ struct fail_point_setting *fp_setting;
+
+ /* Invariant: if we have a ref, our pointer to fp_setting is safe */
+ atomic_add_acq_32(&fp->fp_ref_cnt, 1);
+ fp_setting = fp->fp_setting;
+
+ return (fp_setting);
+}
+
+/* Release a ref on an fp_setting */
+static inline void
+fail_point_setting_release_ref(struct fail_point *fp)
+{
+
+ KASSERT(&fp->fp_ref_cnt > 0, ("Attempting to deref w/no refs"));
+ atomic_subtract_rel_32(&fp->fp_ref_cnt, 1);
+}
+
+/* Append fp entries to fp garbage list */
+static inline void
+fail_point_setting_garbage_append(struct fail_point_setting *fp_setting)
+{
+
+ mtx_lock_spin(&mtx_garbage_list);
+ STAILQ_INSERT_TAIL(&fp_setting_garbage, fp_setting,
+ fs_garbage_link);
+ mtx_unlock_spin(&mtx_garbage_list);
+}
+
+/* Swap fp's entries with fp_setting_new */
+static struct fail_point_setting *
+fail_point_swap_settings(struct fail_point *fp,
+ struct fail_point_setting *fp_setting_new)
+{
+ struct fail_point_setting *fp_setting_old;
+
+ fp_setting_old = fp->fp_setting;
+ fp->fp_setting = fp_setting_new;
+
+ return (fp_setting_old);
+}
+
+static inline void
+fail_point_eval_swap_out(struct fail_point *fp,
+ struct fail_point_setting *fp_setting)
+{
+
+ /* We may have already been swapped out and replaced; ignore. */
+ if (fp->fp_setting == fp_setting)
+ fail_point_swap_settings(fp, NULL);
+}
+
+/* Free up any zero-ref entries in the garbage queue */
+static void
+fail_point_garbage_collect()
+{
+ struct fail_point_setting *fs_current, *fs_next;
+ struct fail_point_setting_garbage fp_ents_free_list;
+
+ /**
+ * We will transfer the entries to free to fp_ents_free_list while holding
+ * the spin mutex, then free it after we drop the lock. This avoids
+ * triggering witness due to sleepable mutexes in the memory
+ * allocator.
+ */
+ STAILQ_INIT(&fp_ents_free_list);
+
+ mtx_lock_spin(&mtx_garbage_list);
+ STAILQ_FOREACH_SAFE(fs_current, &fp_setting_garbage, fs_garbage_link,
+ fs_next) {
+ if (fs_current->fs_parent->fp_setting != fs_current &&
+ fs_current->fs_parent->fp_ref_cnt == 0) {
+ STAILQ_REMOVE(&fp_setting_garbage, fs_current,
+ fail_point_setting, fs_garbage_link);
+ STAILQ_INSERT_HEAD(&fp_ents_free_list, fs_current,
+ fs_garbage_link);
+ }
+ }
+ mtx_unlock_spin(&mtx_garbage_list);
+
+ STAILQ_FOREACH_SAFE(fs_current, &fp_ents_free_list, fs_garbage_link,
+ fs_next)
+ fail_point_setting_destroy(fs_current);
+}
+
+/* Drain out all refs from this fail point */
+static inline void
+fail_point_drain(struct fail_point *fp, int expected_ref)
+{
+ struct fail_point_setting *entries;
+
+ entries = fail_point_swap_settings(fp, NULL);
+ /**
+ * We have unpaused all threads; so we will wait no longer
+ * than the time taken for the longest remaining sleep, or
+ * the length of time of a long-running code block.
+ */
+ while (fp->fp_ref_cnt > expected_ref) {
+ wakeup(FP_PAUSE_CHANNEL(fp));
+ tsleep(&fp, PWAIT, "fail_point_drain", hz / 100);
+ }
+ fail_point_swap_settings(fp, entries);
+}
+
static inline void
-fail_point_sleep(struct fail_point *fp, struct fail_point_entry *ent,
- int msecs, enum fail_point_return_code *pret)
+fail_point_pause(struct fail_point *fp, enum fail_point_return_code *pret,
+ struct mtx *mtx_sleep)
{
- /* convert from millisecs to ticks, rounding up */
- int timo = ((msecs * hz) + 999) / 1000;
+
+ if (fp->fp_pre_sleep_fn)
+ fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
+
+ msleep_spin(FP_PAUSE_CHANNEL(fp), mtx_sleep, "failpt", 0);
+
+ if (fp->fp_post_sleep_fn)
+ fp->fp_post_sleep_fn(fp->fp_post_sleep_arg);
+}
+
+static inline void
+fail_point_sleep(struct fail_point *fp, int msecs,
+ enum fail_point_return_code *pret)
+{
+ int timo;
+
+ /* Convert from millisecs to ticks, rounding up */
+ timo = howmany(msecs * hz, 1000);
if (timo > 0) {
- if (fp->fp_sleep_fn == NULL) {
- msleep(fp, &g_fp_mtx, PWAIT, "failpt", timo);
+ if (!(fp->fp_flags & FAIL_POINT_USE_TIMEOUT_PATH)) {
+ if (fp->fp_pre_sleep_fn)
+ fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
+
+ tsleep(FP_SLEEP_CHANNEL(fp), PWAIT, "failpt", timo);
+
+ if (fp->fp_post_sleep_fn)
+ fp->fp_post_sleep_fn(fp->fp_post_sleep_arg);
} else {
- timeout(fp->fp_sleep_fn, fp->fp_sleep_arg, timo);
+ if (fp->fp_pre_sleep_fn)
+ fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
+
+ timeout(fp->fp_post_sleep_fn, fp->fp_post_sleep_arg,
+ timo);
*pret = FAIL_POINT_RC_QUEUED;
}
}
}
-
-/**
- * Defines stating the equivalent of probablilty one (100%)
- */
-enum {
- PROB_MAX = 1000000, /* probability between zero and this number */
- PROB_DIGITS = 6, /* number of zero's in above number */
-};
-
-static char *parse_fail_point(struct fail_point_entries *, char *);
-static char *parse_term(struct fail_point_entries *, char *);
+static char *parse_fail_point(struct fail_point_setting *, char *);
+static char *parse_term(struct fail_point_setting *, char *);
static char *parse_number(int *out_units, int *out_decimal, char *);
static char *parse_type(struct fail_point_entry *, char *);
-static void free_entry(struct fail_point_entries *, struct fail_point_entry *);
-static void clear_entries(struct fail_point_entries *);
/**
* Initialize a fail_point. The name is formed in a printf-like fashion
@@ -167,7 +467,7 @@ fail_point_init(struct fail_point *fp, const char *fmt, ...)
char *name;
int n;
- TAILQ_INIT(&fp->fp_entries);
+ fp->fp_setting = NULL;
fp->fp_flags = 0;
/* Figure out the size of the name. */
@@ -185,25 +485,33 @@ fail_point_init(struct fail_point *fp, const char *fmt, ...)
fp->fp_name = name;
fp->fp_location = "";
fp->fp_flags |= FAIL_POINT_DYNAMIC_NAME;
- fp->fp_sleep_fn = NULL;
- fp->fp_sleep_arg = NULL;
+ fp->fp_pre_sleep_fn = NULL;
+ fp->fp_pre_sleep_arg = NULL;
+ fp->fp_post_sleep_fn = NULL;
+ fp->fp_post_sleep_arg = NULL;
}
/**
- * Free the resources held by a fail_point.
- *
+ * Free the resources held by a fail_point, and wake any paused threads.
+ * Thou shalt not allow threads to hit this fail point after you enter this
+ * function, nor shall you call this multiple times for a given fp.
* @ingroup failpoint
*/
void
fail_point_destroy(struct fail_point *fp)
{
+ fail_point_drain(fp, 0);
+
if ((fp->fp_flags & FAIL_POINT_DYNAMIC_NAME) != 0) {
fp_free(__DECONST(void *, fp->fp_name));
fp->fp_name = NULL;
}
fp->fp_flags = 0;
- clear_entries(&fp->fp_entries);
+
+ sx_xlock(&sx_fp_set);
+ fail_point_garbage_collect();
+ sx_xunlock(&sx_fp_set);
}
/**
@@ -216,21 +524,51 @@ fail_point_destroy(struct fail_point *fp)
enum fail_point_return_code
fail_point_eval_nontrivial(struct fail_point *fp, int *return_value)
{
- enum fail_point_return_code ret = FAIL_POINT_RC_CONTINUE;
- struct fail_point_entry *ent, *next;
+ bool execute = false;
+ struct fail_point_entry *ent;
+ struct fail_point_setting *fp_setting;
+ enum fail_point_return_code ret;
+ int cont;
+ int count;
int msecs;
+ int usecs;
+
+ ret = FAIL_POINT_RC_CONTINUE;
+ cont = 0; /* don't continue by default */
+
+ fp_setting = fail_point_setting_get_ref(fp);
+ if (fp_setting == NULL)
+ goto abort;
- FP_LOCK();
+ TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue, fe_entries) {
- TAILQ_FOREACH_SAFE(ent, &fp->fp_entries, fe_entries, next) {
- int cont = 0; /* don't continue by default */
+ if (ent->fe_stale)
+ continue;
if (ent->fe_prob < PROB_MAX &&
ent->fe_prob < random() % PROB_MAX)
continue;
+
if (ent->fe_pid != NO_PID && ent->fe_pid != curproc->p_pid)
continue;
+ if (ent->fe_count != FE_COUNT_UNTRACKED) {
+ count = ent->fe_count;
+ while (count > 0) {
+ if (atomic_cmpset_32(&ent->fe_count, count, count - 1)) {
+ count--;
+ execute = true;
+ break;
+ }
+ count = ent->fe_count;
+ }
+ if (execute == false)
+ /* We lost the race; consider the entry stale and bail now */
+ continue;
+ if (count == 0)
+ ent->fe_stale = true;
+ }
+
switch (ent->fe_type) {
case FAIL_POINT_PANIC:
panic("fail point %s panicking", fp->fp_name);
@@ -244,7 +582,7 @@ fail_point_eval_nontrivial(struct fail_point *fp, int *return_value)
case FAIL_POINT_BREAK:
printf("fail point %s breaking to debugger\n",
- fp->fp_name);
+ fp->fp_name);
breakpoint();
break;
@@ -254,51 +592,95 @@ fail_point_eval_nontrivial(struct fail_point *fp, int *return_value)
break;
case FAIL_POINT_SLEEP:
- /*
- * Free the entry now if necessary, since
- * we're about to drop the mutex and sleep.
- */
msecs = ent->fe_arg;
- if (ent->fe_count > 0 && --ent->fe_count == 0) {
- free_entry(&fp->fp_entries, ent);
- ent = NULL;
- }
-
if (msecs)
- fail_point_sleep(fp, ent, msecs, &ret);
+ fail_point_sleep(fp, msecs, &ret);
+ break;
+
+ case FAIL_POINT_PAUSE:
+ /**
+ * Pausing is inherently strange with multiple
+ * entries given our design. That is because some
+ * entries could be unreachable, for instance in cases like:
+ * pause->return. We can never reach the return entry.
+ * The sysctl layer actually truncates all entries after
+ * a pause for this reason.
+ */
+ mtx_lock_spin(&fp_setting->feq_mtx);
+ fail_point_pause(fp, &ret, &fp_setting->feq_mtx);
+ mtx_unlock_spin(&fp_setting->feq_mtx);
+ break;
+
+ case FAIL_POINT_YIELD:
+ kern_yield(-1);
+ break;
+
+ case FAIL_POINT_DELAY:
+ usecs = ent->fe_arg;
+ DELAY(usecs);
break;
default:
break;
}
- if (ent != NULL && ent->fe_count > 0 && --ent->fe_count == 0)
- free_entry(&fp->fp_entries, ent);
if (cont == 0)
break;
}
- /* Get rid of "off"s at the end. */
- while ((ent = TAILQ_LAST(&fp->fp_entries, fail_point_entries)) &&
- ent->fe_type == FAIL_POINT_OFF)
- free_entry(&fp->fp_entries, ent);
+ if (fail_point_is_off(fp))
+ fail_point_eval_swap_out(fp, fp_setting);
- FP_UNLOCK();
+abort:
+ fail_point_setting_release_ref(fp);
return (ret);
+
}
/**
* Translate internal fail_point structure into human-readable text.
*/
static void
-fail_point_get(struct fail_point *fp, struct sbuf *sb)
+fail_point_get(struct fail_point *fp, struct sbuf *sb,
+ bool verbose)
{
struct fail_point_entry *ent;
+ struct fail_point_setting *fp_setting;
+ struct fail_point_entry *fp_entry_cpy;
+ int cnt_sleeping;
+ int idx;
+ int printed_entry_count;
+
+ cnt_sleeping = 0;
+ idx = 0;
+ printed_entry_count = 0;
+
+ fp_entry_cpy = fp_malloc(sizeof(struct fail_point_entry) *
+ (FP_MAX_ENTRY_COUNT + 1), M_WAITOK);
+
+ fp_setting = fail_point_setting_get_ref(fp);
- FP_LOCK();
+ if (fp_setting != NULL) {
+ TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue, fe_entries) {
+ if (ent->fe_stale)
+ continue;
- TAILQ_FOREACH(ent, &fp->fp_entries, fe_entries) {
+ KASSERT(printed_entry_count < FP_MAX_ENTRY_COUNT,
+ ("FP entry list larger than allowed"));
+
+ fp_entry_cpy[printed_entry_count] = *ent;
+ ++printed_entry_count;
+ }
+ }
+ fail_point_setting_release_ref(fp);
+
+ /* This is our equivalent of a NULL terminator */
+ fp_entry_cpy[printed_entry_count].fe_type = FAIL_POINT_INVALID;
+
+ while (idx < printed_entry_count) {
+ ent = &fp_entry_cpy[idx];
+ ++idx;
if (ent->fe_prob < PROB_MAX) {
int decimal = ent->fe_prob % (PROB_MAX / 100);
int units = ent->fe_prob / (PROB_MAX / 100);
@@ -313,7 +695,7 @@ fail_point_get(struct fail_point *fp, struct sbuf *sb)
}
sbuf_printf(sb, "%%");
}
- if (ent->fe_count > 0)
+ if (ent->fe_count >= 0)
sbuf_printf(sb, "%d*", ent->fe_count);
sbuf_printf(sb, "%s", fail_type_strings[ent->fe_type].name);
if (ent->fe_arg)
@@ -323,10 +705,33 @@ fail_point_get(struct fail_point *fp, struct sbuf *sb)
if (TAILQ_NEXT(ent, fe_entries))
sbuf_printf(sb, "->");
}
- if (TAILQ_EMPTY(&fp->fp_entries))
+ if (!printed_entry_count)
sbuf_printf(sb, "off");
- FP_UNLOCK();
+ fp_free(fp_entry_cpy);
+ if (verbose) {
+#ifdef STACK
+ /* Print number of sleeping threads. queue=0 is the argument
+ * used by msleep when sending our threads to sleep. */
+ sbuf_printf(sb, "\nsleeping_thread_stacks = {\n");
+ sleepq_sbuf_print_stacks(sb, FP_SLEEP_CHANNEL(fp), 0,
+ &cnt_sleeping);
+
+ sbuf_printf(sb, "},\n");
+#endif
+ sbuf_printf(sb, "sleeping_thread_count = %d,\n",
+ cnt_sleeping);
+
+#ifdef STACK
+ sbuf_printf(sb, "paused_thread_stacks = {\n");
+ sleepq_sbuf_print_stacks(sb, FP_PAUSE_CHANNEL(fp), 0,
+ &cnt_sleeping);
+
+ sbuf_printf(sb, "},\n");
+#endif
+ sbuf_printf(sb, "paused_thread_count = %d\n",
+ cnt_sleeping);
+ }
}
/**
@@ -336,38 +741,91 @@ fail_point_get(struct fail_point *fp, struct sbuf *sb)
static int
fail_point_set(struct fail_point *fp, char *buf)
{
- int error = 0;
struct fail_point_entry *ent, *ent_next;
- struct fail_point_entries new_entries;
+ struct fail_point_setting *entries;
+ bool should_wake_paused;
+ bool should_truncate;
+ int error;
+
+ error = 0;
+ should_wake_paused = false;
+ should_truncate = false;
/* Parse new entries. */
- TAILQ_INIT(&new_entries);
- if (!parse_fail_point(&new_entries, buf)) {
- clear_entries(&new_entries);
+ /**
+ * ref protects our new malloc'd stuff from being garbage collected
+ * before we link it.
+ */
+ fail_point_setting_get_ref(fp);
+ entries = fail_point_setting_new(fp);
+ if (parse_fail_point(entries, buf) == NULL) {
+ STAILQ_REMOVE(&fp_setting_garbage, entries,
+ fail_point_setting, fs_garbage_link);
+ fail_point_setting_destroy(entries);
error = EINVAL;
goto end;
}
- FP_LOCK();
-
- /* Move new entries in. */
- TAILQ_SWAP(&fp->fp_entries, &new_entries, fail_point_entry, fe_entries);
- clear_entries(&new_entries);
+ /**
+ * Transfer the entries we are going to keep to a new list.
+ * Get rid of useless zero probability entries, and entries with hit
+ * count 0.
+ * If 'off' is present, and it has no hit count set, then all entries
+ * after it are discarded since they are unreachable.
+ */
+ TAILQ_FOREACH_SAFE(ent, &entries->fp_entry_queue, fe_entries, ent_next) {
+ if (ent->fe_prob == 0 || ent->fe_count == 0) {
+ printf("Discarding entry which cannot execute %s\n",
+ fail_type_strings[ent->fe_type].name);
+ TAILQ_REMOVE(&entries->fp_entry_queue, ent,
+ fe_entries);
+ fp_free(ent);
+ continue;
+ } else if (should_truncate) {
+ printf("Discarding unreachable entry %s\n",
+ fail_type_strings[ent->fe_type].name);
+ TAILQ_REMOVE(&entries->fp_entry_queue, ent,
+ fe_entries);
+ fp_free(ent);
+ continue;
+ }
- /* Get rid of useless zero probability entries. */
- TAILQ_FOREACH_SAFE(ent, &fp->fp_entries, fe_entries, ent_next) {
- if (ent->fe_prob == 0)
- free_entry(&fp->fp_entries, ent);
+ if (ent->fe_type == FAIL_POINT_OFF) {
+ should_wake_paused = true;
+ if (ent->fe_count == FE_COUNT_UNTRACKED) {
+ should_truncate = true;
+ TAILQ_REMOVE(&entries->fp_entry_queue, ent,
+ fe_entries);
+ fp_free(ent);
+ }
+ } else if (ent->fe_type == FAIL_POINT_PAUSE) {
+ should_truncate = true;
+ } else if (ent->fe_type == FAIL_POINT_SLEEP && (fp->fp_flags &
+ FAIL_POINT_NONSLEEPABLE)) {
+ /**
+ * If this fail point is annotated as being in a
+ * non-sleepable ctx, convert sleep to delay and
+ * convert the msec argument to usecs.
+ */
+ printf("Sleep call request on fail point in "
+ "non-sleepable context; using delay instead "
+ "of sleep\n");
+ ent->fe_type = FAIL_POINT_DELAY;
+ ent->fe_arg *= 1000;
+ }
}
- /* Get rid of "off"s at the end. */
- while ((ent = TAILQ_LAST(&fp->fp_entries, fail_point_entries)) &&
- ent->fe_type == FAIL_POINT_OFF)
- free_entry(&fp->fp_entries, ent);
-
- FP_UNLOCK();
+ if (TAILQ_EMPTY(&entries->fp_entry_queue)) {
+ entries = fail_point_swap_settings(fp, NULL);
+ if (entries != NULL)
+ wakeup(FP_PAUSE_CHANNEL(fp));
+ } else {
+ if (should_wake_paused)
+ wakeup(FP_PAUSE_CHANNEL(fp));
+ fail_point_swap_settings(fp, entries);
+ }
- end:
+end:
#ifdef IWARNING
if (error)
IWARNING("Failed to set %s %s to %s",
@@ -377,6 +835,7 @@ fail_point_set(struct fail_point *fp, char *buf)
fp->fp_name, fp->fp_location, buf);
#endif /* IWARNING */
+ fail_point_setting_release_ref(fp);
return (error);
}
@@ -385,25 +844,33 @@ fail_point_set(struct fail_point *fp, char *buf)
/**
* Handle kernel failpoint set/get.
*/
+
int
fail_point_sysctl(SYSCTL_HANDLER_ARGS)
{
- struct fail_point *fp = arg1;
- char *buf = NULL;
+ struct fail_point *fp;
+ char *buf;
+ struct sbuf *sb_check;
struct sbuf sb;
int error;
- /* Retrieving */
- sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
- fail_point_get(fp, &sb);
- sbuf_trim(&sb);
- error = sbuf_finish(&sb);
- if (error == 0)
- error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
- sbuf_delete(&sb);
+ error = 0;
+ fp = arg1;
+ buf = NULL;
+
+ sb_check = sbuf_new(&sb, NULL, 1024, SBUF_AUTOEXTEND);
+ if (sb_check != &sb)
+ return (ENOMEM);
+
+ sbuf_set_drain(&sb, (sbuf_drain_func *)fail_sysctl_drain_func, req);
/* Setting */
- if (!error && req->newptr) {
+ /**
+ * Lock protects any new entries from being garbage collected before we
+ * can link them to the fail point.
+ */
+ sx_xlock(&sx_fp_set);
+ if (req->newptr) {
if (req->newlen > MAX_FAIL_POINT_BUF) {
error = EINVAL;
goto out;
@@ -417,31 +884,95 @@ fail_point_sysctl(SYSCTL_HANDLER_ARGS)
buf[req->newlen] = '\0';
error = fail_point_set(fp, buf);
- }
+ }
+
+ fail_point_garbage_collect();
+ sx_xunlock(&sx_fp_set);
+
+ /* Retrieving. */
+ fail_point_get(fp, &sb, false);
out:
- fp_free(buf);
+ sbuf_finish(&sb);
+ sbuf_delete(&sb);
+
+ if (buf)
+ fp_free(buf);
+
return (error);
}
+int
+fail_point_sysctl_status(SYSCTL_HANDLER_ARGS)
+{
+ struct fail_point *fp;
+ struct sbuf sb, *sb_check;
+
+ fp = arg1;
+
+ sb_check = sbuf_new(&sb, NULL, 1024, SBUF_AUTOEXTEND);
+ if (sb_check != &sb)
+ return (ENOMEM);
+
+ sbuf_set_drain(&sb, (sbuf_drain_func *)fail_sysctl_drain_func, req);
+
+ /* Retrieving. */
+ fail_point_get(fp, &sb, true);
+
+ sbuf_finish(&sb);
+ sbuf_delete(&sb);
+
+ /**
+ * Lock protects any new entries from being garbage collected before we
+ * can link them to the fail point.
+ */
+ sx_xlock(&sx_fp_set);
+ fail_point_garbage_collect();
+ sx_xunlock(&sx_fp_set);
+
+ return (0);
+}
+
+int
+fail_sysctl_drain_func(void *sysctl_args, const char *buf, int len)
+{
+ struct sysctl_req *sa;
+ int error;
+
+ sa = sysctl_args;
+
+ error = SYSCTL_OUT(sa, buf, len);
+
+ if (error == ENOMEM)
+ return (-1);
+ else
+ return (len);
+}
+
+
/**
* Internal helper function to translate a human-readable failpoint string
* into a internally-parsable fail_point structure.
*/
static char *
-parse_fail_point(struct fail_point_entries *ents, char *p)
+parse_fail_point(struct fail_point_setting *ents, char *p)
{
/* <fail_point> ::
* <term> ( "->" <term> )*
*/
+ uint8_t term_count;
+
+ term_count = 1;
+
p = parse_term(ents, p);
if (p == NULL)
return (NULL);
+
while (*p != '\0') {
- if (p[0] != '-' || p[1] != '>')
- return (NULL);
- p = parse_term(ents, p + 2);
- if (p == NULL)
+ term_count++;
+ if (p[0] != '-' || p[1] != '>' ||
+ (p = parse_term(ents, p+2)) == NULL ||
+ term_count > FP_MAX_ENTRY_COUNT)
return (NULL);
}
return (p);
@@ -451,14 +982,11 @@ parse_fail_point(struct fail_point_entries *ents, char *p)
* Internal helper function to parse an individual term from a failpoint.
*/
static char *
-parse_term(struct fail_point_entries *ents, char *p)
+parse_term(struct fail_point_setting *ents, char *p)
{
struct fail_point_entry *ent;
- ent = fp_malloc(sizeof *ent, M_WAITOK | M_ZERO);
- ent->fe_prob = PROB_MAX;
- ent->fe_pid = NO_PID;
- TAILQ_INSERT_TAIL(ents, ent, fe_entries);
+ ent = fail_point_entry_new(ents);
/*
* <term> ::
@@ -483,7 +1011,7 @@ parse_term(struct fail_point_entries *ents, char *p)
if (ent->fe_prob > PROB_MAX)
ent->fe_prob = PROB_MAX;
} else if (*p == '*') {
- if (!units || decimal)
+ if (!units || units < 0 || decimal)
return (NULL);
ent->fe_count = units;
} else
@@ -500,7 +1028,7 @@ parse_term(struct fail_point_entries *ents, char *p)
/* [ "(" <integer> ")" ] */
if (*p != '(')
- return p;
+ return (p);
p++;
if (!isdigit(*p) && *p != '-')
return (NULL);
@@ -509,7 +1037,7 @@ parse_term(struct fail_point_entries *ents, char *p)
return (NULL);
/* [ "[pid " <integer> "]" ] */
-#define PID_STRING "[pid "
+#define PID_STRING "[pid "
if (strncmp(p, PID_STRING, sizeof(PID_STRING) - 1) != 0)
return (p);
p += sizeof(PID_STRING) - 1;
@@ -530,7 +1058,7 @@ parse_number(int *out_units, int *out_decimal, char *p)
{
char *old_p;
- /*
+ /**
* <number> ::
* <integer> [ "." <integer> ] |
* "." <integer>
@@ -584,29 +1112,17 @@ parse_type(struct fail_point_entry *ent, char *beg)
return (NULL);
}
-/**
- * Internal helper function to free an individual failpoint term.
- */
-static void
-free_entry(struct fail_point_entries *ents, struct fail_point_entry *ent)
-{
- TAILQ_REMOVE(ents, ent, fe_entries);
- fp_free(ent);
-}
+/* The fail point sysctl tree. */
+SYSCTL_NODE(_debug, OID_AUTO, fail_point, CTLFLAG_RW, 0, "fail points");
-/**
- * Internal helper function to clear out all failpoint terms for a single
- * failpoint.
- */
-static void
-clear_entries(struct fail_point_entries *ents)
+/* Debugging/testing stuff for fail point */
+static int
+sysctl_test_fail_point(SYSCTL_HANDLER_ARGS)
{
- struct fail_point_entry *ent, *ent_next;
- TAILQ_FOREACH_SAFE(ent, ents, fe_entries, ent_next)
- fp_free(ent);
- TAILQ_INIT(ents);
+ KFAIL_POINT_RETURN(DEBUG_FP, test_fail_point);
+ return (0);
}
-
-/* The fail point sysctl tree. */
-SYSCTL_NODE(_debug, OID_AUTO, fail_point, CTLFLAG_RW, 0, "fail points");
+SYSCTL_OID(_debug_fail_point, OID_AUTO, test_trigger_fail_point,
+ CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, sysctl_test_fail_point, "A",
+ "Trigger test fail points");
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 7454d79..e204291 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -1763,8 +1763,6 @@ linker_hints_lookup(const char *path, int pathlen, const char *modname,
goto bad;
}
hints = malloc(vattr.va_size, M_TEMP, M_WAITOK);
- if (hints == NULL)
- goto bad;
error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0,
UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td);
if (error)
diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c
index 3074589..5e634d7 100644
--- a/sys/kern/kern_mbuf.c
+++ b/sys/kern/kern_mbuf.c
@@ -424,6 +424,7 @@ mb_ctor_mbuf(void *mem, int size, void *arg, int how)
m = (struct mbuf *)mem;
flags = args->flags;
+ MPASS((flags & M_NOFREE) == 0);
error = m_init(m, how, type, flags);
@@ -572,6 +573,7 @@ mb_ctor_pack(void *mem, int size, void *arg, int how)
args = (struct mb_args *)arg;
flags = args->flags;
type = args->type;
+ MPASS((flags & M_NOFREE) == 0);
#ifdef INVARIANTS
trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
@@ -731,6 +733,7 @@ m_clget(struct mbuf *m, int how)
zone_drain(zone_pack);
uma_zalloc_arg(zone_clust, m, how);
}
+ MBUF_PROBE2(m__clget, m, how);
return (m->m_flags & M_EXT);
}
@@ -745,6 +748,7 @@ void *
m_cljget(struct mbuf *m, int how, int size)
{
uma_zone_t zone;
+ void *retval;
if (m != NULL) {
KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
@@ -753,7 +757,11 @@ m_cljget(struct mbuf *m, int how, int size)
}
zone = m_getzone(size);
- return (uma_zalloc_arg(zone, m, how));
+ retval = uma_zalloc_arg(zone, m, how);
+
+ MBUF_PROBE4(m__cljget, m, how, size, retval);
+
+ return (retval);
}
/*
@@ -934,6 +942,7 @@ void
m_freem(struct mbuf *mb)
{
+ MBUF_PROBE1(m__freem, mb);
while (mb != NULL)
mb = m_free(mb);
}
diff --git a/sys/kern/kern_osd.c b/sys/kern/kern_osd.c
index cc9bed1..41d518f 100644
--- a/sys/kern/kern_osd.c
+++ b/sys/kern/kern_osd.c
@@ -44,6 +44,23 @@ __FBSDID("$FreeBSD$");
/* OSD (Object Specific Data) */
+/*
+ * Lock key:
+ * (m) osd_module_lock
+ * (o) osd_object_lock
+ * (l) osd_list_lock
+ */
+struct osd_master {
+ struct sx osd_module_lock;
+ struct rmlock osd_object_lock;
+ struct mtx osd_list_lock;
+ LIST_HEAD(, osd) osd_list; /* (l) */
+ osd_destructor_t *osd_destructors; /* (o) */
+ osd_method_t *osd_methods; /* (m) */
+ u_int osd_ntslots; /* (m) */
+ const u_int osd_nmethods;
+};
+
static MALLOC_DEFINE(M_OSD, "osd", "Object Specific Data");
static int osd_debug = 0;
@@ -61,25 +78,12 @@ static void do_osd_del(u_int type, struct osd *osd, u_int slot,
int list_locked);
/*
- * Lists of objects with OSD.
- *
- * Lock key:
- * (m) osd_module_lock
- * (o) osd_object_lock
- * (l) osd_list_lock
+ * List of objects with OSD.
*/
-static LIST_HEAD(, osd) osd_list[OSD_LAST + 1]; /* (m) */
-static osd_method_t *osd_methods[OSD_LAST + 1]; /* (m) */
-static u_int osd_nslots[OSD_LAST + 1]; /* (m) */
-static osd_destructor_t *osd_destructors[OSD_LAST + 1]; /* (o) */
-static const u_int osd_nmethods[OSD_LAST + 1] = {
- [OSD_JAIL] = PR_MAXMETHOD,
+struct osd_master osdm[OSD_LAST + 1] = {
+ [OSD_JAIL] = { .osd_nmethods = PR_MAXMETHOD },
};
-static struct sx osd_module_lock[OSD_LAST + 1];
-static struct rmlock osd_object_lock[OSD_LAST + 1];
-static struct mtx osd_list_lock[OSD_LAST + 1];
-
static void
osd_default_destructor(void *value __unused)
{
@@ -101,12 +105,12 @@ osd_register(u_int type, osd_destructor_t destructor, osd_method_t *methods)
if (destructor == NULL)
destructor = osd_default_destructor;
- sx_xlock(&osd_module_lock[type]);
+ sx_xlock(&osdm[type].osd_module_lock);
/*
* First, we try to find unused slot.
*/
- for (i = 0; i < osd_nslots[type]; i++) {
- if (osd_destructors[type][i] == NULL) {
+ for (i = 0; i < osdm[type].osd_ntslots; i++) {
+ if (osdm[type].osd_destructors[i] == NULL) {
OSD_DEBUG("Unused slot found (type=%u, slot=%u).",
type, i);
break;
@@ -115,31 +119,31 @@ osd_register(u_int type, osd_destructor_t destructor, osd_method_t *methods)
/*
* If no unused slot was found, allocate one.
*/
- if (i == osd_nslots[type]) {
- osd_nslots[type]++;
- if (osd_nmethods[type] != 0)
- osd_methods[type] = realloc(osd_methods[type],
- sizeof(osd_method_t) * osd_nslots[type] *
- osd_nmethods[type], M_OSD, M_WAITOK);
- newptr = malloc(sizeof(osd_destructor_t) * osd_nslots[type],
- M_OSD, M_WAITOK);
- rm_wlock(&osd_object_lock[type]);
- bcopy(osd_destructors[type], newptr,
+ if (i == osdm[type].osd_ntslots) {
+ osdm[type].osd_ntslots++;
+ if (osdm[type].osd_nmethods != 0)
+ osdm[type].osd_methods = realloc(osdm[type].osd_methods,
+ sizeof(osd_method_t) * osdm[type].osd_ntslots *
+ osdm[type].osd_nmethods, M_OSD, M_WAITOK);
+ newptr = malloc(sizeof(osd_destructor_t) *
+ osdm[type].osd_ntslots, M_OSD, M_WAITOK);
+ rm_wlock(&osdm[type].osd_object_lock);
+ bcopy(osdm[type].osd_destructors, newptr,
sizeof(osd_destructor_t) * i);
- free(osd_destructors[type], M_OSD);
- osd_destructors[type] = newptr;
- rm_wunlock(&osd_object_lock[type]);
+ free(osdm[type].osd_destructors, M_OSD);
+ osdm[type].osd_destructors = newptr;
+ rm_wunlock(&osdm[type].osd_object_lock);
OSD_DEBUG("New slot allocated (type=%u, slot=%u).",
type, i + 1);
}
- osd_destructors[type][i] = destructor;
- if (osd_nmethods[type] != 0) {
- for (m = 0; m < osd_nmethods[type]; m++)
- osd_methods[type][i * osd_nmethods[type] + m] =
- methods != NULL ? methods[m] : NULL;
+ osdm[type].osd_destructors[i] = destructor;
+ if (osdm[type].osd_nmethods != 0) {
+ for (m = 0; m < osdm[type].osd_nmethods; m++)
+ osdm[type].osd_methods[i * osdm[type].osd_nmethods + m]
+ = methods != NULL ? methods[m] : NULL;
}
- sx_xunlock(&osd_module_lock[type]);
+ sx_xunlock(&osdm[type].osd_module_lock);
return (i + 1);
}
@@ -150,105 +154,142 @@ osd_deregister(u_int type, u_int slot)
KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
KASSERT(slot > 0, ("Invalid slot."));
- KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot."));
+ KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
- sx_xlock(&osd_module_lock[type]);
- rm_wlock(&osd_object_lock[type]);
+ sx_xlock(&osdm[type].osd_module_lock);
+ rm_wlock(&osdm[type].osd_object_lock);
/*
* Free all OSD for the given slot.
*/
- mtx_lock(&osd_list_lock[type]);
- LIST_FOREACH_SAFE(osd, &osd_list[type], osd_next, tosd)
+ mtx_lock(&osdm[type].osd_list_lock);
+ LIST_FOREACH_SAFE(osd, &osdm[type].osd_list, osd_next, tosd)
do_osd_del(type, osd, slot, 1);
- mtx_unlock(&osd_list_lock[type]);
+ mtx_unlock(&osdm[type].osd_list_lock);
/*
* Set destructor to NULL to free the slot.
*/
- osd_destructors[type][slot - 1] = NULL;
- if (slot == osd_nslots[type]) {
- osd_nslots[type]--;
- osd_destructors[type] = realloc(osd_destructors[type],
- sizeof(osd_destructor_t) * osd_nslots[type], M_OSD,
+ osdm[type].osd_destructors[slot - 1] = NULL;
+ if (slot == osdm[type].osd_ntslots) {
+ osdm[type].osd_ntslots--;
+ osdm[type].osd_destructors = realloc(osdm[type].osd_destructors,
+ sizeof(osd_destructor_t) * osdm[type].osd_ntslots, M_OSD,
M_NOWAIT | M_ZERO);
- if (osd_nmethods[type] != 0)
- osd_methods[type] = realloc(osd_methods[type],
- sizeof(osd_method_t) * osd_nslots[type] *
- osd_nmethods[type], M_OSD, M_NOWAIT | M_ZERO);
+ if (osdm[type].osd_nmethods != 0)
+ osdm[type].osd_methods = realloc(osdm[type].osd_methods,
+ sizeof(osd_method_t) * osdm[type].osd_ntslots *
+ osdm[type].osd_nmethods, M_OSD, M_NOWAIT | M_ZERO);
/*
* We always reallocate to smaller size, so we assume it will
* always succeed.
*/
- KASSERT(osd_destructors[type] != NULL &&
- (osd_nmethods[type] == 0 || osd_methods[type] != NULL),
- ("realloc() failed"));
+ KASSERT(osdm[type].osd_destructors != NULL &&
+ (osdm[type].osd_nmethods == 0 ||
+ osdm[type].osd_methods != NULL), ("realloc() failed"));
OSD_DEBUG("Deregistration of the last slot (type=%u, slot=%u).",
type, slot);
} else {
OSD_DEBUG("Slot deregistration (type=%u, slot=%u).",
type, slot);
}
- rm_wunlock(&osd_object_lock[type]);
- sx_xunlock(&osd_module_lock[type]);
+ rm_wunlock(&osdm[type].osd_object_lock);
+ sx_xunlock(&osdm[type].osd_module_lock);
}
int
osd_set(u_int type, struct osd *osd, u_int slot, void *value)
{
+
+ return (osd_set_reserved(type, osd, slot, NULL, value));
+}
+
+void *
+osd_reserve(u_int slot)
+{
+
+ KASSERT(slot > 0, ("Invalid slot."));
+
+ OSD_DEBUG("Reserving slot array (slot=%u).", slot);
+ return (malloc(sizeof(void *) * slot, M_OSD, M_WAITOK | M_ZERO));
+}
+
+int
+osd_set_reserved(u_int type, struct osd *osd, u_int slot, void *rsv,
+ void *value)
+{
struct rm_priotracker tracker;
KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
KASSERT(slot > 0, ("Invalid slot."));
- KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot."));
+ KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
- rm_rlock(&osd_object_lock[type], &tracker);
+ rm_rlock(&osdm[type].osd_object_lock, &tracker);
if (slot > osd->osd_nslots) {
+ void *newptr;
+
if (value == NULL) {
OSD_DEBUG(
"Not allocating null slot (type=%u, slot=%u).",
type, slot);
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock, &tracker);
+ if (rsv)
+ osd_free_reserved(rsv);
return (0);
- } else if (osd->osd_nslots == 0) {
+ }
+
+ /*
+ * Too few slots allocated here, so we need to extend or create
+ * the array.
+ */
+ if (rsv) {
/*
- * First OSD for this object, so we need to allocate
- * space and put it onto the list.
+ * Use the reserve passed in (assumed to be
+ * the right size).
*/
- osd->osd_slots = malloc(sizeof(void *) * slot, M_OSD,
- M_NOWAIT | M_ZERO);
- if (osd->osd_slots == NULL) {
- rm_runlock(&osd_object_lock[type], &tracker);
- return (ENOMEM);
+ newptr = rsv;
+ if (osd->osd_nslots != 0) {
+ memcpy(newptr, osd->osd_slots,
+ sizeof(void *) * osd->osd_nslots);
+ free(osd->osd_slots, M_OSD);
}
- osd->osd_nslots = slot;
- mtx_lock(&osd_list_lock[type]);
- LIST_INSERT_HEAD(&osd_list[type], osd, osd_next);
- mtx_unlock(&osd_list_lock[type]);
- OSD_DEBUG("Setting first slot (type=%u).", type);
} else {
- void *newptr;
-
- /*
- * Too few slots allocated here, needs to extend
- * the array.
- */
newptr = realloc(osd->osd_slots, sizeof(void *) * slot,
M_OSD, M_NOWAIT | M_ZERO);
if (newptr == NULL) {
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock,
+ &tracker);
return (ENOMEM);
}
- osd->osd_slots = newptr;
- osd->osd_nslots = slot;
- OSD_DEBUG("Growing slots array (type=%u).", type);
}
- }
+ if (osd->osd_nslots == 0) {
+ /*
+ * First OSD for this object, so we need to put it
+ * onto the list.
+ */
+ mtx_lock(&osdm[type].osd_list_lock);
+ LIST_INSERT_HEAD(&osdm[type].osd_list, osd, osd_next);
+ mtx_unlock(&osdm[type].osd_list_lock);
+ OSD_DEBUG("Setting first slot (type=%u).", type);
+ } else
+ OSD_DEBUG("Growing slots array (type=%u).", type);
+ osd->osd_slots = newptr;
+ osd->osd_nslots = slot;
+ } else if (rsv)
+ osd_free_reserved(rsv);
OSD_DEBUG("Setting slot value (type=%u, slot=%u, value=%p).", type,
slot, value);
osd->osd_slots[slot - 1] = value;
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock, &tracker);
return (0);
}
+void
+osd_free_reserved(void *rsv)
+{
+
+ OSD_DEBUG("Discarding reserved slot array.");
+ free(rsv, M_OSD);
+}
+
void *
osd_get(u_int type, struct osd *osd, u_int slot)
{
@@ -257,9 +298,9 @@ osd_get(u_int type, struct osd *osd, u_int slot)
KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
KASSERT(slot > 0, ("Invalid slot."));
- KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot."));
+ KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
- rm_rlock(&osd_object_lock[type], &tracker);
+ rm_rlock(&osdm[type].osd_object_lock, &tracker);
if (slot > osd->osd_nslots) {
value = NULL;
OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot);
@@ -268,7 +309,7 @@ osd_get(u_int type, struct osd *osd, u_int slot)
OSD_DEBUG("Returning slot value (type=%u, slot=%u, value=%p).",
type, slot, value);
}
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock, &tracker);
return (value);
}
@@ -277,9 +318,9 @@ osd_del(u_int type, struct osd *osd, u_int slot)
{
struct rm_priotracker tracker;
- rm_rlock(&osd_object_lock[type], &tracker);
+ rm_rlock(&osdm[type].osd_object_lock, &tracker);
do_osd_del(type, osd, slot, 0);
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock, &tracker);
}
static void
@@ -289,7 +330,7 @@ do_osd_del(u_int type, struct osd *osd, u_int slot, int list_locked)
KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
KASSERT(slot > 0, ("Invalid slot."));
- KASSERT(osd_destructors[type][slot - 1] != NULL, ("Unused slot."));
+ KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
OSD_DEBUG("Deleting slot (type=%u, slot=%u).", type, slot);
@@ -298,7 +339,7 @@ do_osd_del(u_int type, struct osd *osd, u_int slot, int list_locked)
return;
}
if (osd->osd_slots[slot - 1] != NULL) {
- osd_destructors[type][slot - 1](osd->osd_slots[slot - 1]);
+ osdm[type].osd_destructors[slot - 1](osd->osd_slots[slot - 1]);
osd->osd_slots[slot - 1] = NULL;
}
for (i = osd->osd_nslots - 1; i >= 0; i--) {
@@ -312,10 +353,10 @@ do_osd_del(u_int type, struct osd *osd, u_int slot, int list_locked)
/* No values left for this object. */
OSD_DEBUG("No more slots left (type=%u).", type);
if (!list_locked)
- mtx_lock(&osd_list_lock[type]);
+ mtx_lock(&osdm[type].osd_list_lock);
LIST_REMOVE(osd, osd_next);
if (!list_locked)
- mtx_unlock(&osd_list_lock[type]);
+ mtx_unlock(&osdm[type].osd_list_lock);
free(osd->osd_slots, M_OSD);
osd->osd_slots = NULL;
osd->osd_nslots = 0;
@@ -341,21 +382,21 @@ osd_call(u_int type, u_int method, void *obj, void *data)
int error, i;
KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
- KASSERT(method < osd_nmethods[type], ("Invalid method."));
+ KASSERT(method < osdm[type].osd_nmethods, ("Invalid method."));
/*
* Call this method for every slot that defines it, stopping if an
* error is encountered.
*/
error = 0;
- sx_slock(&osd_module_lock[type]);
- for (i = 0; i < osd_nslots[type]; i++) {
- methodfun =
- osd_methods[type][i * osd_nmethods[type] + method];
+ sx_slock(&osdm[type].osd_module_lock);
+ for (i = 0; i < osdm[type].osd_ntslots; i++) {
+ methodfun = osdm[type].osd_methods[i * osdm[type].osd_nmethods +
+ method];
if (methodfun != NULL && (error = methodfun(obj, data)) != 0)
break;
}
- sx_sunlock(&osd_module_lock[type]);
+ sx_sunlock(&osdm[type].osd_module_lock);
return (error);
}
@@ -373,14 +414,14 @@ osd_exit(u_int type, struct osd *osd)
return;
}
- rm_rlock(&osd_object_lock[type], &tracker);
+ rm_rlock(&osdm[type].osd_object_lock, &tracker);
for (i = 1; i <= osd->osd_nslots; i++) {
- if (osd_destructors[type][i - 1] != NULL)
+ if (osdm[type].osd_destructors[i - 1] != NULL)
do_osd_del(type, osd, i, 0);
else
OSD_DEBUG("Unused slot (type=%u, slot=%u).", type, i);
}
- rm_runlock(&osd_object_lock[type], &tracker);
+ rm_runlock(&osdm[type].osd_object_lock, &tracker);
OSD_DEBUG("Object exit (type=%u).", type);
}
@@ -390,13 +431,13 @@ osd_init(void *arg __unused)
u_int i;
for (i = OSD_FIRST; i <= OSD_LAST; i++) {
- osd_nslots[i] = 0;
- LIST_INIT(&osd_list[i]);
- sx_init(&osd_module_lock[i], "osd_module");
- rm_init(&osd_object_lock[i], "osd_object");
- mtx_init(&osd_list_lock[i], "osd_list", NULL, MTX_DEF);
- osd_destructors[i] = NULL;
- osd_methods[i] = NULL;
+ sx_init(&osdm[i].osd_module_lock, "osd_module");
+ rm_init(&osdm[i].osd_object_lock, "osd_object");
+ mtx_init(&osdm[i].osd_list_lock, "osd_list", NULL, MTX_DEF);
+ LIST_INIT(&osdm[i].osd_list);
+ osdm[i].osd_destructors = NULL;
+ osdm[i].osd_ntslots = 0;
+ osdm[i].osd_methods = NULL;
}
}
SYSINIT(osd, SI_SUB_LOCK, SI_ORDER_ANY, osd_init, NULL);
diff --git a/sys/kern/kern_racct.c b/sys/kern/kern_racct.c
index 1c3c9d7..419c69e 100644
--- a/sys/kern/kern_racct.c
+++ b/sys/kern/kern_racct.c
@@ -114,6 +114,8 @@ SDT_PROBE_DEFINE3(racct, , rusage, set,
"struct proc *", "int", "uint64_t");
SDT_PROBE_DEFINE3(racct, , rusage, set__failure,
"struct proc *", "int", "uint64_t");
+SDT_PROBE_DEFINE3(racct, , rusage, set__force,
+ "struct proc *", "int", "uint64_t");
SDT_PROBE_DEFINE3(racct, , rusage, sub,
"struct proc *", "int", "uint64_t");
SDT_PROBE_DEFINE3(racct, , rusage, sub__cred,
@@ -532,7 +534,7 @@ racct_adjust_resource(struct racct *racct, int resource,
}
static int
-racct_add_locked(struct proc *p, int resource, uint64_t amount)
+racct_add_locked(struct proc *p, int resource, uint64_t amount, int force)
{
#ifdef RCTL
int error;
@@ -540,8 +542,6 @@ racct_add_locked(struct proc *p, int resource, uint64_t amount)
ASSERT_RACCT_ENABLED();
- SDT_PROBE3(racct, , rusage, add, p, resource, amount);
-
/*
* We need proc lock to dereference p->p_ucred.
*/
@@ -549,7 +549,7 @@ racct_add_locked(struct proc *p, int resource, uint64_t amount)
#ifdef RCTL
error = rctl_enforce(p, resource, amount);
- if (error && RACCT_IS_DENIABLE(resource)) {
+ if (error && !force && RACCT_IS_DENIABLE(resource)) {
SDT_PROBE3(racct, , rusage, add__failure, p, resource, amount);
return (error);
}
@@ -572,12 +572,32 @@ racct_add(struct proc *p, int resource, uint64_t amount)
if (!racct_enable)
return (0);
+ SDT_PROBE3(racct, , rusage, add, p, resource, amount);
+
mtx_lock(&racct_lock);
- error = racct_add_locked(p, resource, amount);
+ error = racct_add_locked(p, resource, amount, 0);
mtx_unlock(&racct_lock);
return (error);
}
+/*
+ * Increase allocation of 'resource' by 'amount' for process 'p'.
+ * Doesn't check for limits and never fails.
+ */
+void
+racct_add_force(struct proc *p, int resource, uint64_t amount)
+{
+
+ if (!racct_enable)
+ return;
+
+ SDT_PROBE3(racct, , rusage, add__force, p, resource, amount);
+
+ mtx_lock(&racct_lock);
+ racct_add_locked(p, resource, amount, 1);
+ mtx_unlock(&racct_lock);
+}
+
static void
racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount)
{
@@ -597,8 +617,6 @@ racct_add_cred_locked(struct ucred *cred, int resource, uint64_t amount)
/*
* Increase allocation of 'resource' by 'amount' for credential 'cred'.
* Doesn't check for limits and never fails.
- *
- * XXX: Shouldn't this ever return an error?
*/
void
racct_add_cred(struct ucred *cred, int resource, uint64_t amount)
@@ -612,32 +630,8 @@ racct_add_cred(struct ucred *cred, int resource, uint64_t amount)
mtx_unlock(&racct_lock);
}
-/*
- * Increase allocation of 'resource' by 'amount' for process 'p'.
- * Doesn't check for limits and never fails.
- */
-void
-racct_add_force(struct proc *p, int resource, uint64_t amount)
-{
-
- if (!racct_enable)
- return;
-
- SDT_PROBE3(racct, , rusage, add__force, p, resource, amount);
-
- /*
- * We need proc lock to dereference p->p_ucred.
- */
- PROC_LOCK_ASSERT(p, MA_OWNED);
-
- mtx_lock(&racct_lock);
- racct_adjust_resource(p->p_racct, resource, amount);
- racct_add_cred_locked(p->p_ucred, resource, amount);
- mtx_unlock(&racct_lock);
-}
-
static int
-racct_set_locked(struct proc *p, int resource, uint64_t amount)
+racct_set_locked(struct proc *p, int resource, uint64_t amount, int force)
{
int64_t old_amount, decayed_amount;
int64_t diff_proc, diff_cred;
@@ -647,8 +641,6 @@ racct_set_locked(struct proc *p, int resource, uint64_t amount)
ASSERT_RACCT_ENABLED();
- SDT_PROBE3(racct, , rusage, set, p, resource, amount);
-
/*
* We need proc lock to dereference p->p_ucred.
*/
@@ -678,7 +670,7 @@ racct_set_locked(struct proc *p, int resource, uint64_t amount)
#ifdef RCTL
if (diff_proc > 0) {
error = rctl_enforce(p, resource, diff_proc);
- if (error && RACCT_IS_DENIABLE(resource)) {
+ if (error && !force && RACCT_IS_DENIABLE(resource)) {
SDT_PROBE3(racct, , rusage, set__failure, p, resource,
amount);
return (error);
@@ -709,51 +701,14 @@ racct_set(struct proc *p, int resource, uint64_t amount)
if (!racct_enable)
return (0);
+ SDT_PROBE3(racct, , rusage, set__force, p, resource, amount);
+
mtx_lock(&racct_lock);
- error = racct_set_locked(p, resource, amount);
+ error = racct_set_locked(p, resource, amount, 0);
mtx_unlock(&racct_lock);
return (error);
}
-static void
-racct_set_force_locked(struct proc *p, int resource, uint64_t amount)
-{
- int64_t old_amount, decayed_amount;
- int64_t diff_proc, diff_cred;
-
- ASSERT_RACCT_ENABLED();
-
- SDT_PROBE3(racct, , rusage, set, p, resource, amount);
-
- /*
- * We need proc lock to dereference p->p_ucred.
- */
- PROC_LOCK_ASSERT(p, MA_OWNED);
-
- old_amount = p->p_racct->r_resources[resource];
- /*
- * The diffs may be negative.
- */
- diff_proc = amount - old_amount;
- if (RACCT_IS_DECAYING(resource)) {
- /*
- * Resources in per-credential racct containers may decay.
- * If this is the case, we need to calculate the difference
- * between the new amount and the proportional value of the
- * old amount that has decayed in the ucred racct containers.
- */
- decayed_amount = old_amount * RACCT_DECAY_FACTOR / FSCALE;
- diff_cred = amount - decayed_amount;
- } else
- diff_cred = diff_proc;
-
- racct_adjust_resource(p->p_racct, resource, diff_proc);
- if (diff_cred > 0)
- racct_add_cred_locked(p->p_ucred, resource, diff_cred);
- else if (diff_cred < 0)
- racct_sub_cred_locked(p->p_ucred, resource, -diff_cred);
-}
-
void
racct_set_force(struct proc *p, int resource, uint64_t amount)
{
@@ -761,8 +716,10 @@ racct_set_force(struct proc *p, int resource, uint64_t amount)
if (!racct_enable)
return;
+ SDT_PROBE3(racct, , rusage, set, p, resource, amount);
+
mtx_lock(&racct_lock);
- racct_set_force_locked(p, resource, amount);
+ racct_set_locked(p, resource, amount, 1);
mtx_unlock(&racct_lock);
}
@@ -930,13 +887,13 @@ racct_proc_fork(struct proc *parent, struct proc *child)
continue;
error = racct_set_locked(child, i,
- parent->p_racct->r_resources[i]);
+ parent->p_racct->r_resources[i], 0);
if (error != 0)
goto out;
}
- error = racct_add_locked(child, RACCT_NPROC, 1);
- error += racct_add_locked(child, RACCT_NTHR, 1);
+ error = racct_add_locked(child, RACCT_NPROC, 1, 0);
+ error += racct_add_locked(child, RACCT_NTHR, 1, 0);
out:
mtx_unlock(&racct_lock);
@@ -1002,7 +959,7 @@ racct_proc_exit(struct proc *p)
pct = racct_getpcpu(p, pct_estimate);
mtx_lock(&racct_lock);
- racct_set_locked(p, RACCT_CPU, runtime);
+ racct_set_locked(p, RACCT_CPU, runtime, 0);
racct_add_cred_locked(p->p_ucred, RACCT_PCTCPU, pct);
for (i = 0; i <= RACCT_MAX; i++) {
@@ -1010,7 +967,7 @@ racct_proc_exit(struct proc *p)
continue;
if (!RACCT_IS_RECLAIMABLE(i))
continue;
- racct_set_locked(p, i, 0);
+ racct_set_locked(p, i, 0, 0);
}
mtx_unlock(&racct_lock);
@@ -1150,23 +1107,21 @@ racct_proc_wakeup(struct proc *p)
}
static void
-racct_decay_resource(struct racct *racct, void * res, void* dummy)
+racct_decay_callback(struct racct *racct, void *dummy1, void *dummy2)
{
- int resource;
int64_t r_old, r_new;
ASSERT_RACCT_ENABLED();
mtx_assert(&racct_lock, MA_OWNED);
- resource = *(int *)res;
- r_old = racct->r_resources[resource];
+ r_old = racct->r_resources[RACCT_PCTCPU];
/* If there is nothing to decay, just exit. */
if (r_old <= 0)
return;
r_new = r_old * RACCT_DECAY_FACTOR / FSCALE;
- racct->r_resources[resource] = r_new;
+ racct->r_resources[RACCT_PCTCPU] = r_new;
}
static void
@@ -1184,17 +1139,17 @@ racct_decay_post(void)
}
static void
-racct_decay(int resource)
+racct_decay(void)
{
ASSERT_RACCT_ENABLED();
- ui_racct_foreach(racct_decay_resource, racct_decay_pre,
- racct_decay_post, &resource, NULL);
- loginclass_racct_foreach(racct_decay_resource, racct_decay_pre,
- racct_decay_post, &resource, NULL);
- prison_racct_foreach(racct_decay_resource, racct_decay_pre,
- racct_decay_post, &resource, NULL);
+ ui_racct_foreach(racct_decay_callback, racct_decay_pre,
+ racct_decay_post, NULL, NULL);
+ loginclass_racct_foreach(racct_decay_callback, racct_decay_pre,
+ racct_decay_post, NULL, NULL);
+ prison_racct_foreach(racct_decay_callback, racct_decay_pre,
+ racct_decay_post, NULL, NULL);
}
static void
@@ -1209,7 +1164,7 @@ racctd(void)
ASSERT_RACCT_ENABLED();
for (;;) {
- racct_decay(RACCT_PCTCPU);
+ racct_decay();
sx_slock(&allproc_lock);
@@ -1249,11 +1204,11 @@ racctd(void)
pct_estimate = 0;
pct = racct_getpcpu(p, pct_estimate);
mtx_lock(&racct_lock);
- racct_set_force_locked(p, RACCT_PCTCPU, pct);
- racct_set_locked(p, RACCT_CPU, runtime);
+ racct_set_locked(p, RACCT_PCTCPU, pct, 1);
+ racct_set_locked(p, RACCT_CPU, runtime, 0);
racct_set_locked(p, RACCT_WALLCLOCK,
(uint64_t)wallclock.tv_sec * 1000000 +
- wallclock.tv_usec);
+ wallclock.tv_usec, 0);
mtx_unlock(&racct_lock);
PROC_UNLOCK(p);
}
diff --git a/sys/kern/kern_rctl.c b/sys/kern/kern_rctl.c
index b0d3fd6..1970ed8 100644
--- a/sys/kern/kern_rctl.c
+++ b/sys/kern/kern_rctl.c
@@ -78,10 +78,16 @@ FEATURE(rctl, "Resource Limits");
#define RCTL_PCPU_SHIFT (10 * 1000000)
unsigned int rctl_maxbufsize = RCTL_MAX_OUTBUFSIZE;
+static int rctl_log_rate_limit = 10;
+static int rctl_devctl_rate_limit = 10;
SYSCTL_NODE(_kern_racct, OID_AUTO, rctl, CTLFLAG_RW, 0, "Resource Limits");
SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, maxbufsize, CTLFLAG_RWTUN,
&rctl_maxbufsize, 0, "Maximum output buffer size");
+SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, log_rate_limit, CTLFLAG_RW,
+ &rctl_log_rate_limit, 0, "Maximum number of log messages per second");
+SYSCTL_UINT(_kern_racct_rctl, OID_AUTO, devctl_rate_limit, CTLFLAG_RW,
+ &rctl_devctl_rate_limit, 0, "Maximum number of devctl messages per second");
/*
* 'rctl_rule_link' connects a rule with every racct it's related to.
@@ -219,43 +225,43 @@ rctl_resource_name(int resource)
panic("rctl_resource_name: unknown resource %d", resource);
}
-/*
- * Return the amount of resource that can be allocated by 'p' before
- * hitting 'rule'.
- */
-static int64_t
-rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
+static struct racct *
+rctl_proc_rule_to_racct(const struct proc *p, const struct rctl_rule *rule)
{
- int resource;
- int64_t available = INT64_MAX;
struct ucred *cred = p->p_ucred;
ASSERT_RACCT_ENABLED();
rw_assert(&rctl_lock, RA_LOCKED);
- resource = rule->rr_resource;
switch (rule->rr_per) {
case RCTL_SUBJECT_TYPE_PROCESS:
- available = rule->rr_amount -
- p->p_racct->r_resources[resource];
- break;
+ return (p->p_racct);
case RCTL_SUBJECT_TYPE_USER:
- available = rule->rr_amount -
- cred->cr_ruidinfo->ui_racct->r_resources[resource];
- break;
+ return (cred->cr_ruidinfo->ui_racct);
case RCTL_SUBJECT_TYPE_LOGINCLASS:
- available = rule->rr_amount -
- cred->cr_loginclass->lc_racct->r_resources[resource];
- break;
+ return (cred->cr_loginclass->lc_racct);
case RCTL_SUBJECT_TYPE_JAIL:
- available = rule->rr_amount -
- cred->cr_prison->pr_prison_racct->prr_racct->
- r_resources[resource];
- break;
+ return (cred->cr_prison->pr_prison_racct->prr_racct);
default:
- panic("rctl_compute_available: unknown per %d",
- rule->rr_per);
+ panic("%s: unknown per %d", __func__, rule->rr_per);
}
+}
+
+/*
+ * Return the amount of resource that can be allocated by 'p' before
+ * hitting 'rule'.
+ */
+static int64_t
+rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
+{
+ int64_t available;
+ const struct racct *racct;
+
+ ASSERT_RACCT_ENABLED();
+ rw_assert(&rctl_lock, RA_LOCKED);
+
+ racct = rctl_proc_rule_to_racct(p, rule);
+ available = rule->rr_amount - racct->r_resources[rule->rr_resource];
return (available);
}
@@ -336,13 +342,13 @@ rctl_pcpu_available(const struct proc *p) {
int
rctl_enforce(struct proc *p, int resource, uint64_t amount)
{
+ static struct timeval log_lasttime, devctl_lasttime;
+ static int log_curtime = 0, devctl_curtime = 0;
struct rctl_rule *rule;
struct rctl_rule_link *link;
struct sbuf sb;
int should_deny = 0;
char *buf;
- static int curtime = 0;
- static struct timeval lasttime;
ASSERT_RACCT_ENABLED();
@@ -383,7 +389,8 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount)
if (p->p_state != PRS_NORMAL)
continue;
- if (!ppsratecheck(&lasttime, &curtime, 10))
+ if (!ppsratecheck(&log_lasttime, &log_curtime,
+ rctl_log_rate_limit))
continue;
buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
@@ -409,6 +416,10 @@ rctl_enforce(struct proc *p, int resource, uint64_t amount)
if (p->p_state != PRS_NORMAL)
continue;
+ if (!ppsratecheck(&devctl_lasttime, &devctl_curtime,
+ rctl_devctl_rate_limit))
+ continue;
+
buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
if (buf == NULL) {
printf("rctl_enforce: out of memory\n");
@@ -642,6 +653,9 @@ str2int64(const char *str, int64_t *value)
if ((size_t)(end - str) != strlen(str))
return (EINVAL);
+ if (*value < 0)
+ return (ERANGE);
+
return (0);
}
@@ -1008,8 +1022,13 @@ rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
error = str2int64(amountstr, &rule->rr_amount);
if (error != 0)
goto out;
- if (RACCT_IS_IN_MILLIONS(rule->rr_resource))
+ if (RACCT_IS_IN_MILLIONS(rule->rr_resource)) {
+ if (rule->rr_amount > INT64_MAX / 1000000) {
+ error = ERANGE;
+ goto out;
+ }
rule->rr_amount *= 1000000;
+ }
}
if (perstr == NULL || perstr[0] == '\0')
diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index a2e1311..7ee7780 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -516,7 +516,7 @@ sendfile_getsock(struct thread *td, int s, struct file **sock_fp,
int
vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
- int kflags, struct thread *td)
+ struct thread *td)
{
struct file *sock_fp;
struct vnode *vp;
@@ -534,7 +534,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
so = NULL;
m = mh = NULL;
sfs = NULL;
- sbytes = 0;
+ hdrlen = sbytes = 0;
softerr = 0;
error = sendfile_getobj(td, fp, &obj, &vp, &shmfd, &obj_size, &bsize);
@@ -560,26 +560,6 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
cv_init(&sfs->cv, "sendfile");
}
- /* If headers are specified copy them into mbufs. */
- if (hdr_uio != NULL && hdr_uio->uio_resid > 0) {
- hdr_uio->uio_td = td;
- hdr_uio->uio_rw = UIO_WRITE;
- /*
- * In FBSD < 5.0 the nbytes to send also included
- * the header. If compat is specified subtract the
- * header size from nbytes.
- */
- if (kflags & SFK_COMPAT) {
- if (nbytes > hdr_uio->uio_resid)
- nbytes -= hdr_uio->uio_resid;
- else
- nbytes = 0;
- }
- mh = m_uiotombuf(hdr_uio, M_WAITOK, 0, 0, 0);
- hdrlen = m_length(mh, &mhtail);
- } else
- hdrlen = 0;
-
rem = nbytes ? omin(nbytes, obj_size - offset) : obj_size - offset;
/*
@@ -668,11 +648,20 @@ retry_space:
SOCKBUF_UNLOCK(&so->so_snd);
/*
- * Reduce space in the socket buffer by the size of
- * the header mbuf chain.
- * hdrlen is set to 0 after the first loop.
+ * At the beginning of the first loop check if any headers
+ * are specified and copy them into mbufs. Reduce space in
+ * the socket buffer by the size of the header mbuf chain.
+ * Clear hdr_uio here and hdrlen at the end of the first loop.
*/
- space -= hdrlen;
+ if (hdr_uio != NULL && hdr_uio->uio_resid > 0) {
+ hdr_uio->uio_td = td;
+ hdr_uio->uio_rw = UIO_WRITE;
+ hdr_uio->uio_resid = min(hdr_uio->uio_resid, space);
+ mh = m_uiotombuf(hdr_uio, M_WAITOK, 0, 0, 0);
+ hdrlen = m_length(mh, &mhtail);
+ space -= hdrlen;
+ hdr_uio = NULL;
+ }
if (vp != NULL) {
error = vn_lock(vp, LK_SHARED);
@@ -944,6 +933,19 @@ sendfile(struct thread *td, struct sendfile_args *uap, int compat)
&hdr_uio);
if (error != 0)
goto out;
+#ifdef COMPAT_FREEBSD4
+ /*
+ * In FreeBSD < 5.0 the nbytes to send also included
+ * the header. If compat is specified subtract the
+ * header size from nbytes.
+ */
+ if (compat) {
+ if (uap->nbytes > hdr_uio->uio_resid)
+ uap->nbytes -= hdr_uio->uio_resid;
+ else
+ uap->nbytes = 0;
+ }
+#endif
}
if (hdtr.trailers != NULL) {
error = copyinuio(hdtr.trailers, hdtr.trl_cnt,
@@ -965,7 +967,7 @@ sendfile(struct thread *td, struct sendfile_args *uap, int compat)
}
error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset,
- uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
+ uap->nbytes, &sbytes, uap->flags, td);
fdrop(fp, td);
if (uap->sbytes != NULL)
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index 8c84773..c9932f56 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -162,15 +162,7 @@ _sleep(void *ident, struct lock_object *lock, int priority,
else
class = NULL;
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * During autoconfiguration, just return;
- * don't run any other threads or panic below,
- * in case this is the idle thread and already asleep.
- * XXX: this used to do "s = splhigh(); splx(safepri);
- * splx(s);" to give interrupts a chance, but there is
- * no way to give interrupts a chance now.
- */
+ if (SCHEDULER_STOPPED()) {
if (lock != NULL && priority & PDROP)
class->lc_unlock(lock);
return (0);
@@ -264,17 +256,8 @@ msleep_spin_sbt(void *ident, struct mtx *mtx, const char *wmesg,
KASSERT(p != NULL, ("msleep1"));
KASSERT(ident != NULL && TD_IS_RUNNING(td), ("msleep"));
- if (cold || SCHEDULER_STOPPED()) {
- /*
- * During autoconfiguration, just return;
- * don't run any other threads or panic below,
- * in case this is the idle thread and already asleep.
- * XXX: this used to do "s = splhigh(); splx(safepri);
- * splx(s);" to give interrupts a chance, but there is
- * no way to give interrupts a chance now.
- */
+ if (SCHEDULER_STOPPED())
return (0);
- }
sleepq_lock(ident);
CTR5(KTR_PROC, "msleep_spin: thread %ld (pid %ld, %s) on %s (%p)",
@@ -438,8 +421,10 @@ mi_switch(int flags, struct thread *newtd)
if (flags & SW_VOL) {
td->td_ru.ru_nvcsw++;
td->td_swvoltick = ticks;
- } else
+ } else {
td->td_ru.ru_nivcsw++;
+ td->td_swinvoltick = ticks;
+ }
#ifdef SCHED_STATS
SCHED_STAT_INC(sched_switch_stats[flags & SW_TYPE_MASK]);
#endif
diff --git a/sys/kern/pic_if.m b/sys/kern/pic_if.m
index 2309f0c..3003c35 100644
--- a/sys/kern/pic_if.m
+++ b/sys/kern/pic_if.m
@@ -1,7 +1,6 @@
#-
-# Copyright (c) 2012 Jakub Wojciech Klama <jceel@FreeBSD.org>
-# Copyright (c) 2015 Svatopluk Kraus
-# Copyright (c) 2015 Michal Meloun
+# Copyright (c) 2015-2016 Svatopluk Kraus
+# Copyright (c) 2015-2016 Michal Meloun
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -30,88 +29,132 @@
#include <sys/bus.h>
#include <sys/cpuset.h>
-#include <machine/frame.h>
-#include <machine/intr.h>
+#include <sys/resource.h>
+#include <sys/intr.h>
INTERFACE pic;
CODE {
- static int null_pic_bind(device_t dev, struct intr_irqsrc *isrc)
+ static int
+ dflt_pic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
{
+
return (EOPNOTSUPP);
}
- static void null_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
+ static int
+ null_pic_alloc_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+ {
+
+ return (0);
+ }
+
+ static int
+ null_pic_release_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
+ {
+
+ return (0);
+ }
+
+ static int
+ null_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
- return;
+
+ return (0);
}
- static void null_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
+ static int
+ null_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
+ struct resource *res, struct intr_map_data *data)
{
- return;
+
+ return (0);
}
- static void null_pic_init_secondary(device_t dev)
+ static void
+ null_pic_init_secondary(device_t dev)
{
- return;
}
- static void null_pic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
+ static void
+ null_pic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
{
- return;
+ }
+
+ static int
+ dflt_pic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc)
+ {
+
+ return (EOPNOTSUPP);
}
};
-METHOD int register {
+METHOD int alloc_intr {
device_t dev;
struct intr_irqsrc *isrc;
- boolean_t *is_percpu;
-};
+ struct resource *res;
+ struct intr_map_data *data;
+} DEFAULT null_pic_alloc_intr;
-METHOD int unregister {
+METHOD int bind_intr {
device_t dev;
struct intr_irqsrc *isrc;
-};
+} DEFAULT dflt_pic_bind_intr;
METHOD void disable_intr {
device_t dev;
struct intr_irqsrc *isrc;
-} DEFAULT null_pic_disable_intr;
+};
-METHOD void disable_source {
+METHOD void enable_intr {
device_t dev;
struct intr_irqsrc *isrc;
};
-METHOD void enable_source {
+METHOD int map_intr {
device_t dev;
- struct intr_irqsrc *isrc;
+ struct intr_map_data *data;
+ struct intr_irqsrc **isrcp;
};
-METHOD void enable_intr {
+METHOD int release_intr {
device_t dev;
struct intr_irqsrc *isrc;
-} DEFAULT null_pic_enable_intr;
+ struct resource *res;
+ struct intr_map_data *data;
+} DEFAULT null_pic_release_intr;
-METHOD void pre_ithread {
+METHOD int setup_intr {
device_t dev;
struct intr_irqsrc *isrc;
-};
+ struct resource *res;
+ struct intr_map_data *data;
+} DEFAULT null_pic_setup_intr;
-METHOD void post_ithread {
+METHOD int teardown_intr {
device_t dev;
struct intr_irqsrc *isrc;
-};
+ struct resource *res;
+ struct intr_map_data *data;
+} DEFAULT null_pic_teardown_intr;
METHOD void post_filter {
device_t dev;
struct intr_irqsrc *isrc;
};
-METHOD int bind {
+METHOD void post_ithread {
device_t dev;
struct intr_irqsrc *isrc;
-} DEFAULT null_pic_bind;
+};
+
+METHOD void pre_ithread {
+ device_t dev;
+ struct intr_irqsrc *isrc;
+};
METHOD void init_secondary {
device_t dev;
@@ -121,4 +164,11 @@ METHOD void ipi_send {
device_t dev;
struct intr_irqsrc *isrc;
cpuset_t cpus;
+ u_int ipi;
} DEFAULT null_pic_ipi_send;
+
+METHOD int ipi_setup {
+ device_t dev;
+ u_int ipi;
+ struct intr_irqsrc **isrcp;
+} DEFAULT dflt_pic_ipi_setup;
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 8daa9f2..caf9202 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -839,6 +839,38 @@ sysctl_devctl_queue(SYSCTL_HANDLER_ARGS)
return (0);
}
+/**
+ * @brief safely quotes strings that might have double quotes in them.
+ *
+ * The devctl protocol relies on quoted strings having matching quotes.
+ * This routine quotes any internal quotes so the resulting string
+ * is safe to pass to snprintf to construct, for example pnp info strings.
+ * Strings are always terminated with a NUL, but may be truncated if longer
+ * than @p len bytes after quotes.
+ *
+ * @param dst Buffer to hold the string. Must be at least @p len bytes long
+ * @param src Original buffer.
+ * @param len Length of buffer pointed to by @dst, including trailing NUL
+ */
+void
+devctl_safe_quote(char *dst, const char *src, size_t len)
+{
+ char *walker = dst, *ep = dst + len - 1;
+
+ if (len == 0)
+ return;
+ while (src != NULL && walker < ep)
+ {
+ if (*src == '"') {
+ if (ep - walker < 2)
+ break;
+ *walker++ = '\\';
+ }
+ *walker++ = *src++;
+ }
+ *walker = '\0';
+}
+
/* End of /dev/devctl code */
static TAILQ_HEAD(,device) bus_data_devices;
diff --git a/sys/kern/subr_counter.c b/sys/kern/subr_counter.c
index ea2759c..5149f2d 100644
--- a/sys/kern/subr_counter.c
+++ b/sys/kern/subr_counter.c
@@ -94,3 +94,28 @@ sysctl_handle_counter_u64(SYSCTL_HANDLER_ARGS)
return (0);
}
+
+int
+sysctl_handle_counter_u64_array(SYSCTL_HANDLER_ARGS)
+{
+ uint64_t *out;
+ int error;
+
+ out = malloc(arg2 * sizeof(uint64_t), M_TEMP, M_WAITOK);
+ for (int i = 0; i < arg2; i++)
+ out[i] = counter_u64_fetch(((counter_u64_t *)arg1)[i]);
+
+ error = SYSCTL_OUT(req, out, arg2 * sizeof(uint64_t));
+ free(out, M_TEMP);
+
+ if (error || !req->newptr)
+ return (error);
+
+ /*
+ * Any write attempt to a counter zeroes it.
+ */
+ for (int i = 0; i < arg2; i++)
+ counter_u64_zero(((counter_u64_t *)arg1)[i]);
+
+ return (0);
+}
diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index 1c97fd4..96319ad 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -1,7 +1,6 @@
/*-
- * Copyright (c) 2012-2014 Jakub Wojciech Klama <jceel@FreeBSD.org>.
- * Copyright (c) 2015 Svatopluk Kraus
- * Copyright (c) 2015 Michal Meloun
+ * Copyright (c) 2015-2016 Svatopluk Kraus
+ * Copyright (c) 2015-2016 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/cdefs.h>
@@ -38,6 +35,7 @@ __FBSDID("$FreeBSD$");
* - to complete things for removable PICs
*/
+#include "opt_acpi.h"
#include "opt_ddb.h"
#include "opt_platform.h"
@@ -52,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/interrupt.h>
#include <sys/conf.h>
#include <sys/cpuset.h>
+#include <sys/rman.h>
#include <sys/sched.h>
#include <sys/smp.h>
#include <machine/atomic.h>
@@ -112,6 +111,35 @@ u_int irq_next_free;
#define IRQ_INVALID nitems(irq_sources)
+/*
+ * XXX - All stuff around struct intr_dev_data is considered as temporary
+ * until better place for storing struct intr_map_data will be find.
+ *
+ * For now, there are two global interrupt numbers spaces:
+ * <0, NIRQ) ... interrupts without config data
+ * managed in irq_sources[]
+ * IRQ_DDATA_BASE + <0, 2 * NIRQ) ... interrupts with config data
+ * managed in intr_ddata_tab[]
+ *
+ * Read intr_ddata_lookup() to see how these spaces are worked with.
+ * Note that each interrupt number from second space duplicates some number
+ * from first space at this moment. An interrupt number from first space can
+ * be duplicated even multiple times in second space.
+ */
+struct intr_dev_data {
+ device_t idd_dev;
+ intptr_t idd_xref;
+ u_int idd_irq;
+ struct intr_map_data idd_data;
+ struct intr_irqsrc * idd_isrc;
+};
+
+static struct intr_dev_data *intr_ddata_tab[2 * NIRQ];
+static u_int intr_ddata_first_unused;
+
+#define IRQ_DDATA_BASE 10000
+CTASSERT(IRQ_DDATA_BASE > IRQ_INVALID);
+
#ifdef SMP
static boolean_t irq_assign_cpu = FALSE;
#endif
@@ -173,12 +201,10 @@ static inline void
isrc_increment_count(struct intr_irqsrc *isrc)
{
- /*
- * XXX - It should be atomic for PPI interrupts. It was proven that
- * the lost is measurable easily for timer PPI interrupts.
- */
- isrc->isrc_count[0]++;
- /*atomic_add_long(&isrc->isrc_count[0], 1);*/
+ if (isrc->isrc_flags & INTR_ISRCF_PPI)
+ atomic_add_long(&isrc->isrc_count[0], 1);
+ else
+ isrc->isrc_count[0]++;
}
/*
@@ -233,6 +259,16 @@ isrc_setup_counters(struct intr_irqsrc *isrc)
isrc_update_name(isrc, NULL);
}
+/*
+ * Virtualization for interrupt source interrupt counters release.
+ */
+static void
+isrc_release_counters(struct intr_irqsrc *isrc)
+{
+
+ panic("%s: not implemented", __func__);
+}
+
#ifdef SMP
/*
* Virtualization for interrupt source IPI counters setup.
@@ -279,8 +315,8 @@ intr_irq_handler(struct trapframe *tf)
* be called straight from the interrupt controller, when associated interrupt
* source is learned.
*/
-void
-intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
+int
+intr_isrc_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
{
KASSERT(isrc != NULL, ("%s: no source", __func__));
@@ -293,57 +329,16 @@ intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
error = isrc->isrc_filter(isrc->isrc_arg, tf);
PIC_POST_FILTER(isrc->isrc_dev, isrc);
if (error == FILTER_HANDLED)
- return;
- } else
+ return (0);
+ } else
#endif
if (isrc->isrc_event != NULL) {
if (intr_event_handle(isrc->isrc_event, tf) == 0)
- return;
+ return (0);
}
isrc_increment_straycount(isrc);
- PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
-
- device_printf(isrc->isrc_dev, "stray irq <%s> disabled",
- isrc->isrc_name);
-}
-
-/*
- * Allocate interrupt source.
- */
-static struct intr_irqsrc *
-isrc_alloc(u_int type, u_int extsize)
-{
- struct intr_irqsrc *isrc;
-
- isrc = malloc(sizeof(*isrc) + extsize, M_INTRNG, M_WAITOK | M_ZERO);
- isrc->isrc_irq = IRQ_INVALID; /* just to be safe */
- isrc->isrc_type = type;
- isrc->isrc_nspc_type = INTR_IRQ_NSPC_NONE;
- isrc->isrc_trig = INTR_TRIGGER_CONFORM;
- isrc->isrc_pol = INTR_POLARITY_CONFORM;
- CPU_ZERO(&isrc->isrc_cpu);
- return (isrc);
-}
-
-/*
- * Free interrupt source.
- */
-static void
-isrc_free(struct intr_irqsrc *isrc)
-{
-
- free(isrc, M_INTRNG);
-}
-
-void
-intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap);
- va_end(ap);
+ return (EINVAL);
}
/*
@@ -356,8 +351,8 @@ intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
* immediately. However, if only one free handle left which is reused
* constantly...
*/
-static int
-isrc_alloc_irq_locked(struct intr_irqsrc *isrc)
+static inline int
+isrc_alloc_irq(struct intr_irqsrc *isrc)
{
u_int maxirqs, irq;
@@ -383,46 +378,35 @@ found:
isrc->isrc_irq = irq;
irq_sources[irq] = isrc;
- intr_irq_set_name(isrc, "irq%u", irq);
- isrc_setup_counters(isrc);
-
irq_next_free = irq + 1;
if (irq_next_free >= maxirqs)
irq_next_free = 0;
return (0);
}
-#ifdef notyet
+
/*
* Free unique interrupt number (resource handle) from interrupt source.
*/
-static int
+static inline int
isrc_free_irq(struct intr_irqsrc *isrc)
{
- u_int maxirqs;
- mtx_assert(&isrc_table_lock, MA_NOTOWNED);
+ mtx_assert(&isrc_table_lock, MA_OWNED);
- maxirqs = nitems(irq_sources);
- if (isrc->isrc_irq >= maxirqs)
+ if (isrc->isrc_irq >= nitems(irq_sources))
return (EINVAL);
-
- mtx_lock(&isrc_table_lock);
- if (irq_sources[isrc->isrc_irq] != isrc) {
- mtx_unlock(&isrc_table_lock);
+ if (irq_sources[isrc->isrc_irq] != isrc)
return (EINVAL);
- }
irq_sources[isrc->isrc_irq] = NULL;
isrc->isrc_irq = IRQ_INVALID; /* just to be safe */
- mtx_unlock(&isrc_table_lock);
-
return (0);
}
-#endif
+
/*
* Lookup interrupt source by interrupt number (resource handle).
*/
-static struct intr_irqsrc *
+static inline struct intr_irqsrc *
isrc_lookup(u_int irq)
{
@@ -432,158 +416,159 @@ isrc_lookup(u_int irq)
}
/*
- * Lookup interrupt source by namespace description.
+ * Initialize interrupt source and register it into global interrupt table.
*/
-static struct intr_irqsrc *
-isrc_namespace_lookup(device_t dev, uint16_t type, uint16_t num)
+int
+intr_isrc_register(struct intr_irqsrc *isrc, device_t dev, u_int flags,
+ const char *fmt, ...)
{
- u_int irq;
- struct intr_irqsrc *isrc;
+ int error;
+ va_list ap;
- mtx_assert(&isrc_table_lock, MA_OWNED);
+ bzero(isrc, sizeof(struct intr_irqsrc));
+ isrc->isrc_dev = dev;
+ isrc->isrc_irq = IRQ_INVALID; /* just to be safe */
+ isrc->isrc_flags = flags;
+
+ va_start(ap, fmt);
+ vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap);
+ va_end(ap);
- for (irq = 0; irq < nitems(irq_sources); irq++) {
- isrc = irq_sources[irq];
- if (isrc != NULL && isrc->isrc_dev == dev &&
- isrc->isrc_nspc_type == type && isrc->isrc_nspc_num == num)
- return (isrc);
+ mtx_lock(&isrc_table_lock);
+ error = isrc_alloc_irq(isrc);
+ if (error != 0) {
+ mtx_unlock(&isrc_table_lock);
+ return (error);
}
- return (NULL);
+ /*
+ * Setup interrupt counters, but not for IPI sources. Those are setup
+ * later and only for used ones (up to INTR_IPI_COUNT) to not exhaust
+ * our counter pool.
+ */
+ if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0)
+ isrc_setup_counters(isrc);
+ mtx_unlock(&isrc_table_lock);
+ return (0);
}
/*
- * Map interrupt source according to namespace into framework. If such mapping
- * does not exist, create it. Return unique interrupt number (resource handle)
- * associated with mapped interrupt source.
+ * Deregister interrupt source from global interrupt table.
*/
-u_int
-intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num)
+int
+intr_isrc_deregister(struct intr_irqsrc *isrc)
{
- struct intr_irqsrc *isrc, *new_isrc;
int error;
- new_isrc = isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
-
mtx_lock(&isrc_table_lock);
- isrc = isrc_namespace_lookup(dev, type, num);
- if (isrc != NULL) {
- mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
- return (isrc->isrc_irq); /* already mapped */
- }
+ if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0)
+ isrc_release_counters(isrc);
+ error = isrc_free_irq(isrc);
+ mtx_unlock(&isrc_table_lock);
+ return (error);
+}
- error = isrc_alloc_irq_locked(new_isrc);
- if (error != 0) {
+static struct intr_dev_data *
+intr_ddata_alloc(u_int extsize)
+{
+ struct intr_dev_data *ddata;
+
+ ddata = malloc(sizeof(*ddata) + extsize, M_INTRNG, M_WAITOK | M_ZERO);
+
+ mtx_lock(&isrc_table_lock);
+ if (intr_ddata_first_unused >= nitems(intr_ddata_tab)) {
mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
- return (IRQ_INVALID); /* no space left */
+ free(ddata, M_INTRNG);
+ return (NULL);
}
-
- new_isrc->isrc_dev = dev;
- new_isrc->isrc_nspc_type = type;
- new_isrc->isrc_nspc_num = num;
+ intr_ddata_tab[intr_ddata_first_unused] = ddata;
+ ddata->idd_irq = IRQ_DDATA_BASE + intr_ddata_first_unused++;
mtx_unlock(&isrc_table_lock);
-
- return (new_isrc->isrc_irq);
+ return (ddata);
}
-#ifdef FDT
-/*
- * Lookup interrupt source by FDT description.
- */
static struct intr_irqsrc *
-isrc_fdt_lookup(intptr_t xref, pcell_t *cells, u_int ncells)
+intr_ddata_lookup(u_int irq, struct intr_map_data **datap)
{
- u_int irq, cellsize;
+ int error;
struct intr_irqsrc *isrc;
+ struct intr_dev_data *ddata;
- mtx_assert(&isrc_table_lock, MA_OWNED);
+ isrc = isrc_lookup(irq);
+ if (isrc != NULL) {
+ if (datap != NULL)
+ *datap = NULL;
+ return (isrc);
+ }
- cellsize = ncells * sizeof(*cells);
- for (irq = 0; irq < nitems(irq_sources); irq++) {
- isrc = irq_sources[irq];
- if (isrc != NULL && isrc->isrc_type == INTR_ISRCT_FDT &&
- isrc->isrc_xref == xref && isrc->isrc_ncells == ncells &&
- memcmp(isrc->isrc_cells, cells, cellsize) == 0)
- return (isrc);
+ if (irq < IRQ_DDATA_BASE)
+ return (NULL);
+
+ irq -= IRQ_DDATA_BASE;
+ if (irq >= nitems(intr_ddata_tab))
+ return (NULL);
+
+ ddata = intr_ddata_tab[irq];
+ if (ddata->idd_isrc == NULL) {
+ error = intr_map_irq(ddata->idd_dev, ddata->idd_xref,
+ &ddata->idd_data, &irq);
+ if (error != 0)
+ return (NULL);
+ ddata->idd_isrc = isrc_lookup(irq);
}
- return (NULL);
+ if (datap != NULL)
+ *datap = &ddata->idd_data;
+ return (ddata->idd_isrc);
}
+#ifdef DEV_ACPI
/*
- * Map interrupt source according to FDT data into framework. If such mapping
+ * Map interrupt source according to ACPI info into framework. If such mapping
* does not exist, create it. Return unique interrupt number (resource handle)
* associated with mapped interrupt source.
*/
u_int
-intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells)
+intr_acpi_map_irq(device_t dev, u_int irq, enum intr_polarity pol,
+ enum intr_trigger trig)
{
- struct intr_irqsrc *isrc, *new_isrc;
- u_int cellsize;
- intptr_t xref;
- int error;
-
- xref = (intptr_t)node; /* It's so simple for now. */
-
- cellsize = ncells * sizeof(*cells);
- new_isrc = isrc_alloc(INTR_ISRCT_FDT, cellsize);
-
- mtx_lock(&isrc_table_lock);
- isrc = isrc_fdt_lookup(xref, cells, ncells);
- if (isrc != NULL) {
- mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
- return (isrc->isrc_irq); /* already mapped */
- }
-
- error = isrc_alloc_irq_locked(new_isrc);
- if (error != 0) {
- mtx_unlock(&isrc_table_lock);
- isrc_free(new_isrc);
- return (IRQ_INVALID); /* no space left */
- }
-
- new_isrc->isrc_xref = xref;
- new_isrc->isrc_ncells = ncells;
- memcpy(new_isrc->isrc_cells, cells, cellsize);
- mtx_unlock(&isrc_table_lock);
-
- return (new_isrc->isrc_irq);
+ struct intr_dev_data *ddata;
+
+ ddata = intr_ddata_alloc(0);
+ if (ddata == NULL)
+ return (0xFFFFFFFF); /* no space left */
+
+ ddata->idd_dev = dev;
+ ddata->idd_data.type = INTR_MAP_DATA_ACPI;
+ ddata->idd_data.acpi.irq = irq;
+ ddata->idd_data.acpi.pol = pol;
+ ddata->idd_data.acpi.trig = trig;
+ return (ddata->idd_irq);
}
#endif
-
+#ifdef FDT
/*
- * Register interrupt source into interrupt controller.
+ * Map interrupt source according to FDT data into framework. If such mapping
+ * does not exist, create it. Return unique interrupt number (resource handle)
+ * associated with mapped interrupt source.
*/
-static int
-isrc_register(struct intr_irqsrc *isrc)
+u_int
+intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells)
{
- struct intr_pic *pic;
- boolean_t is_percpu;
- int error;
-
- if (isrc->isrc_flags & INTR_ISRCF_REGISTERED)
- return (0);
-
- if (isrc->isrc_dev == NULL) {
- pic = pic_lookup(NULL, isrc->isrc_xref);
- if (pic == NULL || pic->pic_dev == NULL)
- return (ESRCH);
- isrc->isrc_dev = pic->pic_dev;
- }
-
- error = PIC_REGISTER(isrc->isrc_dev, isrc, &is_percpu);
- if (error != 0)
- return (error);
+ struct intr_dev_data *ddata;
+ u_int cellsize;
- mtx_lock(&isrc_table_lock);
- isrc->isrc_flags |= INTR_ISRCF_REGISTERED;
- if (is_percpu)
- isrc->isrc_flags |= INTR_ISRCF_PERCPU;
- isrc_update_name(isrc, NULL);
- mtx_unlock(&isrc_table_lock);
- return (0);
+ cellsize = ncells * sizeof(*cells);
+ ddata = intr_ddata_alloc(cellsize);
+ if (ddata == NULL)
+ return (0xFFFFFFFF); /* no space left */
+
+ ddata->idd_xref = (intptr_t)node;
+ ddata->idd_data.type = INTR_MAP_DATA_FDT;
+ ddata->idd_data.fdt.ncells = ncells;
+ ddata->idd_data.fdt.cells = (pcell_t *)(ddata + 1);
+ memcpy(ddata->idd_data.fdt.cells, cells, cellsize);
+ return (ddata->idd_irq);
}
+#endif
#ifdef INTR_SOLO
/*
@@ -678,7 +663,7 @@ intr_isrc_assign_cpu(void *arg, int cpu)
* informed if the call is successfull.
*/
if (irq_assign_cpu) {
- error = PIC_BIND(isrc->isrc_dev, isrc);
+ error = PIC_BIND_INTR(isrc->isrc_dev, isrc);
if (error) {
CPU_ZERO(&isrc->isrc_cpu);
mtx_unlock(&isrc_table_lock);
@@ -774,7 +759,7 @@ isrc_add_handler(struct intr_irqsrc *isrc, const char *name,
/*
* Lookup interrupt controller locked.
*/
-static struct intr_pic *
+static inline struct intr_pic *
pic_lookup_locked(device_t dev, intptr_t xref)
{
struct intr_pic *pic;
@@ -801,7 +786,6 @@ pic_lookup(device_t dev, intptr_t xref)
mtx_lock(&pic_list_lock);
pic = pic_lookup_locked(dev, xref);
mtx_unlock(&pic_list_lock);
-
return (pic);
}
@@ -871,7 +855,7 @@ intr_pic_register(device_t dev, intptr_t xref)
* Unregister interrupt controller.
*/
int
-intr_pic_unregister(device_t dev, intptr_t xref)
+intr_pic_deregister(device_t dev, intptr_t xref)
{
panic("%s: not implemented", __func__);
@@ -923,12 +907,73 @@ intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
}
int
-intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand,
- void *arg, u_int irq, int flags, void **cookiep)
+intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data,
+ u_int *irqp)
{
- const char *name;
+ int error;
+ struct intr_irqsrc *isrc;
+ struct intr_pic *pic;
+
+ if (data == NULL)
+ return (EINVAL);
+
+ pic = pic_lookup(dev, xref);
+ if (pic == NULL || pic->pic_dev == NULL)
+ return (ESRCH);
+
+ error = PIC_MAP_INTR(pic->pic_dev, data, &isrc);
+ if (error == 0)
+ *irqp = isrc->isrc_irq;
+ return (error);
+}
+
+int
+intr_alloc_irq(device_t dev, struct resource *res)
+{
+ struct intr_map_data *data;
+ struct intr_irqsrc *isrc;
+
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
+
+ isrc = intr_ddata_lookup(rman_get_start(res), &data);
+ if (isrc == NULL)
+ return (EINVAL);
+
+ return (PIC_ALLOC_INTR(isrc->isrc_dev, isrc, res, data));
+}
+
+int
+intr_release_irq(device_t dev, struct resource *res)
+{
+ struct intr_map_data *data;
struct intr_irqsrc *isrc;
+
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
+
+ isrc = intr_ddata_lookup(rman_get_start(res), &data);
+ if (isrc == NULL)
+ return (EINVAL);
+
+ return (PIC_RELEASE_INTR(isrc->isrc_dev, isrc, res, data));
+}
+
+int
+intr_setup_irq(device_t dev, struct resource *res, driver_filter_t filt,
+ driver_intr_t hand, void *arg, int flags, void **cookiep)
+{
int error;
+ struct intr_map_data *data;
+ struct intr_irqsrc *isrc;
+ const char *name;
+
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
+
+ isrc = intr_ddata_lookup(rman_get_start(res), &data);
+ if (isrc == NULL)
+ return (EINVAL);
name = device_get_nameunit(dev);
@@ -947,21 +992,7 @@ intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand,
debugf("irq %u cannot solo on %s\n", irq, name);
return (EINVAL);
}
-#endif
- isrc = isrc_lookup(irq);
- if (isrc == NULL) {
- debugf("irq %u without source on %s\n", irq, name);
- return (EINVAL);
- }
-
- error = isrc_register(isrc);
- if (error != 0) {
- debugf("irq %u map error %d on %s\n", irq, error, name);
- return (error);
- }
-
-#ifdef INTR_SOLO
if (flags & INTR_SOLO) {
error = iscr_setup_filter(isrc, name, (intr_irq_filter_t *)filt,
arg, cookiep);
@@ -978,24 +1009,32 @@ intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand,
return (error);
mtx_lock(&isrc_table_lock);
- isrc->isrc_handlers++;
- if (isrc->isrc_handlers == 1) {
- PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
- PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
+ error = PIC_SETUP_INTR(isrc->isrc_dev, isrc, res, data);
+ if (error == 0) {
+ isrc->isrc_handlers++;
+ if (isrc->isrc_handlers == 1)
+ PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
}
mtx_unlock(&isrc_table_lock);
- return (0);
+ if (error != 0)
+ intr_event_remove_handler(*cookiep);
+ return (error);
}
int
-intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
+intr_teardown_irq(device_t dev, struct resource *res, void *cookie)
{
- struct intr_irqsrc *isrc;
int error;
+ struct intr_map_data *data;
+ struct intr_irqsrc *isrc;
- isrc = isrc_lookup(irq);
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
+
+ isrc = intr_ddata_lookup(rman_get_start(res), &data);
if (isrc == NULL || isrc->isrc_handlers == 0)
return (EINVAL);
+
#ifdef INTR_SOLO
if (isrc->isrc_filter != NULL) {
if (isrc != cookie)
@@ -1005,8 +1044,8 @@ intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
isrc->isrc_filter = NULL;
isrc->isrc_arg = NULL;
isrc->isrc_handlers = 0;
- PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
PIC_DISABLE_INTR(isrc->isrc_dev, isrc);
+ PIC_TEARDOWN_INTR(isrc->isrc_dev, isrc, res, data);
isrc_update_name(isrc, NULL);
mtx_unlock(&isrc_table_lock);
return (0);
@@ -1019,10 +1058,9 @@ intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
if (error == 0) {
mtx_lock(&isrc_table_lock);
isrc->isrc_handlers--;
- if (isrc->isrc_handlers == 0) {
- PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
+ if (isrc->isrc_handlers == 0)
PIC_DISABLE_INTR(isrc->isrc_dev, isrc);
- }
+ PIC_TEARDOWN_INTR(isrc->isrc_dev, isrc, res, data);
intrcnt_updatename(isrc);
mtx_unlock(&isrc_table_lock);
}
@@ -1030,36 +1068,16 @@ intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
}
int
-intr_irq_config(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
+intr_describe_irq(device_t dev, struct resource *res, void *cookie,
+ const char *descr)
{
+ int error;
struct intr_irqsrc *isrc;
- isrc = isrc_lookup(irq);
- if (isrc == NULL)
- return (EINVAL);
-
- if (isrc->isrc_handlers != 0)
- return (EBUSY); /* interrrupt is enabled (active) */
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
- /*
- * Once an interrupt is enabled, we do not change its configuration.
- * A controller PIC_ENABLE_INTR() method is called when an interrupt
- * is going to be enabled. In this method, a controller should setup
- * the interrupt according to saved configuration parameters.
- */
- isrc->isrc_trig = trig;
- isrc->isrc_pol = pol;
-
- return (0);
-}
-
-int
-intr_irq_describe(u_int irq, void *cookie, const char *descr)
-{
- struct intr_irqsrc *isrc;
- int error;
-
- isrc = isrc_lookup(irq);
+ isrc = intr_ddata_lookup(rman_get_start(res), NULL);
if (isrc == NULL || isrc->isrc_handlers == 0)
return (EINVAL);
#ifdef INTR_SOLO
@@ -1084,11 +1102,14 @@ intr_irq_describe(u_int irq, void *cookie, const char *descr)
#ifdef SMP
int
-intr_irq_bind(u_int irq, int cpu)
+intr_bind_irq(device_t dev, struct resource *res, int cpu)
{
struct intr_irqsrc *isrc;
- isrc = isrc_lookup(irq);
+ KASSERT(rman_get_start(res) == rman_get_end(res),
+ ("%s: more interrupts in resource", __func__));
+
+ isrc = intr_ddata_lookup(rman_get_start(res), NULL);
if (isrc == NULL || isrc->isrc_handlers == 0)
return (EINVAL);
#ifdef INTR_SOLO
@@ -1135,7 +1156,7 @@ intr_irq_shuffle(void *arg __unused)
for (i = 0; i < NIRQ; i++) {
isrc = irq_sources[i];
if (isrc == NULL || isrc->isrc_handlers == 0 ||
- isrc->isrc_flags & INTR_ISRCF_PERCPU)
+ isrc->isrc_flags & INTR_ISRCF_PPI)
continue;
if (isrc->isrc_event != NULL &&
@@ -1151,7 +1172,7 @@ intr_irq_shuffle(void *arg __unused)
* for bound ISRC. The best thing we can do is to clear
* isrc_cpu so inconsistency with ie_cpu will be detectable.
*/
- if (PIC_BIND(isrc->isrc_dev, isrc) != 0)
+ if (PIC_BIND_INTR(isrc->isrc_dev, isrc) != 0)
CPU_ZERO(&isrc->isrc_cpu);
}
mtx_unlock(&isrc_table_lock);
@@ -1196,6 +1217,7 @@ intr_pic_init_secondary(void)
DB_SHOW_COMMAND(irqs, db_show_irqs)
{
u_int i, irqsum;
+ u_long num;
struct intr_irqsrc *isrc;
for (irqsum = 0, i = 0; i < NIRQ; i++) {
@@ -1203,11 +1225,11 @@ DB_SHOW_COMMAND(irqs, db_show_irqs)
if (isrc == NULL)
continue;
+ num = isrc->isrc_count != NULL ? isrc->isrc_count[0] : 0;
db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i,
isrc->isrc_name, isrc->isrc_cpu.__bits[0],
- isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "",
- isrc->isrc_count[0]);
- irqsum += isrc->isrc_count[0];
+ isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", num);
+ irqsum += num;
}
db_printf("irq total %u\n", irqsum);
}
diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c
index 41f1f34..9bbec64 100644
--- a/sys/kern/subr_rman.c
+++ b/sys/kern/subr_rman.c
@@ -159,7 +159,7 @@ rman_manage_region(struct rman *rm, rman_res_t start, rman_res_t end)
struct resource_i *r, *s, *t;
int rv = 0;
- DPRINTF(("rman_manage_region: <%s> request: start %#lx, end %#lx\n",
+ DPRINTF(("rman_manage_region: <%s> request: start %#jx, end %#jx\n",
rm->rm_descr, start, end));
if (start < rm->rm_start || end > rm->rm_end)
return EINVAL;
@@ -174,7 +174,7 @@ rman_manage_region(struct rman *rm, rman_res_t start, rman_res_t end)
/* Skip entries before us. */
TAILQ_FOREACH(s, &rm->rm_list, r_link) {
- if (s->r_end == ULONG_MAX)
+ if (s->r_end == ~0)
break;
if (s->r_end + 1 >= r->r_start)
break;
@@ -444,8 +444,8 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
rv = NULL;
- DPRINTF(("rman_reserve_resource_bound: <%s> request: [%#lx, %#lx], "
- "length %#lx, flags %u, device %s\n", rm->rm_descr, start, end,
+ DPRINTF(("rman_reserve_resource_bound: <%s> request: [%#jx, %#jx], "
+ "length %#jx, flags %x, device %s\n", rm->rm_descr, start, end,
count, flags,
dev == NULL ? "<null>" : device_get_nameunit(dev)));
KASSERT((flags & RF_FIRSTSHARE) == 0,
@@ -454,19 +454,29 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
mtx_lock(rm->rm_mtx);
+ r = TAILQ_FIRST(&rm->rm_list);
+ if (r == NULL) {
+ DPRINTF(("NULL list head\n"));
+ } else {
+ DPRINTF(("rman_reserve_resource_bound: trying %#jx <%#jx,%#jx>\n",
+ r->r_end, start, count-1));
+ }
for (r = TAILQ_FIRST(&rm->rm_list);
r && r->r_end < start + count - 1;
- r = TAILQ_NEXT(r, r_link))
+ r = TAILQ_NEXT(r, r_link)) {
;
+ DPRINTF(("rman_reserve_resource_bound: tried %#jx <%#jx,%#jx>\n",
+ r->r_end, start, count-1));
+ }
if (r == NULL) {
DPRINTF(("could not find a region\n"));
goto out;
}
- amask = (1ul << RF_ALIGNMENT(flags)) - 1;
- KASSERT(start <= ULONG_MAX - amask,
- ("start (%#lx) + amask (%#lx) would wrap around", start, amask));
+ amask = (1ull << RF_ALIGNMENT(flags)) - 1;
+ KASSERT(start <= RM_MAX_END - amask,
+ ("start (%#jx) + amask (%#jx) would wrap around", start, amask));
/* If bound is 0, bmask will also be 0 */
bmask = ~(bound - 1);
@@ -474,18 +484,18 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
* First try to find an acceptable totally-unshared region.
*/
for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
- DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end));
+ DPRINTF(("considering [%#jx, %#jx]\n", s->r_start, s->r_end));
/*
* The resource list is sorted, so there is no point in
* searching further once r_start is too large.
*/
if (s->r_start > end - (count - 1)) {
- DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n",
+ DPRINTF(("s->r_start (%#jx) + count - 1> end (%#jx)\n",
s->r_start, end));
break;
}
- if (s->r_start > ULONG_MAX - amask) {
- DPRINTF(("s->r_start (%#lx) + amask (%#lx) too large\n",
+ if (s->r_start > RM_MAX_END - amask) {
+ DPRINTF(("s->r_start (%#jx) + amask (%#jx) too large\n",
s->r_start, amask));
break;
}
@@ -493,7 +503,7 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
DPRINTF(("region is allocated\n"));
continue;
}
- rstart = ulmax(s->r_start, start);
+ rstart = ummax(s->r_start, start);
/*
* Try to find a region by adjusting to boundary and alignment
* until both conditions are satisfied. This is not an optimal
@@ -505,16 +515,16 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
rstart += bound - (rstart & ~bmask);
} while ((rstart & amask) != 0 && rstart < end &&
rstart < s->r_end);
- rend = ulmin(s->r_end, ulmax(rstart + count - 1, end));
+ rend = ummin(s->r_end, ummax(rstart + count - 1, end));
if (rstart > rend) {
DPRINTF(("adjusted start exceeds end\n"));
continue;
}
- DPRINTF(("truncated region: [%#lx, %#lx]; size %#lx (requested %#lx)\n",
+ DPRINTF(("truncated region: [%#jx, %#jx]; size %#jx (requested %#jx)\n",
rstart, rend, (rend - rstart + 1), count));
if ((rend - rstart + 1) >= count) {
- DPRINTF(("candidate region: [%#lx, %#lx], size %#lx\n",
+ DPRINTF(("candidate region: [%#jx, %#jx], size %#jx\n",
rstart, rend, (rend - rstart + 1)));
if ((s->r_end - s->r_start + 1) == count) {
DPRINTF(("candidate region is entire chunk\n"));
@@ -545,7 +555,7 @@ rman_reserve_resource_bound(struct rman *rm, rman_res_t start, rman_res_t end,
if (s->r_start < rv->r_start && s->r_end > rv->r_end) {
DPRINTF(("splitting region in three parts: "
- "[%#lx, %#lx]; [%#lx, %#lx]; [%#lx, %#lx]\n",
+ "[%#jx, %#jx]; [%#jx, %#jx]; [%#jx, %#jx]\n",
s->r_start, rv->r_start - 1,
rv->r_start, rv->r_end,
rv->r_end + 1, s->r_end));
@@ -1032,8 +1042,8 @@ dump_rman_header(struct rman *rm)
if (db_pager_quit)
return;
- db_printf("rman %p: %s (0x%lx-0x%lx full range)\n",
- rm, rm->rm_descr, rm->rm_start, rm->rm_end);
+ db_printf("rman %p: %s (0x%jx-0x%jx full range)\n",
+ rm, rm->rm_descr, (rman_res_t)rm->rm_start, (rman_res_t)rm->rm_end);
}
static void
@@ -1051,7 +1061,7 @@ dump_rman(struct rman *rm)
devname = "nomatch";
} else
devname = NULL;
- db_printf(" 0x%lx-0x%lx (RID=%d) ",
+ db_printf(" 0x%jx-0x%jx (RID=%d) ",
r->r_start, r->r_end, r->r_rid);
if (devname != NULL)
db_printf("(%s)\n", devname);
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c
index 12908f6..ef06c48 100644
--- a/sys/kern/subr_sleepqueue.c
+++ b/sys/kern/subr_sleepqueue.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include "opt_sleepqueue_profiling.h"
#include "opt_ddb.h"
#include "opt_sched.h"
+#include "opt_stack.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -75,6 +76,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sdt.h>
#include <sys/signalvar.h>
#include <sys/sleepqueue.h>
+#include <sys/stack.h>
#include <sys/sysctl.h>
#include <vm/uma.h>
@@ -83,6 +85,7 @@ __FBSDID("$FreeBSD$");
#include <ddb/ddb.h>
#endif
+
/*
* Constants for the hash table of sleep queue chains.
* SC_TABLESIZE must be a power of two for SC_MASK to work properly.
@@ -382,6 +385,8 @@ sleepq_set_timeout_sbt(void *wchan, sbintime_t sbt, sbintime_t pr,
MPASS(TD_ON_SLEEPQ(td));
MPASS(td->td_sleepqueue == NULL);
MPASS(wchan != NULL);
+ if (cold)
+ panic("timed sleep before timers are working");
callout_reset_sbt_on(&td->td_slpcallout, sbt, pr,
sleepq_timeout, td, PCPU_GET(cpuid), flags | C_DIRECT_EXEC);
}
@@ -1034,6 +1039,122 @@ sleepq_abort(struct thread *td, int intrval)
return (sleepq_resume_thread(sq, td, 0));
}
+/*
+ * Prints the stacks of all threads presently sleeping on wchan/queue to
+ * the sbuf sb. Sets count_stacks_printed to the number of stacks actually
+ * printed. Typically, this will equal the number of threads sleeping on the
+ * queue, but may be less if sb overflowed before all stacks were printed.
+ */
+#ifdef STACK
+int
+sleepq_sbuf_print_stacks(struct sbuf *sb, void *wchan, int queue,
+ int *count_stacks_printed)
+{
+ struct thread *td, *td_next;
+ struct sleepqueue *sq;
+ struct stack **st;
+ struct sbuf **td_infos;
+ int i, stack_idx, error, stacks_to_allocate;
+ bool finished, partial_print;
+
+ error = 0;
+ finished = false;
+ partial_print = false;
+
+ KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
+ MPASS((queue >= 0) && (queue < NR_SLEEPQS));
+
+ stacks_to_allocate = 10;
+ for (i = 0; i < 3 && !finished ; i++) {
+ /* We cannot malloc while holding the queue's spinlock, so
+ * we do our mallocs now, and hope it is enough. If it
+ * isn't, we will free these, drop the lock, malloc more,
+ * and try again, up to a point. After that point we will
+ * give up and report ENOMEM. We also cannot write to sb
+ * during this time since the client may have set the
+ * SBUF_AUTOEXTEND flag on their sbuf, which could cause a
+ * malloc as we print to it. So we defer actually printing
+ * to sb until after we drop the spinlock.
+ */
+
+ /* Where we will store the stacks. */
+ st = malloc(sizeof(struct stack *) * stacks_to_allocate,
+ M_TEMP, M_WAITOK);
+ for (stack_idx = 0; stack_idx < stacks_to_allocate;
+ stack_idx++)
+ st[stack_idx] = stack_create();
+
+ /* Where we will store the td name, tid, etc. */
+ td_infos = malloc(sizeof(struct sbuf *) * stacks_to_allocate,
+ M_TEMP, M_WAITOK);
+ for (stack_idx = 0; stack_idx < stacks_to_allocate;
+ stack_idx++)
+ td_infos[stack_idx] = sbuf_new(NULL, NULL,
+ MAXCOMLEN + sizeof(struct thread *) * 2 + 40,
+ SBUF_FIXEDLEN);
+
+ sleepq_lock(wchan);
+ sq = sleepq_lookup(wchan);
+ if (sq == NULL) {
+ /* This sleepq does not exist; exit and return ENOENT. */
+ error = ENOENT;
+ finished = true;
+ sleepq_release(wchan);
+ goto loop_end;
+ }
+
+ stack_idx = 0;
+ /* Save thread info */
+ TAILQ_FOREACH_SAFE(td, &sq->sq_blocked[queue], td_slpq,
+ td_next) {
+ if (stack_idx >= stacks_to_allocate)
+ goto loop_end;
+
+ /* Note the td_lock is equal to the sleepq_lock here. */
+ stack_save_td(st[stack_idx], td);
+
+ sbuf_printf(td_infos[stack_idx], "%d: %s %p",
+ td->td_tid, td->td_name, td);
+
+ ++stack_idx;
+ }
+
+ finished = true;
+ sleepq_release(wchan);
+
+ /* Print the stacks */
+ for (i = 0; i < stack_idx; i++) {
+ sbuf_finish(td_infos[i]);
+ sbuf_printf(sb, "--- thread %s: ---\n", sbuf_data(td_infos[i]));
+ stack_sbuf_print(sb, st[i]);
+ sbuf_printf(sb, "\n");
+
+ error = sbuf_error(sb);
+ if (error == 0)
+ *count_stacks_printed = stack_idx;
+ }
+
+loop_end:
+ if (!finished)
+ sleepq_release(wchan);
+ for (stack_idx = 0; stack_idx < stacks_to_allocate;
+ stack_idx++)
+ stack_destroy(st[stack_idx]);
+ for (stack_idx = 0; stack_idx < stacks_to_allocate;
+ stack_idx++)
+ sbuf_delete(td_infos[stack_idx]);
+ free(st, M_TEMP);
+ free(td_infos, M_TEMP);
+ stacks_to_allocate *= 10;
+ }
+
+ if (!finished && error == 0)
+ error = ENOMEM;
+
+ return (error);
+}
+#endif
+
#ifdef SLEEPQUEUE_PROFILING
#define SLEEPQ_PROF_LOCATIONS 1024
#define SLEEPQ_SBUFSIZE 512
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index 82349f8..9848136 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/bus.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/sched.h>
@@ -51,6 +52,10 @@ __FBSDID("$FreeBSD$");
#include "opt_sched.h"
#ifdef SMP
+MALLOC_DEFINE(M_TOPO, "toponodes", "SMP topology data");
+#endif
+
+#ifdef SMP
volatile cpuset_t stopped_cpus;
volatile cpuset_t started_cpus;
volatile cpuset_t suspended_cpus;
@@ -556,7 +561,7 @@ smp_rendezvous(void (* setup_func)(void *),
smp_rendezvous_cpus(all_cpus, setup_func, action_func, teardown_func, arg);
}
-static struct cpu_group group[MAXCPU];
+static struct cpu_group group[MAXCPU * MAX_CACHE_LEVELS + 1];
struct cpu_group *
smp_topo(void)
@@ -616,6 +621,17 @@ smp_topo(void)
}
struct cpu_group *
+smp_topo_alloc(u_int count)
+{
+ static u_int index;
+ u_int curr;
+
+ curr = index;
+ index += count;
+ return (&group[curr]);
+}
+
+struct cpu_group *
smp_topo_none(void)
{
struct cpu_group *top;
@@ -861,3 +877,233 @@ sysctl_kern_smp_active(SYSCTL_HANDLER_ARGS)
return (error);
}
+
+#ifdef SMP
+void
+topo_init_node(struct topo_node *node)
+{
+
+ bzero(node, sizeof(*node));
+ TAILQ_INIT(&node->children);
+}
+
+void
+topo_init_root(struct topo_node *root)
+{
+
+ topo_init_node(root);
+ root->type = TOPO_TYPE_SYSTEM;
+}
+
+struct topo_node *
+topo_add_node_by_hwid(struct topo_node *parent, int hwid,
+ topo_node_type type, uintptr_t subtype)
+{
+ struct topo_node *node;
+
+ TAILQ_FOREACH_REVERSE(node, &parent->children,
+ topo_children, siblings) {
+ if (node->hwid == hwid
+ && node->type == type && node->subtype == subtype) {
+ return (node);
+ }
+ }
+
+ node = malloc(sizeof(*node), M_TOPO, M_WAITOK);
+ topo_init_node(node);
+ node->parent = parent;
+ node->hwid = hwid;
+ node->type = type;
+ node->subtype = subtype;
+ TAILQ_INSERT_TAIL(&parent->children, node, siblings);
+ parent->nchildren++;
+
+ return (node);
+}
+
+struct topo_node *
+topo_find_node_by_hwid(struct topo_node *parent, int hwid,
+ topo_node_type type, uintptr_t subtype)
+{
+
+ struct topo_node *node;
+
+ TAILQ_FOREACH(node, &parent->children, siblings) {
+ if (node->hwid == hwid
+ && node->type == type && node->subtype == subtype) {
+ return (node);
+ }
+ }
+
+ return (NULL);
+}
+
+void
+topo_promote_child(struct topo_node *child)
+{
+ struct topo_node *next;
+ struct topo_node *node;
+ struct topo_node *parent;
+
+ parent = child->parent;
+ next = TAILQ_NEXT(child, siblings);
+ TAILQ_REMOVE(&parent->children, child, siblings);
+ TAILQ_INSERT_HEAD(&parent->children, child, siblings);
+
+ while (next != NULL) {
+ node = next;
+ next = TAILQ_NEXT(node, siblings);
+ TAILQ_REMOVE(&parent->children, node, siblings);
+ TAILQ_INSERT_AFTER(&parent->children, child, node, siblings);
+ child = node;
+ }
+}
+
+struct topo_node *
+topo_next_node(struct topo_node *top, struct topo_node *node)
+{
+ struct topo_node *next;
+
+ if ((next = TAILQ_FIRST(&node->children)) != NULL)
+ return (next);
+
+ if ((next = TAILQ_NEXT(node, siblings)) != NULL)
+ return (next);
+
+ while ((node = node->parent) != top)
+ if ((next = TAILQ_NEXT(node, siblings)) != NULL)
+ return (next);
+
+ return (NULL);
+}
+
+struct topo_node *
+topo_next_nonchild_node(struct topo_node *top, struct topo_node *node)
+{
+ struct topo_node *next;
+
+ if ((next = TAILQ_NEXT(node, siblings)) != NULL)
+ return (next);
+
+ while ((node = node->parent) != top)
+ if ((next = TAILQ_NEXT(node, siblings)) != NULL)
+ return (next);
+
+ return (NULL);
+}
+
+void
+topo_set_pu_id(struct topo_node *node, cpuid_t id)
+{
+
+ KASSERT(node->type == TOPO_TYPE_PU,
+ ("topo_set_pu_id: wrong node type: %u", node->type));
+ KASSERT(CPU_EMPTY(&node->cpuset) && node->cpu_count == 0,
+ ("topo_set_pu_id: cpuset already not empty"));
+ node->id = id;
+ CPU_SET(id, &node->cpuset);
+ node->cpu_count = 1;
+ node->subtype = 1;
+
+ while ((node = node->parent) != NULL) {
+ if (CPU_ISSET(id, &node->cpuset))
+ break;
+ CPU_SET(id, &node->cpuset);
+ node->cpu_count++;
+ }
+}
+
+int
+topo_analyze(struct topo_node *topo_root, int all,
+ int *pkg_count, int *cores_per_pkg, int *thrs_per_core)
+{
+ struct topo_node *pkg_node;
+ struct topo_node *core_node;
+ struct topo_node *pu_node;
+ int thrs_per_pkg;
+ int cpp_counter;
+ int tpc_counter;
+ int tpp_counter;
+
+ *pkg_count = 0;
+ *cores_per_pkg = -1;
+ *thrs_per_core = -1;
+ thrs_per_pkg = -1;
+ pkg_node = topo_root;
+ while (pkg_node != NULL) {
+ if (pkg_node->type != TOPO_TYPE_PKG) {
+ pkg_node = topo_next_node(topo_root, pkg_node);
+ continue;
+ }
+ if (!all && CPU_EMPTY(&pkg_node->cpuset)) {
+ pkg_node = topo_next_nonchild_node(topo_root, pkg_node);
+ continue;
+ }
+
+ (*pkg_count)++;
+
+ cpp_counter = 0;
+ tpp_counter = 0;
+ core_node = pkg_node;
+ while (core_node != NULL) {
+ if (core_node->type == TOPO_TYPE_CORE) {
+ if (!all && CPU_EMPTY(&core_node->cpuset)) {
+ core_node =
+ topo_next_nonchild_node(pkg_node,
+ core_node);
+ continue;
+ }
+
+ cpp_counter++;
+
+ tpc_counter = 0;
+ pu_node = core_node;
+ while (pu_node != NULL) {
+ if (pu_node->type == TOPO_TYPE_PU &&
+ (all || !CPU_EMPTY(&pu_node->cpuset)))
+ tpc_counter++;
+ pu_node = topo_next_node(core_node,
+ pu_node);
+ }
+
+ if (*thrs_per_core == -1)
+ *thrs_per_core = tpc_counter;
+ else if (*thrs_per_core != tpc_counter)
+ return (0);
+
+ core_node = topo_next_nonchild_node(pkg_node,
+ core_node);
+ } else {
+ /* PU node directly under PKG. */
+ if (core_node->type == TOPO_TYPE_PU &&
+ (all || !CPU_EMPTY(&core_node->cpuset)))
+ tpp_counter++;
+ core_node = topo_next_node(pkg_node,
+ core_node);
+ }
+ }
+
+ if (*cores_per_pkg == -1)
+ *cores_per_pkg = cpp_counter;
+ else if (*cores_per_pkg != cpp_counter)
+ return (0);
+ if (thrs_per_pkg == -1)
+ thrs_per_pkg = tpp_counter;
+ else if (thrs_per_pkg != tpp_counter)
+ return (0);
+
+ pkg_node = topo_next_nonchild_node(topo_root, pkg_node);
+ }
+
+ KASSERT(*pkg_count > 0,
+ ("bug in topology or analysis"));
+ if (*cores_per_pkg == 0) {
+ KASSERT(*thrs_per_core == -1 && thrs_per_pkg > 0,
+ ("bug in topology or analysis"));
+ *thrs_per_core = thrs_per_pkg;
+ }
+
+ return (1);
+}
+#endif /* SMP */
+
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index fe79f52..75fb66e 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -89,12 +89,14 @@ __FBSDID("$FreeBSD$");
#define SYS_IOCTL_SMALL_SIZE 128 /* bytes */
#define SYS_IOCTL_SMALL_ALIGN 8 /* bytes */
-int iosize_max_clamp = 0;
+#ifdef __LP64__
+static int iosize_max_clamp = 0;
SYSCTL_INT(_debug, OID_AUTO, iosize_max_clamp, CTLFLAG_RW,
&iosize_max_clamp, 0, "Clamp max i/o size to INT_MAX");
-int devfs_iosize_max_clamp = 1;
+static int devfs_iosize_max_clamp = 1;
SYSCTL_INT(_debug, OID_AUTO, devfs_iosize_max_clamp, CTLFLAG_RW,
&devfs_iosize_max_clamp, 0, "Clamp max i/o size to INT_MAX for devices");
+#endif
/*
* Assert that the return value of read(2) and write(2) syscalls fits
@@ -159,6 +161,24 @@ struct selfd {
static uma_zone_t selfd_zone;
static struct mtx_pool *mtxpool_select;
+#ifdef __LP64__
+size_t
+devfs_iosize_max(void)
+{
+
+ return (devfs_iosize_max_clamp || SV_CURPROC_FLAG(SV_ILP32) ?
+ INT_MAX : SSIZE_MAX);
+}
+
+size_t
+iosize_max(void)
+{
+
+ return (iosize_max_clamp || SV_CURPROC_FLAG(SV_ILP32) ?
+ INT_MAX : SSIZE_MAX);
+}
+#endif
+
#ifndef _SYS_SYSPROTO_H_
struct read_args {
int fd;
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 44ddd81..3575028 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 296572 2016-03-09 19:05:11Z jhb
+ * created from FreeBSD: head/sys/kern/syscalls.master 297167 2016-03-21 21:37:33Z jhb
*/
const char *syscallnames[] = {
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index f08f5e3..5675425 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -554,7 +554,7 @@
312 AUE_SETRESGID STD { int setresgid(gid_t rgid, gid_t egid, \
gid_t sgid); }
313 AUE_NULL OBSOL signanosleep
-314 AUE_NULL STD { int aio_return(struct aiocb *aiocbp); }
+314 AUE_NULL STD { ssize_t aio_return(struct aiocb *aiocbp); }
315 AUE_NULL STD { int aio_suspend( \
struct aiocb * const * aiocbp, int nent, \
const struct timespec *timeout); }
@@ -643,7 +643,7 @@
358 AUE_EXTATTR_DELETE_FILE STD { int extattr_delete_file(const char *path, \
int attrnamespace, \
const char *attrname); }
-359 AUE_NULL STD { int aio_waitcomplete( \
+359 AUE_NULL STD { ssize_t aio_waitcomplete( \
struct aiocb **aiocbp, \
struct timespec *timeout); }
360 AUE_GETRESUID STD { int getresuid(uid_t *ruid, uid_t *euid, \
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
index 6fd03f1..c2ea2b4 100644
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -9796,7 +9796,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* aio_return */
case 314:
if (ndx == 0 || ndx == 1)
- p = "int";
+ p = "ssize_t";
break;
/* aio_suspend */
case 315:
@@ -9972,7 +9972,7 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* aio_waitcomplete */
case 359:
if (ndx == 0 || ndx == 1)
- p = "int";
+ p = "ssize_t";
break;
/* getresuid */
case 360:
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index 23bfbff..62dfda6 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -47,6 +47,49 @@ __FBSDID("$FreeBSD$");
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/uio.h>
+#include <sys/sdt.h>
+
+SDT_PROBE_DEFINE5_XLATE(sdt, , , m__init,
+ "struct mbuf *", "mbufinfo_t *",
+ "uint32_t", "uint32_t",
+ "uint16_t", "uint16_t",
+ "uint32_t", "uint32_t",
+ "uint32_t", "uint32_t");
+
+SDT_PROBE_DEFINE3_XLATE(sdt, , , m__gethdr,
+ "uint32_t", "uint32_t",
+ "uint16_t", "uint16_t",
+ "struct mbuf *", "mbufinfo_t *");
+
+SDT_PROBE_DEFINE3_XLATE(sdt, , , m__get,
+ "uint32_t", "uint32_t",
+ "uint16_t", "uint16_t",
+ "struct mbuf *", "mbufinfo_t *");
+
+SDT_PROBE_DEFINE4_XLATE(sdt, , , m__getcl,
+ "uint32_t", "uint32_t",
+ "uint16_t", "uint16_t",
+ "uint32_t", "uint32_t",
+ "struct mbuf *", "mbufinfo_t *");
+
+SDT_PROBE_DEFINE3_XLATE(sdt, , , m__clget,
+ "struct mbuf *", "mbufinfo_t *",
+ "uint32_t", "uint32_t",
+ "uint32_t", "uint32_t");
+
+SDT_PROBE_DEFINE4_XLATE(sdt, , , m__cljget,
+ "struct mbuf *", "mbufinfo_t *",
+ "uint32_t", "uint32_t",
+ "uint32_t", "uint32_t",
+ "void*", "void*");
+
+SDT_PROBE_DEFINE(sdt, , , m__cljset);
+
+SDT_PROBE_DEFINE1_XLATE(sdt, , , m__free,
+ "struct mbuf *", "mbufinfo_t *");
+
+SDT_PROBE_DEFINE1_XLATE(sdt, , , m__freem,
+ "struct mbuf *", "mbufinfo_t *");
#include <security/mac/mac_framework.h>
@@ -1627,7 +1670,7 @@ m_unshare(struct mbuf *m0, int how)
* don't know how to break up the non-contiguous memory when
* doing DMA.
*/
- n = m_getcl(how, m->m_type, m->m_flags);
+ n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS);
if (n == NULL) {
m_freem(m0);
return (NULL);
@@ -1657,7 +1700,7 @@ m_unshare(struct mbuf *m0, int how)
break;
off += cc;
- n = m_getcl(how, m->m_type, m->m_flags);
+ n = m_getcl(how, m->m_type, m->m_flags & M_COPYFLAGS);
if (n == NULL) {
m_freem(mfirst);
m_freem(m0);
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 35d17b1..d873217 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -358,7 +358,7 @@ sysctl_maxsockets(SYSCTL_HANDLER_ARGS)
}
SYSCTL_PROC(_kern_ipc, OID_AUTO, maxsockets, CTLTYPE_INT|CTLFLAG_RW,
&maxsockets, 0, sysctl_maxsockets, "IU",
- "Maximum number of sockets avaliable");
+ "Maximum number of sockets available");
/*
* Socket operation routines. These routines are called by the routines in
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 27fa239..20df141 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -743,7 +743,7 @@ aio_process_rw(struct kaiocb *job)
struct file *fp;
struct uio auio;
struct iovec aiov;
- int cnt;
+ ssize_t cnt;
int error;
int oublock_st, oublock_end;
int inblock_st, inblock_end;
@@ -1173,7 +1173,7 @@ aio_qphysio(struct proc *p, struct kaiocb *job)
struct cdevsw *csw;
struct cdev *dev;
struct kaioinfo *ki;
- int error, ref, unmap, poff;
+ int error, ref, poff;
vm_prot_t prot;
cb = &job->uaiocb;
@@ -1206,12 +1206,13 @@ aio_qphysio(struct proc *p, struct kaiocb *job)
ki = p->p_aioinfo;
poff = (vm_offset_t)cb->aio_buf & PAGE_MASK;
- unmap = ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed);
- if (unmap) {
+ if ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed) {
if (cb->aio_nbytes > MAXPHYS) {
error = -1;
goto unref;
}
+
+ pbuf = NULL;
} else {
if (cb->aio_nbytes > MAXPHYS - poff) {
error = -1;
@@ -1221,17 +1222,14 @@ aio_qphysio(struct proc *p, struct kaiocb *job)
error = -1;
goto unref;
}
- }
- job->bp = bp = g_alloc_bio();
- if (!unmap) {
+
job->pbuf = pbuf = (struct buf *)getpbuf(NULL);
BUF_KERNPROC(pbuf);
- }
-
- AIO_LOCK(ki);
- if (!unmap)
+ AIO_LOCK(ki);
ki->kaio_buffer_count++;
- AIO_UNLOCK(ki);
+ AIO_UNLOCK(ki);
+ }
+ job->bp = bp = g_alloc_bio();
bp->bio_length = cb->aio_nbytes;
bp->bio_bcount = cb->aio_nbytes;
@@ -1245,17 +1243,18 @@ aio_qphysio(struct proc *p, struct kaiocb *job)
prot = VM_PROT_READ;
if (cb->aio_lio_opcode == LIO_READ)
prot |= VM_PROT_WRITE; /* Less backwards than it looks */
- if ((job->npages = vm_fault_quick_hold_pages(
- &curproc->p_vmspace->vm_map,
+ job->npages = vm_fault_quick_hold_pages(&curproc->p_vmspace->vm_map,
(vm_offset_t)bp->bio_data, bp->bio_length, prot, job->pages,
- sizeof(job->pages)/sizeof(job->pages[0]))) < 0) {
+ nitems(job->pages));
+ if (job->npages < 0) {
error = EFAULT;
goto doerror;
}
- if (!unmap) {
+ if (pbuf != NULL) {
pmap_qenter((vm_offset_t)pbuf->b_data,
job->pages, job->npages);
bp->bio_data = pbuf->b_data + poff;
+ atomic_add_int(&num_buf_aio, 1);
} else {
bp->bio_ma = job->pages;
bp->bio_ma_n = job->npages;
@@ -1264,20 +1263,16 @@ aio_qphysio(struct proc *p, struct kaiocb *job)
bp->bio_flags |= BIO_UNMAPPED;
}
- if (!unmap)
- atomic_add_int(&num_buf_aio, 1);
-
/* Perform transfer. */
csw->d_strategy(bp);
dev_relthread(dev, ref);
return (0);
doerror:
- AIO_LOCK(ki);
- if (!unmap)
+ if (pbuf != NULL) {
+ AIO_LOCK(ki);
ki->kaio_buffer_count--;
- AIO_UNLOCK(ki);
- if (pbuf) {
+ AIO_UNLOCK(ki);
relpbuf(pbuf, NULL);
job->pbuf = NULL;
}
@@ -1446,8 +1441,7 @@ aio_aqueue(struct thread *td, struct aiocb *ujob, struct aioliojob *lj,
return (error);
}
- /* XXX: aio_nbytes is later casted to signed types. */
- if (job->uaiocb.aio_nbytes > INT_MAX) {
+ if (job->uaiocb.aio_nbytes > IOSIZE_MAX) {
uma_zfree(aiocb_zone, job);
return (EINVAL);
}
@@ -1788,7 +1782,7 @@ kern_aio_return(struct thread *td, struct aiocb *ujob, struct aiocb_ops *ops)
struct proc *p = td->td_proc;
struct kaiocb *job;
struct kaioinfo *ki;
- int status, error;
+ long status, error;
ki = p->p_aioinfo;
if (ki == NULL)
@@ -2344,7 +2338,8 @@ kern_aio_waitcomplete(struct thread *td, struct aiocb **ujobp,
struct kaioinfo *ki;
struct kaiocb *job;
struct aiocb *ujob;
- int error, status, timo;
+ long error, status;
+ int timo;
ops->store_aiocb(ujobp, NULL);
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 9be0ece..9eb523c 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -256,10 +256,10 @@ vfs_free_addrlist_af(struct radix_node_head **prnh)
rnh = *prnh;
RADIX_NODE_HEAD_LOCK(rnh);
- (*rnh->rnh_walktree)(&rnh->rh, vfs_free_netcred, &rnh->rh);
+ (*rnh->rnh_walktree)(&rnh->rh, vfs_free_netcred, rnh);
RADIX_NODE_HEAD_UNLOCK(rnh);
RADIX_NODE_HEAD_DESTROY(rnh);
- free(rnh, M_RTABLE);
+ rn_detachhead((void **)prnh);
prnh = NULL;
}
diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c
index cf24253..a33e376 100644
--- a/sys/kern/vfs_mountroot.c
+++ b/sys/kern/vfs_mountroot.c
@@ -89,6 +89,7 @@ __FBSDID("$FreeBSD$");
static int parse_mount(char **);
static struct mntarg *parse_mountroot_options(struct mntarg *, const char *);
static int sysctl_vfs_root_mount_hold(SYSCTL_HANDLER_ARGS);
+static void vfs_mountroot_wait(void);
static int vfs_mountroot_wait_if_neccessary(const char *fs, const char *dev);
/*
@@ -488,6 +489,8 @@ parse_dir_ask(char **conf)
char *mnt;
int error;
+ vfs_mountroot_wait();
+
printf("\nLoader variables:\n");
parse_dir_ask_printenv("vfs.root.mountfrom");
parse_dir_ask_printenv("vfs.root.mountfrom.options");
diff --git a/sys/mips/atheros/apb.c b/sys/mips/atheros/apb.c
index 8d230a7..abae9c2 100644
--- a/sys/mips/atheros/apb.c
+++ b/sys/mips/atheros/apb.c
@@ -178,7 +178,7 @@ apb_alloc_resource(device_t bus, device_t child, int type, int *rid,
passthrough = (device_get_parent(child) != bus);
rle = NULL;
- dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %ld, %d)\n",
+ dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %jd, %d)\n",
__func__, bus, child, type, *rid, (void *)(intptr_t)start,
(void *)(intptr_t)end, count, flags);
@@ -491,8 +491,8 @@ apb_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return (retval);
}
diff --git a/sys/mips/beri/beri_simplebus.c b/sys/mips/beri/beri_simplebus.c
index dd219a5..79302f6 100644
--- a/sys/mips/beri/beri_simplebus.c
+++ b/sys/mips/beri/beri_simplebus.c
@@ -239,8 +239,8 @@ simplebus_print_child(device_t dev, device_t child)
rv = 0;
rv += bus_print_child_header(dev, child);
- rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
if ((ip = simplebus_get_interrupt_parent(child)) != NULL)
rv += printf(" (%s)", device_get_nameunit(ip));
rv += bus_print_child_footer(dev, child);
diff --git a/sys/mips/mips/mips_pic.c b/sys/mips/mips/mips_pic.c
index 250f8cf..4e97c41 100644
--- a/sys/mips/mips/mips_pic.c
+++ b/sys/mips/mips/mips_pic.c
@@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/smp.h>
#include <sys/sched.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
#include <machine/bus.h>
#include <machine/hwfunc.h>
@@ -217,8 +219,11 @@ mips_pic_intr(void *arg)
KASSERT(i == 0, ("all interrupts handled"));
#ifdef HWPMC_HOOKS
- if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN))
+ if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) {
+ struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame;
+
pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf);
+ }
#endif
return (FILTER_HANDLED);
}
diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c
index 617d842..89049f0 100644
--- a/sys/mips/mips/nexus.c
+++ b/sys/mips/mips/nexus.c
@@ -231,8 +231,8 @@ nexus_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return (retval);
}
@@ -275,7 +275,7 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
struct rman *rm;
int isdefault, needactivate, passthrough;
- dprintf("%s: entry (%p, %p, %d, %p, %p, %p, %ld, %d)\n",
+ dprintf("%s: entry (%p, %p, %d, %p, %p, %p, %jd, %d)\n",
__func__, bus, child, type, rid, (void *)(intptr_t)start,
(void *)(intptr_t)end, count, flags);
dprintf("%s: requested rid is %d\n", __func__, *rid);
@@ -350,7 +350,7 @@ nexus_set_resource(device_t dev, device_t child, int type, int rid,
struct resource_list *rl = &ndev->nx_resources;
struct resource_list_entry *rle;
- dprintf("%s: entry (%p, %p, %d, %d, %p, %ld)\n",
+ dprintf("%s: entry (%p, %p, %d, %d, %p, %jd)\n",
__func__, dev, child, type, rid, (void *)(intptr_t)start, count);
rle = resource_list_add(rl, type, rid, start, start + count - 1,
diff --git a/sys/mips/nlm/xlp_pci.c b/sys/mips/nlm/xlp_pci.c
index fee23cd..863c6aa 100644
--- a/sys/mips/nlm/xlp_pci.c
+++ b/sys/mips/nlm/xlp_pci.c
@@ -433,7 +433,7 @@ mips_platform_pcib_setup_intr(device_t dev, device_t child,
if (error)
return error;
if (rman_get_start(irq) != rman_get_end(irq)) {
- device_printf(dev, "Interrupt allocation %lu != %lu\n",
+ device_printf(dev, "Interrupt allocation %ju != %ju\n",
rman_get_start(irq), rman_get_end(irq));
return (EINVAL);
}
diff --git a/sys/mips/nlm/xlp_simplebus.c b/sys/mips/nlm/xlp_simplebus.c
index 3ffb19a..413775b 100644
--- a/sys/mips/nlm/xlp_simplebus.c
+++ b/sys/mips/nlm/xlp_simplebus.c
@@ -209,7 +209,7 @@ xlp_simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
if (j == sc->nranges && sc->nranges != 0) {
if (bootverbose)
device_printf(bus, "Could not map resource "
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
}
@@ -235,7 +235,7 @@ xlp_simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
} else {
if (bootverbose)
device_printf(bus, "Invalid MEM range"
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
break;
diff --git a/sys/mips/rmi/iodi.c b/sys/mips/rmi/iodi.c
index da0405d..d1f74e1 100644
--- a/sys/mips/rmi/iodi.c
+++ b/sys/mips/rmi/iodi.c
@@ -134,17 +134,17 @@ iodi_alloc_resource(device_t bus, device_t child, int type, int *rid,
#ifdef DEBUG
switch (type) {
case SYS_RES_IRQ:
- device_printf(bus, "IRQ resource - for %s %lx-%lx\n",
+ device_printf(bus, "IRQ resource - for %s %jx-%jx\n",
device_get_nameunit(child), start, end);
break;
case SYS_RES_IOPORT:
- device_printf(bus, "IOPORT resource - for %s %lx-%lx\n",
+ device_printf(bus, "IOPORT resource - for %s %jx-%jx\n",
device_get_nameunit(child), start, end);
break;
case SYS_RES_MEMORY:
- device_printf(bus, "MEMORY resource - for %s %lx-%lx\n",
+ device_printf(bus, "MEMORY resource - for %s %jx-%jx\n",
device_get_nameunit(child), start, end);
break;
}
diff --git a/sys/mips/rmi/xlr_pci.c b/sys/mips/rmi/xlr_pci.c
index 194213b..53581a6 100644
--- a/sys/mips/rmi/xlr_pci.c
+++ b/sys/mips/rmi/xlr_pci.c
@@ -464,7 +464,7 @@ mips_platform_pci_setup_intr(device_t dev, device_t child,
if (error)
return error;
if (rman_get_start(irq) != rman_get_end(irq)) {
- device_printf(dev, "Interrupt allocation %lu != %lu\n",
+ device_printf(dev, "Interrupt allocation %ju != %ju\n",
rman_get_start(irq), rman_get_end(irq));
return (EINVAL);
}
diff --git a/sys/mips/rt305x/obio.c b/sys/mips/rt305x/obio.c
index ff7ba03..ac27230 100644
--- a/sys/mips/rt305x/obio.c
+++ b/sys/mips/rt305x/obio.c
@@ -587,8 +587,8 @@ obio_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return (retval);
}
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 8d9e499..e2c2205 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -250,6 +250,7 @@ SUBDIR= \
${_nandfs} \
${_nandsim} \
${_ncr} \
+ ${_nctgpio} \
${_ncv} \
${_ndis} \
netfpga10g \
@@ -367,6 +368,8 @@ SUBDIR= \
udf_iconv \
ufs \
unionfs \
+ urtwn \
+ ${_urtwnfw} \
usb \
utopia \
${_vesa} \
@@ -484,6 +487,7 @@ _ispfw= ispfw
_mwlfw= mwlfw
_ralfw= ralfw
_rtwnfw= rtwnfw
+_urtwnfw= urtwnfw
_sf= sf
_ti= ti
_txp= txp
@@ -555,6 +559,7 @@ _ixv= ixv
_linprocfs= linprocfs
_linsysfs= linsysfs
_linux= linux
+_nctgpio= nctgpio
_ndis= ndis
_pccard= pccard
.if ${MK_OFED} != "no" || defined(ALL_MODULES)
diff --git a/sys/modules/nctgpio/Makefile b/sys/modules/nctgpio/Makefile
new file mode 100644
index 0000000..88e133d
--- /dev/null
+++ b/sys/modules/nctgpio/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/nctgpio
+KMOD= nctgpio
+SRCS= nctgpio.c
+SRCS+= device_if.h bus_if.h isa_if.h gpio_if.h opt_platform.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/pflog/Makefile b/sys/modules/pflog/Makefile
index 1889681..36656dc 100644
--- a/sys/modules/pflog/Makefile
+++ b/sys/modules/pflog/Makefile
@@ -7,14 +7,11 @@ SRCS= if_pflog.c \
opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h
SRCS+= bus_if.h device_if.h
-.if defined(KERNBUILDDIR)
-MKDEP+= -include ${KERNBUILDDIR}/opt_global.h
-.else
+.if !defined(KERNBUILDDIR)
.if defined(VIMAGE)
opt_global.h:
echo "#define VIMAGE 1" >> ${.TARGET}
CFLAGS+= -include opt_global.h
-MKDEP+= -include opt_global.h
.endif
.endif
diff --git a/sys/modules/pfsync/Makefile b/sys/modules/pfsync/Makefile
index d38bde7..89af6f9 100644
--- a/sys/modules/pfsync/Makefile
+++ b/sys/modules/pfsync/Makefile
@@ -7,14 +7,11 @@ SRCS= if_pfsync.c \
opt_pf.h opt_inet.h opt_inet6.h
SRCS+= bus_if.h device_if.h
-.if defined(KERNBUILDDIR)
-MKDEP+= -include ${KERNBUILDDIR}/opt_global.h
-.else
+.if !defined(KERNBUILDDIR)
.if defined(VIMAGE)
opt_global.h:
echo "#define VIMAGE 1" >> ${.TARGET}
CFLAGS+= -include opt_global.h
-MKDEP+= -include opt_global.h
.endif
.endif
diff --git a/sys/modules/usb/urtwn/Makefile b/sys/modules/urtwn/Makefile
index 59fa910..a4fdc25 100644
--- a/sys/modules/usb/urtwn/Makefile
+++ b/sys/modules/urtwn/Makefile
@@ -1,8 +1,9 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/../../../dev/usb/wlan
+.PATH: ${.CURDIR}/../../dev/urtwn
-.include <src.opts.mk>
+SYSDIR?=${.CURDIR}/../..
+.include "${SYSDIR}/conf/kern.opts.mk"
KMOD = if_urtwn
SRCS = if_urtwn.c if_urtwnreg.h if_urtwnvar.h \
diff --git a/sys/modules/usb/urtwnfw/Makefile b/sys/modules/urtwnfw/Makefile
index 611b411..611b411 100644
--- a/sys/modules/usb/urtwnfw/Makefile
+++ b/sys/modules/urtwnfw/Makefile
diff --git a/sys/modules/usb/urtwnfw/Makefile.inc b/sys/modules/urtwnfw/Makefile.inc
index 17c78be..2a97a09 100644
--- a/sys/modules/usb/urtwnfw/Makefile.inc
+++ b/sys/modules/urtwnfw/Makefile.inc
@@ -11,5 +11,5 @@ FIRMWS= ${_FIRM}:${KMOD}:111
# FIRMWARE_LICENSE= realtek
-${_FIRM}: ${.CURDIR}/../../../../contrib/dev/urtwn/${_FIRM}.uu
+${_FIRM}: ${.CURDIR}/../../../contrib/dev/urtwn/${_FIRM}.uu
uudecode -p $? > ${.TARGET}
diff --git a/sys/modules/usb/urtwnfw/urtwnrtl8188eu/Makefile b/sys/modules/urtwnfw/urtwnrtl8188eu/Makefile
index d3c974e..d3c974e 100644
--- a/sys/modules/usb/urtwnfw/urtwnrtl8188eu/Makefile
+++ b/sys/modules/urtwnfw/urtwnrtl8188eu/Makefile
diff --git a/sys/modules/usb/urtwnfw/urtwnrtl8192cT/Makefile b/sys/modules/urtwnfw/urtwnrtl8192cT/Makefile
index ef49984..ef49984 100644
--- a/sys/modules/usb/urtwnfw/urtwnrtl8192cT/Makefile
+++ b/sys/modules/urtwnfw/urtwnrtl8192cT/Makefile
diff --git a/sys/modules/usb/urtwnfw/urtwnrtl8192cU/Makefile b/sys/modules/urtwnfw/urtwnrtl8192cU/Makefile
index e9a932c..e9a932c 100644
--- a/sys/modules/usb/urtwnfw/urtwnrtl8192cU/Makefile
+++ b/sys/modules/urtwnfw/urtwnrtl8192cU/Makefile
diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile
index b236d04..72b123e 100644
--- a/sys/modules/usb/Makefile
+++ b/sys/modules/usb/Makefile
@@ -47,7 +47,6 @@ SUBDIR = usb
SUBDIR += ${_dwc_otg} ehci ${_musb} ohci uhci xhci ${_uss820dci} ${_at91dci} \
${_atmegadci} ${_avr32dci} ${_rsu} ${_rsufw} ${_saf1761otg}
SUBDIR += ${_rum} ${_run} ${_runfw} ${_uath} upgt usie ural ${_zyd} ${_urtw}
-SUBDIR += urtwn ${_urtwnfw}
SUBDIR += atp uhid ukbd ums udbp ufm uep wsp ugold uled
SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
umct umcs umodem umoscom uplcom uslcom uvisor uvscom
@@ -70,7 +69,6 @@ _rum= rum
_uath= uath
_zyd= zyd
_kue= kue
-_urtwnfw= urtwnfw
_run= run
_runfw= runfw
_rsu= rsu
diff --git a/sys/modules/wtap/Makefile b/sys/modules/wtap/Makefile
index 68b905f..58f60fb 100644
--- a/sys/modules/wtap/Makefile
+++ b/sys/modules/wtap/Makefile
@@ -16,11 +16,8 @@ SRCS += visibility.c
SRCS += opt_global.h
-.if defined(KERNBUILDDIR)
-MKDEP= -include ${KERNBUILDDIR}/opt_global.h
-.else
+.if !defined(KERNBUILDDIR)
CFLAGS+= -include opt_global.h
-MKDEP= -include opt_global.h
opt_global.h:
echo "#define VIMAGE 1" > ${.TARGET}
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
index 438028d..52d8f61 100644
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -333,6 +333,7 @@ struct ether_vlan_header {
#define ETHERTYPE_SLOW 0x8809 /* 802.3ad link aggregation (LACP) */
#define ETHERTYPE_PPP 0x880B /* PPP (obsolete by PPPoE) */
#define ETHERTYPE_HITACHI 0x8820 /* Hitachi Cable (Optoelectronic Systems Laboratory) */
+#define ETHERTYPE_TEST 0x8822 /* Network Conformance Testing */
#define ETHERTYPE_MPLS 0x8847 /* MPLS Unicast */
#define ETHERTYPE_MPLS_MCAST 0x8848 /* MPLS Multicast */
#define ETHERTYPE_AXIS 0x8856 /* Axis Communications AB proprietary bootstrap/config */
diff --git a/sys/net/if_debug.c b/sys/net/if_debug.c
index 1d198eb..fbcc2b0 100644
--- a/sys/net/if_debug.c
+++ b/sys/net/if_debug.c
@@ -67,6 +67,8 @@ if_show_ifnet(struct ifnet *ifp)
IF_DB_PRINTF("%p", if_l2com);
IF_DB_PRINTF("%p", if_vnet);
IF_DB_PRINTF("%p", if_home_vnet);
+ IF_DB_PRINTF("%p", if_vlantrunk);
+ IF_DB_PRINTF("%p", if_bpf);
IF_DB_PRINTF("%p", if_addr);
IF_DB_PRINTF("%p", if_llsoftc);
IF_DB_PRINTF("%p", if_label);
diff --git a/sys/net/route.c b/sys/net/route.c
index 45f479c..4b191d0 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -201,6 +201,16 @@ rt_tables_get_rnh(int table, int fam)
return (*rt_tables_get_rnh_ptr(table, fam));
}
+u_int
+rt_tables_get_gen(int table, int fam)
+{
+ struct rib_head *rnh;
+
+ rnh = *rt_tables_get_rnh_ptr(table, fam);
+ return (rnh->rnh_gen);
+}
+
+
/*
* route initialization must occur before ip6_init2(), which happenas at
* SI_ORDER_MIDDLE.
@@ -1754,6 +1764,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
*ret_nrt = rt;
RT_ADDREF(rt);
}
+ rnh->rnh_gen++; /* Routing table updated */
RT_UNLOCK(rt);
break;
case RTM_CHANGE:
diff --git a/sys/net/route.h b/sys/net/route.h
index 6cc1e1c..e0ff6b4 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -98,6 +98,14 @@ struct rt_metrics {
/* lle state is exported in rmx_state rt_metrics field */
#define rmx_state rmx_weight
+/*
+ * Keep a generation count of routing table, incremented on route addition,
+ * so we can invalidate caches. This is accessed without a lock, as precision
+ * is not required.
+ */
+typedef volatile u_int rt_gen_t; /* tree generation (for adds) */
+#define RT_GEN(fibnum, af) rt_tables_get_gen(fibnum, af)
+
#define RT_DEFAULT_FIB 0 /* Explicitly mark fib=0 restricted cases */
#define RT_ALL_FIBS -1 /* Announce event for every fib */
#ifdef _KERNEL
@@ -398,6 +406,20 @@ struct rt_addrinfo {
} \
} while (0)
+/*
+ * Validate a cached route based on a supplied cookie. If there is an
+ * out-of-date cache, simply free it. Update the generation number
+ * for the new allocation
+ */
+#define RT_VALIDATE(ro, cookiep, fibnum) do { \
+ rt_gen_t cookie = RT_GEN(fibnum, (ro)->ro_dst.sa_family); \
+ if (*(cookiep) != cookie && (ro)->ro_rt != NULL) { \
+ RTFREE((ro)->ro_rt); \
+ (ro)->ro_rt = NULL; \
+ *(cookiep) = cookie; \
+ } \
+} while (0)
+
struct ifmultiaddr;
struct rib_head;
@@ -415,6 +437,7 @@ int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
struct rib_head *rt_table_init(int);
void rt_table_destroy(struct rib_head *);
+u_int rt_tables_get_gen(int table, int fam);
int rtsock_addrmsg(int, struct ifaddr *, int);
int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
diff --git a/sys/net/route_var.h b/sys/net/route_var.h
index 86fc8a9..a8ef56a 100644
--- a/sys/net/route_var.h
+++ b/sys/net/route_var.h
@@ -41,7 +41,7 @@ struct rib_head {
rn_walktree_t *rnh_walktree; /* traverse tree */
rn_walktree_from_t *rnh_walktree_from; /* traverse tree below a */
rn_close_t *rnh_close; /*do something when the last ref drops*/
- u_int rnh_gen; /* generation counter */
+ rt_gen_t rnh_gen; /* generation counter */
int rnh_multipath; /* multipath capable ? */
struct radix_node rnh_nodes[3]; /* empty tree for common case */
struct rwlock rib_lock; /* config/data path lock */
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index d59ef70..810da1b 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -275,8 +275,6 @@ rts_attach(struct socket *so, int proto, struct thread *td)
/* XXX */
rp = malloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO);
- if (rp == NULL)
- return ENOBUFS;
so->so_pcb = (caddr_t)rp;
so->so_fibnum = td->td_proc->p_fibnum;
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 0a25392..f5fdd5a 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -317,6 +317,27 @@ struct ieee80211_wme_param {
} __packed;
/*
+ * WME U-APSD qos info field defines
+ */
+#define WME_CAPINFO_UAPSD_EN 0x00000080
+#define WME_CAPINFO_UAPSD_VO 0x00000001
+#define WME_CAPINFO_UAPSD_VI 0x00000002
+#define WME_CAPINFO_UAPSD_BK 0x00000004
+#define WME_CAPINFO_UAPSD_BE 0x00000008
+#define WME_CAPINFO_UAPSD_ACFLAGS_SHIFT 0
+#define WME_CAPINFO_UAPSD_ACFLAGS_MASK 0xF
+#define WME_CAPINFO_UAPSD_MAXSP_SHIFT 5
+#define WME_CAPINFO_UAPSD_MAXSP_MASK 0x3
+#define WME_CAPINFO_IE_OFFSET 8
+#define WME_UAPSD_MAXSP(_qosinfo) \
+ (((_qosinfo) >> WME_CAPINFO_UAPSD_MAXSP_SHIFT) & \
+ WME_CAPINFO_UAPSD_MAXSP_MASK)
+#define WME_UAPSD_AC_ENABLED(_ac, _qosinfo) \
+ ((1 << (3 - (_ac))) & ( \
+ ((_qosinfo) >> WME_CAPINFO_UAPSD_ACFLAGS_SHIFT) & \
+ WME_CAPINFO_UAPSD_ACFLAGS_MASK))
+
+/*
* Management Notification Frame
*/
struct ieee80211_mnf {
@@ -346,6 +367,7 @@ struct ieee80211_action {
#define IEEE80211_ACTION_CAT_MESH 13 /* Mesh */
#define IEEE80211_ACTION_CAT_SELF_PROT 15 /* Self-protected */
/* 16 - 125 reserved */
+#define IEEE80211_ACTION_VHT 21
#define IEEE80211_ACTION_CAT_VENDOR 127 /* Vendor Specific */
#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended xmit chan width*/
@@ -695,6 +717,151 @@ struct ieee80211_ie_htinfo {
#define IEEE80211_HTINFO_BASIC_STBCMCS_S 0
#define IEEE80211_HTINFO_DUALPROTECTED 0x80
+
+/*
+ * 802.11ac definitions - 802.11ac-2013 .
+ */
+
+/* VHT opmode bits */
+#define IEEE80211_VHT_OPMODE_CHANWIDTH_MASK 3
+#define IEEE80211_VHT_OPMODE_CHANWIDTH_20MHZ 0
+#define IEEE80211_VHT_OPMODE_CHANWIDTH_40MHZ 1
+#define IEEE80211_VHT_OPMODE_CHANWIDTH_80MHZ 2
+#define IEEE80211_VHT_OPMODE_CHANWIDTH_160MHZ 3
+#define IEEE80211_VHT_OPMODE_RX_NSS_MASK 0x70
+#define IEEE80211_VHT_OPMODE_RX_NSS_SHIFT 4
+#define IEEE80211_VHT_OPMODE_RX_NSS_TYPE_BF 0x80
+
+/*
+ * Maximum length of A-MPDU that the STA can RX in VHT.
+ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+#define IEEE80211_VHTCAP_MAX_AMPDU_8K 0
+#define IEEE80211_VHTCAP_MAX_AMPDU_16K 1
+#define IEEE80211_VHTCAP_MAX_AMPDU_32K 2
+#define IEEE80211_VHTCAP_MAX_AMPDU_64K 3
+#define IEEE80211_VHTCAP_MAX_AMPDU_128K 4
+#define IEEE80211_VHTCAP_MAX_AMPDU_256K 5
+#define IEEE80211_VHTCAP_MAX_AMPDU_512K 6
+#define IEEE80211_VHTCAP_MAX_AMPDU_1024K 7
+
+/*
+ * VHT MCS information.
+ * + rx_highest/tx_highest: optional; maximum long GI VHT PPDU
+ * data rate. 1Mbit/sec units.
+ * + rx_mcs_map/tx_mcs_map: bitmap of per-stream supported MCS;
+ * 2 bits each.
+ */
+#define IEEE80211_VHT_MCS_SUPPORT_0_7 0 /* MCS0-7 */
+#define IEEE80211_VHT_MCS_SUPPORT_0_8 1 /* MCS0-8 */
+#define IEEE80211_VHT_MCS_SUPPORT_0_9 2 /* MCS0-9 */
+#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 /* not supported */
+
+struct ieee80211_vht_mcs_info {
+ uint16_t rx_mcs_map;
+ uint16_t rx_highest;
+ uint16_t tx_mcs_map;
+ uint16_t tx_highest;
+} __packed;
+
+/* VHT capabilities element: 802.11ac-2013 8.4.2.160 */
+struct ieee80211_ie_vhtcap {
+ uint8_t ie;
+ uint8_t len;
+ uint32_t vht_cap_info;
+ struct ieee80211_vht_mcs_info supp_mcs;
+} __packed;
+
+#define IEEE80211_VHT_CHANWIDTH_USE_HT 0 /* Use HT IE for chw */
+#define IEEE80211_VHT_CHANWIDTH_80MHZ 1 /* 80MHz */
+#define IEEE80211_VHT_CHANWIDTH_160MHZ 2 /* 160MHz */
+#define IEEE80211_VHT_CHANWIDTH_80P80MHZ 3 /* 80+80MHz */
+
+/* VHT operation IE - 802.11ac-2013 8.4.2.161 */
+struct ieee80211_ie_vht_operation {
+ uint8_t ie;
+ uint8_t len;
+ uint8_t chan_width;
+ uint8_t center_freq_seg1_idx;
+ uint8_t center_freq_seg2_idx;
+ uint16_t basic_mcs_set;
+} __packed;
+
+/* 802.11ac VHT Capabilities */
+#define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 0x00000000
+#define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_7991 0x00000001
+#define IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454 0x00000002
+#define IEEE80211_VHTCAP_MAX_MPDU_MASK 0x00000003
+#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
+#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
+#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK 0x0000000C
+#define IEEE80211_VHTCAP_RXLDPC 0x00000010
+#define IEEE80211_VHTCAP_SHORT_GI_80 0x00000020
+#define IEEE80211_VHTCAP_SHORT_GI_160 0x00000040
+#define IEEE80211_VHTCAP_TXSTBC 0x00000080
+#define IEEE80211_VHTCAP_RXSTBC_1 0x00000100
+#define IEEE80211_VHTCAP_RXSTBC_2 0x00000200
+#define IEEE80211_VHTCAP_RXSTBC_3 0x00000300
+#define IEEE80211_VHTCAP_RXSTBC_4 0x00000400
+#define IEEE80211_VHTCAP_RXSTBC_MASK 0x00000700
+#define IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE 0x00000800
+#define IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE 0x00001000
+#define IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT 13
+#define IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK \
+ (7 << IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT)
+#define IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_SHIFT 16
+#define IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK \
+ (7 << IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_SHIFT)
+#define IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE 0x00080000
+#define IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE 0x00100000
+#define IEEE80211_VHTCAP_VHT_TXOP_PS 0x00200000
+#define IEEE80211_VHTCAP_HTC_VHT 0x00400000
+#define IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23
+#define IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
+ (7 << IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT)
+#define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000
+#define IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
+#define IEEE80211_VHTCAP_RX_ANTENNA_PATTERN 0x10000000
+#define IEEE80211_VHTCAP_TX_ANTENNA_PATTERN 0x20000000
+
+/*
+ * VHT Transmit Power Envelope element - 802.11ac-2013 8.4.2.164
+ *
+ * This defines the maximum transmit power for various bandwidths.
+ */
+/*
+ * Count is how many elements follow and what they're for:
+ *
+ * 0 - 20 MHz
+ * 1 - 20+40 MHz
+ * 2 - 20+40+80 MHz
+ * 3 - 20+40+80+(160, 80+80) MHz
+ */
+#define IEEE80211_VHT_TXPWRENV_INFO_COUNT_SHIFT 0
+#define IEEE80211_VHT_TXPWRENV_INFO_COUNT_MASK 0x07
+
+/*
+ * Unit is the tx power representation. It should be EIRP for now;
+ * other values are reserved.
+ */
+#define IEEE80211_VHT_TXPWRENV_UNIT_MASK 0x38
+#define IEEE80211_VHT_TXPWRENV_UNIT_SHIFT 3
+
+/* This value is within the unit mask/shift above */
+#define IEEE80211_VHT_TXPWRENV_UNIT_EIRP 0
+
+struct ieee80211_ie_vht_txpwrenv {
+ uint8_t ie;
+ uint8_t len;
+ uint8_t tx_info;
+ int8_t tx_elem[0]; /* TX power elements, 1/2 dB, signed */
+};
+
+/* VHT action codes */
+#define WLAN_ACTION_VHT_COMPRESSED_BF 0
+#define WLAN_ACTION_VHT_GROUPID_MGMT 1
+#define WLAN_ACTION_VHT_OPMODE_NOTIF 2
+
/*
* Management information element payloads.
*/
@@ -709,6 +876,8 @@ enum {
IEEE80211_ELEMID_IBSSPARMS = 6,
IEEE80211_ELEMID_COUNTRY = 7,
IEEE80211_ELEMID_BSSLOAD = 11,
+ IEEE80211_ELEMID_TSPEC = 13,
+ IEEE80211_ELEMID_TCLAS = 14,
IEEE80211_ELEMID_CHALLENGE = 16,
/* 17-31 reserved for challenge text extension */
IEEE80211_ELEMID_PWRCNSTR = 32,
@@ -728,6 +897,17 @@ enum {
IEEE80211_ELEMID_XRATES = 50,
IEEE80211_ELEMID_APCHANREP = 51,
IEEE80211_ELEMID_HTINFO = 61,
+ IEEE80211_ELEMID_SECCHAN_OFFSET = 62,
+ IEEE80211_ELEMID_RRM_ENACAPS = 70,
+ IEEE80211_ELEMID_MULTIBSSID = 71,
+ IEEE80211_ELEMID_COEX_2040 = 72,
+ IEEE80211_ELEMID_INTOL_CHN_REPORT = 73,
+ IEEE80211_ELEMID_OVERLAP_BSS_SCAN_PARAM = 74,
+ IEEE80211_ELEMID_TSF_REQ = 91,
+ IEEE80211_ELEMID_TSF_RESP = 92,
+ IEEE80211_ELEMID_WNM_SLEEP_MODE = 93,
+ IEEE80211_ELEMID_TIM_BCAST_REQ = 94,
+ IEEE80211_ELEMID_TIM_BCAST_RESP = 95,
IEEE80211_ELEMID_TPC = 150,
IEEE80211_ELEMID_CCKM = 156,
IEEE80211_ELEMID_VENDOR = 221, /* vendor private */
@@ -751,7 +931,7 @@ enum {
IEEE80211_ELEMID_MESHGANN = 125,
IEEE80211_ELEMID_MESHRANN = 126,
/* 127 Extended Capabilities */
- IEEE80211_ELEMID_MESHEXTCAP = 127,
+ IEEE80211_ELEMID_EXTCAP = 127,
/* 128-129 reserved */
IEEE80211_ELEMID_MESHPREQ = 130,
IEEE80211_ELEMID_MESHPREP = 131,
@@ -760,6 +940,11 @@ enum {
IEEE80211_ELEMID_MESHPXU = 137,
IEEE80211_ELEMID_MESHPXUC = 138,
IEEE80211_ELEMID_MESHAH = 60, /* XXX: remove */
+
+ /* 802.11ac */
+ IEEE80211_ELEMID_VHT_CAP = 191,
+ IEEE80211_ELEMID_VHT_OPMODE = 192,
+ IEEE80211_ELEMID_VHT_PWR_ENV = 195,
};
struct ieee80211_tim_ie {
diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c
index f50334e..7460223 100644
--- a/sys/net80211/ieee80211_amrr.c
+++ b/sys/net80211/ieee80211_amrr.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/sbuf.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
@@ -75,6 +76,7 @@ static void amrr_tx_update(const struct ieee80211vap *vap,
const struct ieee80211_node *, void *, void *, void *);
static void amrr_sysctlattach(struct ieee80211vap *,
struct sysctl_ctx_list *, struct sysctl_oid *);
+static void amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s);
/* number of references from net80211 layer */
static int nrefs = 0;
@@ -91,6 +93,7 @@ static const struct ieee80211_ratectl amrr = {
.ir_tx_complete = amrr_tx_complete,
.ir_tx_update = amrr_tx_update,
.ir_setinterval = amrr_setinterval,
+ .ir_node_stats = amrr_node_stats,
};
IEEE80211_RATECTL_MODULE(amrr, 1);
IEEE80211_RATECTL_ALG(amrr, IEEE80211_RATECTL_AMRR, amrr);
@@ -410,3 +413,31 @@ amrr_sysctlattach(struct ieee80211vap *vap,
"amrr_min_sucess_threshold", CTLFLAG_RW,
&amrr->amrr_min_success_threshold, 0, "");
}
+
+static void
+amrr_node_stats(struct ieee80211_node *ni, struct sbuf *s)
+{
+ int rate;
+ struct ieee80211_amrr_node *amn = ni->ni_rctls;
+ struct ieee80211_rateset *rs;
+
+ /* XXX TODO: check locking? */
+
+ /* XXX TODO: this should be a method */
+ if (amrr_node_is_11n(ni)) {
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ sbuf_printf(s, "rate: MCS %d\n", rate);
+ } else {
+ rs = &ni->ni_rates;
+ rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ sbuf_printf(s, "rate: %d Mbit\n", rate / 2);
+ }
+
+ sbuf_printf(s, "ticks: %d\n", amn->amn_ticks);
+ sbuf_printf(s, "txcnt: %u\n", amn->amn_txcnt);
+ sbuf_printf(s, "success: %u\n", amn->amn_success);
+ sbuf_printf(s, "success_threshold: %u\n", amn->amn_success_threshold);
+ sbuf_printf(s, "recovery: %u\n", amn->amn_recovery);
+ sbuf_printf(s, "retry_cnt: %u\n", amn->amn_retrycnt);
+}
diff --git a/sys/net80211/ieee80211_dfs.c b/sys/net80211/ieee80211_dfs.c
index 232ceb7..4478d9e 100644
--- a/sys/net80211/ieee80211_dfs.c
+++ b/sys/net80211/ieee80211_dfs.c
@@ -245,7 +245,7 @@ dfs_timeout(void *arg)
for (i = 0; i < ic->ic_nchans; i++) {
c = &ic->ic_channels[i];
if (IEEE80211_IS_CHAN_RADAR(c)) {
- if (time_after_eq(now, dfs->nol_event[i]+NOL_TIMEOUT)) {
+ if (ieee80211_time_after_eq(now, dfs->nol_event[i]+NOL_TIMEOUT)) {
c->ic_state &= ~IEEE80211_CHANSTATE_RADAR;
if (c->ic_state & IEEE80211_CHANSTATE_NORADAR) {
/*
diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h
index 0566da7..62f3335 100644
--- a/sys/net80211/ieee80211_freebsd.h
+++ b/sys/net80211/ieee80211_freebsd.h
@@ -251,10 +251,10 @@ void ieee80211_vap_destroy(struct ieee80211vap *);
#define ticks_to_msecs(t) (1000*(t) / hz)
#define ticks_to_secs(t) ((t) / hz)
-#define time_after(a,b) ((long)(b) - (long)(a) < 0)
-#define time_before(a,b) time_after(b,a)
-#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)
-#define time_before_eq(a,b) time_after_eq(b,a)
+#define ieee80211_time_after(a,b) ((long)(b) - (long)(a) < 0)
+#define ieee80211_time_before(a,b) ieee80211_time_after(b,a)
+#define ieee80211_time_after_eq(a,b) ((long)(a) - (long)(b) >= 0)
+#define ieee80211_time_before_eq(a,b) ieee80211_time_after_eq(b,a)
struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen);
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 1a21734..be380e9 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -1406,7 +1406,7 @@ ieee80211_ht_timeout(struct ieee80211com *ic)
IEEE80211_LOCK_ASSERT(ic);
if ((ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) &&
- time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
+ ieee80211_time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
#if 0
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
"%s", "time out non-HT STA present on channel");
diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c
index 6bbc32c..0c920d8 100644
--- a/sys/net80211/ieee80211_hwmp.c
+++ b/sys/net80211/ieee80211_hwmp.c
@@ -260,7 +260,7 @@ ieee80211_hwmp_init(void)
}
SYSINIT(wlan_hwmp, SI_SUB_DRIVERS, SI_ORDER_SECOND, ieee80211_hwmp_init, NULL);
-void
+static void
hwmp_vattach(struct ieee80211vap *vap)
{
struct ieee80211_hwmp_state *hs;
@@ -279,7 +279,7 @@ hwmp_vattach(struct ieee80211vap *vap)
vap->iv_hwmp = hs;
}
-void
+static void
hwmp_vdetach(struct ieee80211vap *vap)
{
struct ieee80211_hwmp_state *hs = vap->iv_hwmp;
@@ -289,7 +289,7 @@ hwmp_vdetach(struct ieee80211vap *vap)
vap->iv_hwmp = NULL;
}
-int
+static int
hwmp_newstate(struct ieee80211vap *vap, enum ieee80211_state ostate, int arg)
{
enum ieee80211_state nstate = vap->iv_state;
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 3b4379f..5c2f9e5 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -603,9 +603,10 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
case IEEE80211_ELEMID_MESHCONF:
scan->meshconf = frm;
break;
- case IEEE80211_ELEMID_MESHEXTCAP:
- break;
#endif
+ /* Extended capabilities; nothing handles it for now */
+ case IEEE80211_ELEMID_EXTCAP:
+ break;
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(frm))
scan->wpa = frm;
diff --git a/sys/net80211/ieee80211_ioctl.h b/sys/net80211/ieee80211_ioctl.h
index ee98026..8c606c1 100644
--- a/sys/net80211/ieee80211_ioctl.h
+++ b/sys/net80211/ieee80211_ioctl.h
@@ -246,7 +246,10 @@ struct ieee80211_stats {
uint32_t is_ampdu_bar_tx_retry; /* A-MPDU BAR frames TX rtry */
uint32_t is_ampdu_bar_tx_fail; /* A-MPDU BAR frames TX fail */
- uint32_t is_spare[7];
+ uint32_t is_ff_encapfail; /* failed FF encap */
+ uint32_t is_amsdu_encapfail; /* failed A-MSDU encap */
+
+ uint32_t is_spare[5];
};
/*
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index 6ac3655..520687b 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -2638,7 +2638,7 @@ ieee80211_erp_timeout(struct ieee80211com *ic)
IEEE80211_LOCK_ASSERT(ic);
if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
- time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
+ ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
#if 0
IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
"%s", "age out non-ERP sta present on channel");
diff --git a/sys/net80211/ieee80211_power.c b/sys/net80211/ieee80211_power.c
index 587e48f..4493ed6 100644
--- a/sys/net80211/ieee80211_power.c
+++ b/sys/net80211/ieee80211_power.c
@@ -623,7 +623,7 @@ ieee80211_sta_ps_timer_check(struct ieee80211vap *vap)
/* If we've done any data within our idle interval, bail */
/* XXX hard-coded to one second for now, ew! */
- if (time_after(ic->ic_lastdata + 500, ticks))
+ if (ieee80211_time_after(ic->ic_lastdata + 500, ticks))
goto out;
/*
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 3bc3141..2feb59a 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1531,7 +1531,7 @@ beacon_miss(void *arg, int npending)
IEEE80211_LOCK(ic);
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
/*
- * We only pass events through for sta vap's in RUN state;
+ * We only pass events through for sta vap's in RUN+ state;
* may be too restrictive but for now this saves all the
* handlers duplicating these checks.
*/
@@ -1550,7 +1550,7 @@ beacon_swmiss(void *arg, int npending)
struct ieee80211com *ic = vap->iv_ic;
IEEE80211_LOCK(ic);
- if (vap->iv_state == IEEE80211_S_RUN) {
+ if (vap->iv_state >= IEEE80211_S_RUN) {
/* XXX Call multiple times if npending > zero? */
vap->iv_bmiss(vap);
}
@@ -1570,8 +1570,7 @@ ieee80211_swbmiss(void *arg)
IEEE80211_LOCK_ASSERT(ic);
- /* XXX sleep state? */
- KASSERT(vap->iv_state == IEEE80211_S_RUN,
+ KASSERT(vap->iv_state >= IEEE80211_S_RUN,
("wrong state %d", vap->iv_state));
if (ic->ic_flags & IEEE80211_F_SCAN) {
diff --git a/sys/net80211/ieee80211_ratectl.c b/sys/net80211/ieee80211_ratectl.c
index 3eff898..e9a0e2f 100644
--- a/sys/net80211/ieee80211_ratectl.c
+++ b/sys/net80211/ieee80211_ratectl.c
@@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/sbuf.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/malloc.h>
@@ -68,12 +69,52 @@ ieee80211_ratectl_unregister(int type)
ratectls[type] = NULL;
}
+static void
+ieee80211_ratectl_sysctl_stats_node_iter(void *arg, struct ieee80211_node *ni)
+{
+
+ struct sbuf *sb = (struct sbuf *) arg;
+ sbuf_printf(sb, "MAC: %6D\n", ni->ni_macaddr, ":");
+ ieee80211_ratectl_node_stats(ni, sb);
+ sbuf_printf(sb, "\n");
+}
+
+static int
+ieee80211_ratectl_sysctl_stats(SYSCTL_HANDLER_ARGS)
+{
+ struct ieee80211vap *vap = arg1;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct sbuf sb;
+ int error;
+
+ error = sysctl_wire_old_buffer(req, 0);
+ if (error)
+ return (error);
+ sbuf_new_for_sysctl(&sb, NULL, 8, req);
+ sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
+
+ IEEE80211_LOCK(ic);
+ ieee80211_iterate_nodes(&ic->ic_sta,
+ ieee80211_ratectl_sysctl_stats_node_iter,
+ &sb);
+ IEEE80211_UNLOCK(ic);
+
+ error = sbuf_finish(&sb);
+ sbuf_delete(&sb);
+ return (error);
+}
+
void
ieee80211_ratectl_init(struct ieee80211vap *vap)
{
if (vap->iv_rate == ratectls[IEEE80211_RATECTL_NONE])
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_AMRR);
vap->iv_rate->ir_init(vap);
+
+ /* Attach generic stats sysctl */
+ SYSCTL_ADD_PROC(vap->iv_sysctl, SYSCTL_CHILDREN(vap->iv_oid), OID_AUTO,
+ "rate_stats", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, vap,
+ 0, ieee80211_ratectl_sysctl_stats, "A", "ratectl node stats");
}
void
diff --git a/sys/net80211/ieee80211_ratectl.h b/sys/net80211/ieee80211_ratectl.h
index 5603509..9765fe7 100644
--- a/sys/net80211/ieee80211_ratectl.h
+++ b/sys/net80211/ieee80211_ratectl.h
@@ -53,6 +53,7 @@ struct ieee80211_ratectl {
const struct ieee80211_node *,
void *, void *, void *);
void (*ir_setinterval)(const struct ieee80211vap *, int);
+ void (*ir_node_stats)(struct ieee80211_node *ni, struct sbuf *s);
};
void ieee80211_ratectl_register(int, const struct ieee80211_ratectl *);
@@ -115,3 +116,13 @@ ieee80211_ratectl_setinterval(const struct ieee80211vap *vap, int msecs)
return;
vap->iv_rate->ir_setinterval(vap, msecs);
}
+
+static __inline void
+ieee80211_ratectl_node_stats(struct ieee80211_node *ni, struct sbuf *s)
+{
+ const struct ieee80211vap *vap = ni->ni_vap;
+
+ if (vap->iv_rate->ir_node_stats == NULL)
+ return;
+ vap->iv_rate->ir_node_stats(ni, s);
+}
diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c
index 07df92f..233c436 100644
--- a/sys/net80211/ieee80211_scan_sta.c
+++ b/sys/net80211/ieee80211_scan_sta.c
@@ -1323,7 +1323,7 @@ sta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
* XXX deauth current ap
*/
if (curRate < roamRate || curRssi < roamRssi) {
- if (time_after(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
+ if (ieee80211_time_after(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
/*
* Scan cache contents are too old; force a scan now
* if possible so we have current state to make a
@@ -1333,7 +1333,7 @@ sta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
* XXX force immediate switch on scan complete
*/
if (!IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) &&
- time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle))
+ ieee80211_time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle))
ieee80211_bg_scan(vap, 0);
return;
}
diff --git a/sys/net80211/ieee80211_scan_sw.c b/sys/net80211/ieee80211_scan_sw.c
index fc62f24..5875980 100644
--- a/sys/net80211/ieee80211_scan_sw.c
+++ b/sys/net80211/ieee80211_scan_sw.c
@@ -304,7 +304,7 @@ ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan,
}
if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
(flags & IEEE80211_SCAN_FLUSH) == 0 &&
- time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
+ ieee80211_time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
/*
* We're not currently scanning and the cache is
* deemed hot enough to consult. Lock out others
@@ -674,7 +674,7 @@ end:
if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
(ss_priv->ss_iflags & ISCAN_ABORT) ||
- time_after(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
+ ieee80211_time_after(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
ss_priv->ss_iflags &= ~ISCAN_RUNNING;
scan_end(ss, scandone);
return;
@@ -686,7 +686,7 @@ end:
/*
* Watch for truncation due to the scan end time.
*/
- if (time_after(ticks + ss->ss_maxdwell, ss_priv->ss_scanend))
+ if (ieee80211_time_after(ticks + ss->ss_maxdwell, ss_priv->ss_scanend))
maxdwell = ss_priv->ss_scanend - ticks;
else
maxdwell = ss->ss_maxdwell;
@@ -807,7 +807,7 @@ scan_end(struct ieee80211_scan_state *ss, int scandone)
if ((ss_priv->ss_iflags & ISCAN_CANCEL) == 0 &&
!ss->ss_ops->scan_end(ss, vap) &&
(ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
- time_before(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
+ ieee80211_time_before(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: done, restart "
"[ticks %u, dwell min %lu scanend %lu]\n",
@@ -923,7 +923,7 @@ ieee80211_swscan_add_scan(struct ieee80211vap *vap,
* the timer so we'll switch to the next channel.
*/
if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 &&
- time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
+ ieee80211_time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
"%s: chan %3d%c min dwell met (%u > %lu)\n",
__func__,
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index ee14ffd..16d801c 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -206,6 +206,24 @@ sta_authretry(struct ieee80211vap *vap, struct ieee80211_node *ni, int reason)
}
}
+static void
+sta_swbmiss_start(struct ieee80211vap *vap)
+{
+
+ if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) {
+ /*
+ * Start s/w beacon miss timer for devices w/o
+ * hardware support. We fudge a bit here since
+ * we're doing this in software.
+ */
+ vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
+ 2 * vap->iv_bmissthreshold * vap->iv_bss->ni_intval);
+ vap->iv_swbmiss_count = 0;
+ callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
+ ieee80211_swbmiss, vap);
+ }
+}
+
/*
* IEEE80211_M_STA vap state machine handler.
* This routine handles the main states in the 802.11 protocol.
@@ -341,12 +359,13 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
break;
}
break;
+ case IEEE80211_S_SLEEP:
case IEEE80211_S_RUN:
switch (arg & 0xff) {
case IEEE80211_FC0_SUBTYPE_AUTH:
IEEE80211_SEND_MGMT(ni,
IEEE80211_FC0_SUBTYPE_AUTH, 2);
- vap->iv_state = ostate; /* stay RUN */
+ vap->iv_state = IEEE80211_S_RUN; /* stay RUN */
break;
case IEEE80211_FC0_SUBTYPE_DEAUTH:
ieee80211_sta_leave(ni);
@@ -418,19 +437,8 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
goto invalid;
}
ieee80211_sync_curchan(ic);
- if (ostate != IEEE80211_S_RUN &&
- (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
- /*
- * Start s/w beacon miss timer for devices w/o
- * hardware support. We fudge a bit here since
- * we're doing this in software.
- */
- vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
- 2 * vap->iv_bmissthreshold * ni->ni_intval);
- vap->iv_swbmiss_count = 0;
- callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
- ieee80211_swbmiss, vap);
- }
+ if (ostate != IEEE80211_S_RUN)
+ sta_swbmiss_start(vap);
/*
* When 802.1x is not in use mark the port authorized
* at this point so traffic can flow.
@@ -450,6 +458,7 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
goto invalid;
break;
case IEEE80211_S_SLEEP:
+ sta_swbmiss_start(vap);
vap->iv_sta_ps(vap, 1);
break;
default:
@@ -1244,7 +1253,7 @@ contbgscan(struct ieee80211vap *vap)
return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
(ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 &&
vap->iv_state == IEEE80211_S_RUN && /* XXX? */
- time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
+ ieee80211_time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
}
/*
@@ -1265,8 +1274,8 @@ startbgscan(struct ieee80211vap *vap)
#ifdef IEEE80211_SUPPORT_SUPERG
!IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) &&
#endif
- time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) &&
- time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
+ ieee80211_time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) &&
+ ieee80211_time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle));
}
static void
diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c
index 03d9c60..7fe91cc 100644
--- a/sys/net80211/ieee80211_wds.c
+++ b/sys/net80211/ieee80211_wds.c
@@ -288,9 +288,11 @@ ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
/*
* Encapsulate the packet in prep for transmission.
*/
+ IEEE80211_TX_LOCK(ic);
mcopy = ieee80211_encap(vap, ni, mcopy);
if (mcopy == NULL) {
/* NB: stat+msg handled in ieee80211_encap */
+ IEEE80211_TX_UNLOCK(ic);
ieee80211_free_node(ni);
continue;
}
@@ -298,6 +300,7 @@ ieee80211_dwds_mcast(struct ieee80211vap *vap0, struct mbuf *m)
mcopy->m_pkthdr.rcvif = (void *) ni;
err = ieee80211_parent_xmitpkt(ic, mcopy);
+ IEEE80211_TX_UNLOCK(ic);
if (!err) {
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index ec42e67..50e5d6e 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1298,6 +1298,11 @@ in_pcbfree(struct inpcb *inp)
if (inp->inp_moptions != NULL)
inp_freemoptions(inp->inp_moptions);
#endif
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
+
inp->inp_vflag = 0;
inp->inp_flags2 |= INP_FREED;
crfree(inp->inp_cred);
@@ -2225,6 +2230,23 @@ in_pcbremlists(struct inpcb *inp)
}
/*
+ * Check for alternatives when higher level complains
+ * about service problems. For now, invalidate cached
+ * routing information. If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+void
+in_losing(struct inpcb *inp)
+{
+
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
+ return;
+}
+
+/*
* A set label operation has occurred at the socket layer, propagate the
* label change into the in_pcb for the socket.
*/
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 54eab88..9c77a51 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -42,6 +42,7 @@
#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/_rwlock.h>
+#include <net/route.h>
#ifdef _KERNEL
#include <sys/lock.h>
@@ -238,8 +239,14 @@ struct inpcb {
#define inp_zero_size offsetof(struct inpcb, inp_gencnt)
inp_gen_t inp_gencnt; /* (c) generation count */
struct llentry *inp_lle; /* cached L2 information */
- struct rtentry *inp_rt; /* cached L3 information */
struct rwlock inp_lock;
+ rt_gen_t inp_rt_cookie; /* generation for route entry */
+ union { /* cached L3 information */
+ struct route inpu_route;
+ struct route_in6 inpu_route6;
+ } inp_rtu;
+#define inp_route inp_rtu.inpu_route
+#define inp_route6 inp_rtu.inpu_route6
};
#define inp_fport inp_inc.inc_fport
#define inp_lport inp_inc.inc_lport
@@ -722,6 +729,7 @@ void in_pcbrehash_mbuf(struct inpcb *, struct mbuf *);
int in_pcbrele(struct inpcb *);
int in_pcbrele_rlocked(struct inpcb *);
int in_pcbrele_wlocked(struct inpcb *);
+void in_losing(struct inpcb *);
void in_pcbsetsolabel(struct socket *so);
int in_getpeeraddr(struct socket *so, struct sockaddr **nam);
int in_getsockaddr(struct socket *so, struct sockaddr **nam);
diff --git a/sys/netinet/in_pcbgroup.c b/sys/netinet/in_pcbgroup.c
index 2d3c136..04a7699 100644
--- a/sys/netinet/in_pcbgroup.c
+++ b/sys/netinet/in_pcbgroup.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/smp.h>
+#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/rss_config.h>
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index fa225fc..afdf1a7 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -282,17 +282,36 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
gw = dst = (struct sockaddr_in *)&ro->ro_dst;
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m);
rte = ro->ro_rt;
- /*
- * The address family should also be checked in case of sharing
- * the cache with IPv6.
- */
- if (rte == NULL || dst->sin_family != AF_INET) {
+ if (rte == NULL) {
bzero(dst, sizeof(*dst));
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = ip->ip_dst;
}
again:
+ /*
+ * Validate route against routing table additions;
+ * a better/more specific route might have been added.
+ */
+ if (inp)
+ RT_VALIDATE(ro, &inp->inp_rt_cookie, fibnum);
+ /*
+ * If there is a cached route,
+ * check that it is to the same destination
+ * and is still up. If not, free it and try again.
+ * The address family should also be checked in case of sharing the
+ * cache with IPv6.
+ * Also check whether routing cache needs invalidation.
+ */
+ rte = ro->ro_rt;
+ if (rte && ((rte->rt_flags & RTF_UP) == 0 ||
+ rte->rt_ifp == NULL ||
+ !RT_LINK_IS_UP(rte->rt_ifp) ||
+ dst->sin_family != AF_INET ||
+ dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
+ RTFREE(rte);
+ rte = ro->ro_rt = (struct rtentry *)NULL;
+ }
ia = NULL;
have_ia_ref = 0;
/*
diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c
index 0bddcfd..0ad3e33 100644
--- a/sys/netinet/sctp_cc_functions.c
+++ b/sys/netinet/sctp_cc_functions.c
@@ -1526,13 +1526,13 @@ sctp_rtt_rtcc_calculated(struct sctp_tcb *stcb SCTP_UNUSED,
struct sctp_hs_raise_drop {
int32_t cwnd;
- int32_t increase;
- int32_t drop_percent;
+ int8_t increase;
+ int8_t drop_percent;
};
#define SCTP_HS_TABLE_SIZE 73
-struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
+static const struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
{38, 1, 50}, /* 0 */
{118, 2, 44}, /* 1 */
{221, 3, 41}, /* 2 */
@@ -1632,7 +1632,7 @@ sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
}
}
net->last_hs_used = indx;
- incr = ((sctp_cwnd_adjust[indx].increase) << 10);
+ incr = (((int32_t) sctp_cwnd_adjust[indx].increase) << 10);
net->cwnd += incr;
}
sctp_enforce_cwnd_limit(&stcb->asoc, net);
@@ -1658,7 +1658,7 @@ sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
} else {
/* drop by the proper amount */
net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
- sctp_cwnd_adjust[net->last_hs_used].drop_percent);
+ (int32_t) sctp_cwnd_adjust[net->last_hs_used].drop_percent);
net->cwnd = net->ssthresh;
/* now where are we */
indx = net->last_hs_used;
@@ -2323,7 +2323,7 @@ sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
}
}
-struct sctp_cc_functions sctp_cc_functions[] = {
+const struct sctp_cc_functions sctp_cc_functions[] = {
{
.sctp_set_initial_cc_param = sctp_set_initial_cc_param,
.sctp_cwnd_update_after_sack = sctp_cwnd_update_after_sack,
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 5837f6f..497dde6 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -68,6 +68,8 @@ __FBSDID("$FreeBSD$");
/* Largest length of a chunk */
#define SCTP_MAX_CHUNK_LENGTH 0xffff
+/* Largest length of an error cause */
+#define SCTP_MAX_CAUSE_LENGTH 0xffff
/* Number of addresses where we just skip the counting */
#define SCTP_COUNT_LIMIT 40
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 75c1ac5..cbc7fb5 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -1948,7 +1948,7 @@ finish_express_del:
return (1);
}
-int8_t sctp_map_lookup_tab[256] = {
+static const int8_t sctp_map_lookup_tab[256] = {
0, 1, 0, 2, 0, 1, 0, 3,
0, 1, 0, 2, 0, 1, 0, 4,
0, 1, 0, 2, 0, 1, 0, 3,
@@ -2495,7 +2495,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
if (op_err != NULL) {
cause = mtod(op_err, struct sctp_gen_error_cause *);
cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
- cause->length = htons(chk_length + sizeof(struct sctp_gen_error_cause));
+ cause->length = htons((uint16_t) (chk_length + sizeof(struct sctp_gen_error_cause)));
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, chk_length, M_NOWAIT);
if (SCTP_BUF_NEXT(op_err) != NULL) {
@@ -2688,7 +2688,7 @@ sctp_process_segment_range(struct sctp_tcb *stcb, struct sctp_tmit_chunk **p_tp1
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_GAP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
sctp_flight_size_decrease(tp1);
@@ -2897,7 +2897,7 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
sctp_flight_size_increase(tp1);
@@ -3211,7 +3211,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND,
(tp1->whoTo ? (tp1->whoTo->flight_size) : 0),
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
if (tp1->whoTo) {
@@ -3523,7 +3523,7 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_DWN_WP_FWD,
tp1->whoTo ? tp1->whoTo->flight_size : 0,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
return;
}
@@ -3542,7 +3542,7 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
}
@@ -3661,7 +3661,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
sctp_flight_size_decrease(tp1);
@@ -4302,7 +4302,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_CA,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
sctp_flight_size_decrease(tp1);
@@ -4575,7 +4575,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) tp1->whoTo,
+ (uint32_t) (uintptr_t) tp1->whoTo,
tp1->rec.data.TSN_seq);
}
sctp_flight_size_increase(tp1);
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index a205f2f..c555be2 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -2358,7 +2358,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
SCTP_RTT_FROM_NON_DATA);
#if defined(INET) || defined(INET6)
if (((*netp)->port == 0) && (port != 0)) {
- sctp_pathmtu_adjustment(stcb, (*netp)->mtu - sizeof(struct udphdr));
+ sctp_pathmtu_adjustment(stcb, (uint16_t) ((*netp)->mtu - sizeof(struct udphdr)));
}
(*netp)->port = port;
#endif
@@ -3339,7 +3339,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PDRP,
tp1->whoTo->flight_size,
tp1->book_size,
- (uintptr_t) stcb,
+ (uint32_t) (uintptr_t) stcb,
tp1->rec.data.TSN_seq);
}
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
@@ -5596,7 +5596,7 @@ process_control_chunks:
len = min(SCTP_SIZE32(chk_length), (uint32_t) (length - *offset));
cause = mtod(op_err, struct sctp_gen_error_cause *);
cause->code = htons(SCTP_CAUSE_UNRECOG_CHUNK);
- cause->length = htons(len + sizeof(struct sctp_gen_error_cause));
+ cause->length = htons((uint16_t) (len + sizeof(struct sctp_gen_error_cause)));
SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause);
SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(m, *offset, len, M_NOWAIT);
if (SCTP_BUF_NEXT(op_err) != NULL) {
@@ -6033,7 +6033,9 @@ trigger_send:
if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
cnt_ctrl_ready = stcb->asoc.ctrl_queue_cnt - stcb->asoc.ecn_echo_cnt_onq;
}
- if (cnt_ctrl_ready || stcb->asoc.trigger_reset ||
+ if (!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue) ||
+ cnt_ctrl_ready ||
+ stcb->asoc.trigger_reset ||
((un_sent) &&
(stcb->asoc.peers_rwnd > 0 ||
(stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) {
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index a900106..8eda473 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -67,7 +67,7 @@ struct sack_track {
struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY];
};
-struct sack_track sack_array[256] = {
+const struct sack_track sack_array[256] = {
{0, 0, 0, 0, /* 0x00 */
{{0, 0},
{0, 0},
@@ -3508,7 +3508,7 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
return (found);
}
/* It is exactly what we want. Copy it out. */
- m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), cpsize, (caddr_t)data);
+ m_copydata(control, at + CMSG_ALIGN(sizeof(cmh)), (int)cpsize, (caddr_t)data);
return (1);
} else {
struct sctp_sndrcvinfo *sndrcvinfo;
@@ -4186,7 +4186,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip));
+ udp->uh_ulen = htons((uint16_t) (packet_length - sizeof(struct ip)));
if (V_udp_cksum) {
udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP));
} else {
@@ -4414,7 +4414,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else {
ip6h->ip6_nxt = IPPROTO_SCTP;
}
- ip6h->ip6_plen = (packet_length - sizeof(struct ip6_hdr));
+ ip6h->ip6_plen = (uint16_t) (packet_length - sizeof(struct ip6_hdr));
ip6h->ip6_dst = sin6->sin6_addr;
/*
@@ -4533,7 +4533,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr));
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
- udp->uh_ulen = htons(packet_length - sizeof(struct ip6_hdr));
+ udp->uh_ulen = htons((uint16_t) (packet_length - sizeof(struct ip6_hdr)));
udp->uh_sum = 0;
sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr));
} else {
@@ -6479,10 +6479,10 @@ error_out:
}
}
/* get the new end of length */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
} else {
/* how much is left at the end? */
- len = M_TRAILINGSPACE(*endofchain);
+ len = (int)M_TRAILINGSPACE(*endofchain);
}
/* Find the end of the data, for appending */
cp = (mtod((*endofchain), caddr_t)+SCTP_BUF_LEN((*endofchain)));
@@ -6636,7 +6636,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
ph = mtod(m, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + ca->sndlen);
+ ph->param_length = htons((uint16_t) (sizeof(struct sctp_paramhdr) + ca->sndlen));
}
/*
* We add one here to keep the assoc from dis-appearing on
@@ -6814,7 +6814,7 @@ sctp_copy_out_all(struct uio *uio, int len)
left = len;
SCTP_BUF_LEN(ret) = 0;
/* save space for the data chunk header */
- cancpy = M_TRAILINGSPACE(ret);
+ cancpy = (int)M_TRAILINGSPACE(ret);
willcpy = min(cancpy, left);
at = ret;
while (left > 0) {
@@ -6835,7 +6835,7 @@ sctp_copy_out_all(struct uio *uio, int len)
}
at = SCTP_BUF_NEXT(at);
SCTP_BUF_LEN(at) = 0;
- cancpy = M_TRAILINGSPACE(at);
+ cancpy = (int)M_TRAILINGSPACE(at);
willcpy = min(cancpy, left);
}
}
@@ -6869,7 +6869,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL;
/* get length and mbuf chain */
if (uio) {
- ca->sndlen = uio->uio_resid;
+ ca->sndlen = (int)uio->uio_resid;
ca->m = sctp_copy_out_all(uio, ca->sndlen);
if (ca->m == NULL) {
SCTP_FREE(ca, SCTP_M_COPYAL);
@@ -7019,7 +7019,7 @@ all_done:
sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t) data_list[i]->whoTo,
+ (uint32_t) (uintptr_t) data_list[i]->whoTo,
data_list[i]->rec.data.TSN_seq);
}
sctp_flight_size_increase(data_list[i]);
@@ -7516,7 +7516,7 @@ dont_do_it:
goto out_of;
}
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
- chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk));
+ chk->book_size = chk->send_size = (uint16_t) (to_move + sizeof(struct sctp_data_chunk));
chk->book_size_scale = 0;
chk->sent = SCTP_DATAGRAM_UNSENT;
@@ -7551,7 +7551,7 @@ dont_do_it:
chk->rec.data.TSN_seq = atomic_fetchadd_int(&asoc->sending_seq, 1);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) {
sctp_misc_ints(SCTP_STRMOUT_LOG_SEND,
- (uintptr_t) stcb, sp->length,
+ (uint32_t) (uintptr_t) stcb, sp->length,
(uint32_t) ((chk->rec.data.stream_number << 16) | chk->rec.data.stream_seq),
chk->rec.data.TSN_seq);
}
@@ -8943,6 +8943,8 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err)
chk->asoc = &stcb->asoc;
chk->data = op_err;
chk->whoTo = NULL;
+ chk->rec.chunk_id.id = SCTP_OPERATION_ERROR;
+ chk->rec.chunk_id.can_take_data = 0;
hdr = mtod(op_err, struct sctp_chunkhdr *);
hdr->chunk_type = SCTP_OPERATION_ERROR;
hdr->chunk_flags = 0;
@@ -9827,7 +9829,7 @@ one_chunk_around:
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND,
data_list[i]->whoTo->flight_size,
data_list[i]->book_size,
- (uintptr_t) data_list[i]->whoTo,
+ (uint32_t) (uintptr_t) data_list[i]->whoTo,
data_list[i]->rec.data.TSN_seq);
}
sctp_flight_size_increase(data_list[i]);
@@ -10288,7 +10290,7 @@ sctp_fill_in_rest:
space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
(cnt_of_skipped * sizeof(struct sctp_strseq)));
- cnt_of_space = M_TRAILINGSPACE(chk->data);
+ cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
ovh = SCTP_MIN_OVERHEAD;
@@ -10414,7 +10416,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
struct sctp_sack_chunk *sack;
struct sctp_nr_sack_chunk *nr_sack;
struct sctp_gap_ack_block *gap_descriptor;
- struct sack_track *selector;
+ const struct sack_track *selector;
int mergeable = 0;
int offset;
caddr_t limit;
@@ -10546,7 +10548,7 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
}
/* ok, lets go through and fill it in */
SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD);
- space = M_TRAILINGSPACE(a_chk->data);
+ space = (unsigned int)M_TRAILINGSPACE(a_chk->data);
if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) {
space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD);
}
@@ -10760,9 +10762,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
* queue.
*/
if (type == SCTP_SELECTIVE_ACK) {
- a_chk->send_size = sizeof(struct sctp_sack_chunk) +
+ a_chk->send_size = (uint16_t) (sizeof(struct sctp_sack_chunk) +
(num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
sack->sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -10772,9 +10774,9 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked
sack->ch.chunk_flags = flags;
sack->ch.chunk_length = htons(a_chk->send_size);
} else {
- a_chk->send_size = sizeof(struct sctp_nr_sack_chunk) +
+ a_chk->send_size = (uint16_t) (sizeof(struct sctp_nr_sack_chunk) +
(num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
- num_dups * sizeof(int32_t);
+ num_dups * sizeof(int32_t));
SCTP_BUF_LEN(a_chk->data) = a_chk->send_size;
nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd);
@@ -11082,10 +11084,10 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port));
udp->uh_dport = port;
udp->uh_sum = 0;
- udp->uh_ulen = htons(sizeof(struct udphdr) +
+ udp->uh_ulen = htons((uint16_t) (sizeof(struct udphdr) +
sizeof(struct sctphdr) +
sizeof(struct sctp_chunkhdr) +
- cause_len + padding_len);
+ cause_len + padding_len));
len += sizeof(struct udphdr);
shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr));
} else {
@@ -11108,7 +11110,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
} else {
ch->chunk_flags = SCTP_HAD_NO_TCB;
}
- ch->chunk_length = htons(sizeof(struct sctp_chunkhdr) + cause_len);
+ ch->chunk_length = htons((uint16_t) (sizeof(struct sctp_chunkhdr) + cause_len));
len += sizeof(struct sctp_chunkhdr);
len += cause_len + padding_len;
@@ -11157,7 +11159,7 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst,
#endif
#ifdef INET6
case AF_INET6:
- ip6->ip6_plen = len - sizeof(struct ip6_hdr);
+ ip6->ip6_plen = (uint16_t) (len - sizeof(struct ip6_hdr));
if (port) {
#if defined(SCTP_WITH_NO_CSUM)
SCTP_STAT_INCR(sctps_sendnocrc);
@@ -11484,7 +11486,7 @@ jump_out:
* Len is already adjusted to size minus overhead above take
* out the pkt_drop chunk itself from it.
*/
- chk->send_size = len - sizeof(struct sctp_pktdrop_chunk);
+ chk->send_size = (uint16_t) (len - sizeof(struct sctp_pktdrop_chunk));
len = chk->send_size;
} else {
/* no truncation needed */
@@ -11624,7 +11626,7 @@ sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk,
if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) {
number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET;
}
- len = (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
+ len = (uint16_t) (sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries));
req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST);
req_out->ph.param_length = htons(len);
req_out->request_seq = htonl(seq);
@@ -11681,7 +11683,7 @@ sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk,
/* get to new offset for the param. */
req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len);
/* now how long will this param be? */
- len = (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
+ len = (uint16_t) (sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries));
req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST);
req_in->ph.param_length = htons(len);
req_in->request_seq = htonl(seq);
@@ -12313,7 +12315,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
(void)SCTP_GETTIME_TIMEVAL(&sp->ts);
sp->stream = srcv->sinfo_stream;
- sp->length = min(uio->uio_resid, max_send_len);
+ sp->length = (uint32_t) min(uio->uio_resid, max_send_len);
if ((sp->length == (uint32_t) uio->uio_resid) &&
((user_marks_eor == 0) ||
(srcv->sinfo_flags & SCTP_EOF) ||
@@ -12472,7 +12474,7 @@ sctp_lower_sosend(struct socket *so,
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
}
- sndlen = uio->uio_resid;
+ sndlen = (unsigned int)uio->uio_resid;
} else {
top = SCTP_HEADER_TO_CHAIN(i_pak);
sndlen = SCTP_HEADER_LEN(i_pak);
@@ -12871,7 +12873,7 @@ sctp_lower_sosend(struct socket *so,
/* now move forward the data pointer */
ph = mtod(mm, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons(sizeof(struct sctp_paramhdr) + tot_out);
+ ph->param_length = htons((uint16_t) (sizeof(struct sctp_paramhdr) + tot_out));
ph++;
SCTP_BUF_LEN(mm) = tot_out + sizeof(struct sctp_paramhdr);
if (top == NULL) {
@@ -13291,7 +13293,7 @@ skip_preblock:
min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
- asoc, uio->uio_resid);
+ asoc, (size_t)uio->uio_resid);
}
be.error = 0;
stcb->block_entry = &be;
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 7e3218d..12aa145 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -5357,6 +5357,7 @@ void
sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t action)
{
struct sctp_laddr *laddr;
+ struct sctp_tcb *stcb;
int fnd, error = 0;
fnd = 0;
@@ -5402,6 +5403,9 @@ sctp_add_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa, uint32_t ac
default:
break;
}
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ sctp_add_local_addr_restricted(stcb, ifa);
+ }
}
return;
}
diff --git a/sys/netinet/sctp_ss_functions.c b/sys/netinet/sctp_ss_functions.c
index a2568ad..c4cbb05 100644
--- a/sys/netinet/sctp_ss_functions.c
+++ b/sys/netinet/sctp_ss_functions.c
@@ -822,7 +822,7 @@ default_again:
return (strq);
}
-struct sctp_ss_functions sctp_ss_functions[] = {
+const struct sctp_ss_functions sctp_ss_functions[] = {
/* SCTP_SS_DEFAULT */
{
.sctp_ss_init = sctp_ss_default_init,
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index dec02de..9fa37e7 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -662,7 +662,7 @@ start_again:
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t) chk->whoTo,
+ (uint32_t) (uintptr_t) chk->whoTo,
chk->rec.data.TSN_seq);
}
sctp_flight_size_decrease(chk);
@@ -790,7 +790,7 @@ start_again:
sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t) chk->whoTo,
+ (uint32_t) (uintptr_t) chk->whoTo,
chk->rec.data.TSN_seq);
}
sctp_flight_size_increase(chk);
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index d11bf20..a75f025 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -54,8 +54,8 @@ __FBSDID("$FreeBSD$");
-extern struct sctp_cc_functions sctp_cc_functions[];
-extern struct sctp_ss_functions sctp_ss_functions[];
+extern const struct sctp_cc_functions sctp_cc_functions[];
+extern const struct sctp_ss_functions sctp_ss_functions[];
void
sctp_init(void)
@@ -132,7 +132,7 @@ sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
chk->whoTo->flight_size,
chk->book_size,
- (uintptr_t) chk->whoTo,
+ (uint32_t) (uintptr_t) chk->whoTo,
chk->rec.data.TSN_seq);
}
/* Clear any time so NO RTT is being done */
@@ -1413,7 +1413,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
int creat_lock_on = 0;
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
- int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
+ unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
uint32_t vrf_id;
int bad_addresses = 0;
sctp_assoc_t *a_id;
@@ -1449,10 +1449,10 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
error = EFAULT;
goto out_now;
}
- totaddrp = (int *)optval;
+ totaddrp = (unsigned int *)optval;
totaddr = *totaddrp;
sa = (struct sockaddr *)(totaddrp + 1);
- stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
+ stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (unsigned int)(optsize - sizeof(int)), &bad_addresses);
if ((stcb != NULL) || bad_addresses) {
/* Already have or am bring up an association */
SCTP_ASOC_CREATE_UNLOCK(inp);
@@ -1903,7 +1903,8 @@ flags_out:
case SCTP_GET_ASSOC_ID_LIST:
{
struct sctp_assoc_ids *ids;
- unsigned int at, limit;
+ uint32_t at;
+ size_t limit;
SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
SCTP_INP_RLOCK(inp);
@@ -1919,6 +1920,11 @@ flags_out:
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
if (at < limit) {
ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
+ if (at == 0) {
+ error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ break;
+ }
} else {
error = EINVAL;
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
@@ -5810,6 +5816,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
__func__);
continue;
}
+ if ((sctp_is_addr_restricted(stcb, laddr->ifa)) &&
+ (!sctp_is_addr_pending(stcb, laddr->ifa))) {
+ continue;
+ }
if (laddr->ifa == ifa) {
found = 1;
break;
@@ -5862,7 +5872,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
out_of_it:
SCTP_TCB_UNLOCK(stcb);
} else {
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 4115256..9434f06 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -58,8 +58,8 @@ __FBSDID("$FreeBSD$");
#define KTR_SCTP KTR_SUBSYS
#endif
-extern struct sctp_cc_functions sctp_cc_functions[];
-extern struct sctp_ss_functions sctp_ss_functions[];
+extern const struct sctp_cc_functions sctp_cc_functions[];
+extern const struct sctp_ss_functions sctp_ss_functions[];
void
sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
@@ -503,7 +503,7 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
}
void
-sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
+sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen)
{
struct sctp_cwnd_log sctp_clog;
@@ -513,7 +513,7 @@ sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen)
sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt;
sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue;
sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024);
- sctp_clog.x.blk.sndlen = sendlen;
+ sctp_clog.x.blk.sndlen = (uint32_t) sendlen;
SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
SCTP_LOG_EVENT_BLOCK,
from,
@@ -2679,7 +2679,8 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
- size_t notif_len, abort_len;
+ unsigned int notif_len;
+ uint16_t abort_len;
unsigned int i;
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
@@ -2691,7 +2692,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
return;
}
if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
- notif_len = sizeof(struct sctp_assoc_change);
+ notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
if (abort != NULL) {
abort_len = ntohs(abort->ch.chunk_length);
} else {
@@ -2705,7 +2706,7 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* Retry with smaller value. */
- notif_len = sizeof(struct sctp_assoc_change);
+ notif_len = (unsigned int)sizeof(struct sctp_assoc_change);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
goto set_error;
@@ -3570,7 +3571,8 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
struct mbuf *m_notify;
struct sctp_remote_error *sre;
struct sctp_queued_to_read *control;
- size_t notif_len, chunk_len;
+ unsigned int notif_len;
+ uint16_t chunk_len;
if ((stcb == NULL) ||
sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) {
@@ -3581,11 +3583,11 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
} else {
chunk_len = 0;
}
- notif_len = sizeof(struct sctp_remote_error) + chunk_len;
+ notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
/* Retry with smaller value. */
- notif_len = sizeof(struct sctp_remote_error);
+ notif_len = (unsigned int)sizeof(struct sctp_remote_error);
m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA);
if (m_notify == NULL) {
return;
@@ -4739,19 +4741,23 @@ sctp_generate_cause(uint16_t code, char *info)
{
struct mbuf *m;
struct sctp_gen_error_cause *cause;
- size_t info_len, len;
+ size_t info_len;
+ uint16_t len;
if ((code == 0) || (info == NULL)) {
return (NULL);
}
info_len = strlen(info);
- len = sizeof(struct sctp_paramhdr) + info_len;
+ if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) {
+ return (NULL);
+ }
+ len = (uint16_t) (sizeof(struct sctp_paramhdr) + info_len);
m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
if (m != NULL) {
SCTP_BUF_LEN(m) = len;
cause = mtod(m, struct sctp_gen_error_cause *);
cause->code = htons(code);
- cause->length = htons((uint16_t) len);
+ cause->length = htons(len);
memcpy(cause->info, info, info_len);
}
return (m);
@@ -4762,15 +4768,15 @@ sctp_generate_no_user_data_cause(uint32_t tsn)
{
struct mbuf *m;
struct sctp_error_no_user_data *no_user_data_cause;
- size_t len;
+ uint16_t len;
- len = sizeof(struct sctp_error_no_user_data);
+ len = (uint16_t) sizeof(struct sctp_error_no_user_data);
m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA);
if (m != NULL) {
SCTP_BUF_LEN(m) = len;
no_user_data_cause = mtod(m, struct sctp_error_no_user_data *);
no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA);
- no_user_data_cause->cause.length = htons((uint16_t) len);
+ no_user_data_cause->cause.length = htons(len);
no_user_data_cause->tsn = tsn; /* tsn is passed in as NBO */
}
return (m);
@@ -5295,7 +5301,7 @@ sctp_sorecvmsg(struct socket *so,
uint32_t rwnd_req = 0;
int hold_sblock = 0;
int hold_rlock = 0;
- int slen = 0;
+ ssize_t slen = 0;
uint32_t held_length = 0;
int sockbuf_lock = 0;
@@ -5340,11 +5346,11 @@ sctp_sorecvmsg(struct socket *so,
in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
sctp_misc_ints(SCTP_SORECV_ENTER,
- rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
+ rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t) uio->uio_resid);
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
sctp_misc_ints(SCTP_SORECV_ENTERPL,
- rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
+ rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t) uio->uio_resid);
}
error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
if (error) {
@@ -6219,13 +6225,13 @@ out:
if (stcb) {
sctp_misc_ints(SCTP_SORECV_DONE,
freed_so_far,
- ((uio) ? (slen - uio->uio_resid) : slen),
+ (uint32_t) ((uio) ? (slen - uio->uio_resid) : slen),
stcb->asoc.my_rwnd,
so->so_rcv.sb_cc);
} else {
sctp_misc_ints(SCTP_SORECV_DONE,
freed_so_far,
- ((uio) ? (slen - uio->uio_resid) : slen),
+ (uint32_t) ((uio) ? (slen - uio->uio_resid) : slen),
0,
so->so_rcv.sb_cc);
}
@@ -6452,30 +6458,30 @@ out_now:
struct sctp_tcb *
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- int *totaddr, int *num_v4, int *num_v6, int *error,
- int limit, int *bad_addr)
+ unsigned int *totaddr,
+ unsigned int *num_v4, unsigned int *num_v6, int *error,
+ unsigned int limit, int *bad_addr)
{
struct sockaddr *sa;
struct sctp_tcb *stcb = NULL;
- size_t incr, at, i;
+ unsigned int incr, at, i;
at = incr = 0;
sa = addr;
-
*error = *num_v6 = *num_v4 = 0;
/* account and validate addresses */
- for (i = 0; i < (size_t)*totaddr; i++) {
+ for (i = 0; i < *totaddr; i++) {
switch (sa->sa_family) {
#ifdef INET
case AF_INET:
- (*num_v4) += 1;
- incr = sizeof(struct sockaddr_in);
if (sa->sa_len != incr) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
*bad_addr = 1;
return (NULL);
}
+ (*num_v4) += 1;
+ incr = (unsigned int)sizeof(struct sockaddr_in);
break;
#endif
#ifdef INET6
@@ -6491,14 +6497,14 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
*bad_addr = 1;
return (NULL);
}
- (*num_v6) += 1;
- incr = sizeof(struct sockaddr_in6);
if (sa->sa_len != incr) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
*error = EINVAL;
*bad_addr = 1;
return (NULL);
}
+ (*num_v6) += 1;
+ incr = (unsigned int)sizeof(struct sockaddr_in6);
break;
}
#endif
@@ -6507,7 +6513,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
/* we are done */
break;
}
- if (i == (size_t)*totaddr) {
+ if (i == *totaddr) {
break;
}
SCTP_INP_INCR_REF(inp);
@@ -6518,7 +6524,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
} else {
SCTP_INP_DECR_REF(inp);
}
- if ((at + incr) > (size_t)limit) {
+ if ((at + incr) > limit) {
*totaddr = i;
break;
}
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index 354d40e..2d32792 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -220,7 +220,8 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
struct sctp_tcb *
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
- int *totaddr, int *num_v4, int *num_v6, int *error, int limit, int *bad_addr);
+ unsigned int *totaddr, unsigned int *num_v4, unsigned int *num_v6,
+ int *error, unsigned int limit, int *bad_addr);
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
@@ -376,7 +377,7 @@ void sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc
void sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from);
void sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *, int, int, uint8_t);
-void sctp_log_block(uint8_t, struct sctp_association *, int);
+void sctp_log_block(uint8_t, struct sctp_association *, size_t);
void sctp_log_rwnd(uint8_t, uint32_t, uint32_t, uint32_t);
void sctp_log_rwnd_set(uint8_t, uint32_t, uint32_t, uint32_t, uint32_t);
int sctp_fill_stat_log(void *, size_t *);
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 102430d..7134ce4 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -235,16 +235,39 @@ VNET_DEFINE(struct inpcbhead, tcb);
VNET_DEFINE(struct inpcbinfo, tcbinfo);
/*
- * TCP statistics are stored in an "array" of counter(9)s.
+ * TCP statistics are stored in an array of counter(9)s, which size matches
+ * size of struct tcpstat. TCP running connection count is a regular array.
*/
VNET_PCPUSTAT_DEFINE(struct tcpstat, tcpstat);
-VNET_PCPUSTAT_SYSINIT(tcpstat);
SYSCTL_VNET_PCPUSTAT(_net_inet_tcp, TCPCTL_STATS, stats, struct tcpstat,
tcpstat, "TCP statistics (struct tcpstat, netinet/tcp_var.h)");
+VNET_DEFINE(counter_u64_t, tcps_states[TCP_NSTATES]);
+SYSCTL_COUNTER_U64_ARRAY(_net_inet_tcp, TCPCTL_STATES, states, CTLFLAG_RD |
+ CTLFLAG_VNET, &VNET_NAME(tcps_states)[0], TCP_NSTATES,
+ "TCP connection counts by TCP state");
+
+static void
+tcp_vnet_init(const void *unused)
+{
+
+ COUNTER_ARRAY_ALLOC(VNET(tcps_states), TCP_NSTATES, M_WAITOK);
+ VNET_PCPUSTAT_ALLOC(tcpstat, M_WAITOK);
+}
+VNET_SYSINIT(tcp_vnet_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+ tcp_vnet_init, NULL);
#ifdef VIMAGE
-VNET_PCPUSTAT_SYSUNINIT(tcpstat);
+static void
+tcp_vnet_uninit(const void *unused)
+{
+
+ COUNTER_ARRAY_FREE(VNET(tcps_states), TCP_NSTATES);
+ VNET_PCPUSTAT_FREE(tcpstat);
+}
+VNET_SYSUNINIT(tcp_vnet_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+ tcp_vnet_uninit, NULL);
#endif /* VIMAGE */
+
/*
* Kernel module interface for updating tcpstat. The argument is an index
* into tcpstat treated as an array.
diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
index 7067abe..bd323bf 100644
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -67,6 +67,8 @@ static MALLOC_DEFINE(M_LRO, "LRO", "LRO control structures");
#define TCP_LRO_INVALID_CSUM 0x0000
#endif
+static void tcp_lro_rx_done(struct lro_ctrl *lc);
+
int
tcp_lro_init(struct lro_ctrl *lc)
{
@@ -91,8 +93,8 @@ tcp_lro_init_args(struct lro_ctrl *lc, struct ifnet *ifp,
lc->lro_ackcnt_lim = TCP_LRO_ACKCNT_MAX;
lc->lro_length_lim = TCP_LRO_LENGTH_MAX;
lc->ifp = ifp;
- SLIST_INIT(&lc->lro_free);
- SLIST_INIT(&lc->lro_active);
+ LIST_INIT(&lc->lro_free);
+ LIST_INIT(&lc->lro_active);
/* compute size to allocate */
size = (lro_mbufs * sizeof(struct mbuf *)) +
@@ -111,7 +113,7 @@ tcp_lro_init_args(struct lro_ctrl *lc, struct ifnet *ifp,
/* setup linked list */
for (i = 0; i != lro_entries; i++)
- SLIST_INSERT_HEAD(&lc->lro_free, le + i, next);
+ LIST_INSERT_HEAD(&lc->lro_free, le + i, next);
return (0);
}
@@ -123,11 +125,11 @@ tcp_lro_free(struct lro_ctrl *lc)
unsigned x;
/* reset LRO free list */
- SLIST_INIT(&lc->lro_free);
+ LIST_INIT(&lc->lro_free);
/* free active mbufs, if any */
- while ((le = SLIST_FIRST(&lc->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lc->lro_active, next);
+ while ((le = LIST_FIRST(&lc->lro_active)) != NULL) {
+ LIST_REMOVE(le, next);
m_freem(le->m_head);
}
@@ -226,20 +228,31 @@ tcp_lro_rx_csum_fixup(struct lro_entry *le, void *l3hdr, struct tcphdr *th,
}
#endif
+static void
+tcp_lro_rx_done(struct lro_ctrl *lc)
+{
+ struct lro_entry *le;
+
+ while ((le = LIST_FIRST(&lc->lro_active)) != NULL) {
+ LIST_REMOVE(le, next);
+ tcp_lro_flush(lc, le);
+ }
+}
+
void
tcp_lro_flush_inactive(struct lro_ctrl *lc, const struct timeval *timeout)
{
struct lro_entry *le, *le_tmp;
struct timeval tv;
- if (SLIST_EMPTY(&lc->lro_active))
+ if (LIST_EMPTY(&lc->lro_active))
return;
getmicrotime(&tv);
timevalsub(&tv, timeout);
- SLIST_FOREACH_SAFE(le, &lc->lro_active, next, le_tmp) {
+ LIST_FOREACH_SAFE(le, &lc->lro_active, next, le_tmp) {
if (timevalcmp(&tv, &le->mtime, >=)) {
- SLIST_REMOVE(&lc->lro_active, le, lro_entry, next);
+ LIST_REMOVE(le, next);
tcp_lro_flush(lc, le);
}
}
@@ -335,7 +348,7 @@ tcp_lro_flush(struct lro_ctrl *lc, struct lro_entry *le)
lc->lro_queued += le->append_cnt + 1;
lc->lro_flushed++;
bzero(le, sizeof(*le));
- SLIST_INSERT_HEAD(&lc->lro_free, le, next);
+ LIST_INSERT_HEAD(&lc->lro_free, le, next);
}
static int
@@ -362,13 +375,12 @@ done:
void
tcp_lro_flush_all(struct lro_ctrl *lc)
{
- struct lro_entry *le;
uint32_t hashtype;
uint32_t flowid;
unsigned x;
/* check if no mbufs to flush */
- if (__predict_false(lc->lro_mbuf_count == 0))
+ if (lc->lro_mbuf_count == 0)
goto done;
/* sort all mbufs according to stream */
@@ -390,10 +402,7 @@ tcp_lro_flush_all(struct lro_ctrl *lc)
hashtype = M_HASHTYPE_GET(mb);
/* flush active streams */
- while ((le = SLIST_FIRST(&lc->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lc->lro_active, next);
- tcp_lro_flush(lc, le);
- }
+ tcp_lro_rx_done(lc);
}
#ifdef TCP_LRO_RESET_SEQUENCE
/* reset sequence number */
@@ -409,10 +418,8 @@ tcp_lro_flush_all(struct lro_ctrl *lc)
}
done:
/* flush active streams */
- while ((le = SLIST_FIRST(&lc->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lc->lro_active, next);
- tcp_lro_flush(lc, le);
- }
+ tcp_lro_rx_done(lc);
+
lc->lro_mbuf_count = 0;
}
@@ -586,7 +593,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
seq = ntohl(th->th_seq);
/* Try to find a matching previous segment. */
- SLIST_FOREACH(le, &lc->lro_active, next) {
+ LIST_FOREACH(le, &lc->lro_active, next) {
if (le->eh_type != eh_type)
continue;
if (le->source_port != th->th_sport ||
@@ -613,7 +620,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
/* Flush now if appending will result in overflow. */
if (le->p_len > (lc->lro_length_lim - tcp_data_len)) {
- SLIST_REMOVE(&lc->lro_active, le, lro_entry, next);
+ LIST_REMOVE(le, next);
tcp_lro_flush(lc, le);
break;
}
@@ -622,7 +629,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
if (__predict_false(seq != le->next_seq ||
(tcp_data_len == 0 && le->ack_seq == th->th_ack))) {
/* Out of order packet or duplicate ACK. */
- SLIST_REMOVE(&lc->lro_active, le, lro_entry, next);
+ LIST_REMOVE(le, next);
tcp_lro_flush(lc, le);
return (TCP_LRO_CANNOT);
}
@@ -655,8 +662,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
* be further delayed.
*/
if (le->append_cnt >= lc->lro_ackcnt_lim) {
- SLIST_REMOVE(&lc->lro_active, le, lro_entry,
- next);
+ LIST_REMOVE(le, next);
tcp_lro_flush(lc, le);
}
return (0);
@@ -680,7 +686,7 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
* overflow, pro-actively flush now.
*/
if (le->p_len > (lc->lro_length_lim - lc->ifp->if_mtu)) {
- SLIST_REMOVE(&lc->lro_active, le, lro_entry, next);
+ LIST_REMOVE(le, next);
tcp_lro_flush(lc, le);
} else
getmicrotime(&le->mtime);
@@ -689,13 +695,13 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
}
/* Try to find an empty slot. */
- if (SLIST_EMPTY(&lc->lro_free))
- return (TCP_LRO_CANNOT);
+ if (LIST_EMPTY(&lc->lro_free))
+ return (TCP_LRO_NO_ENTRIES);
/* Start a new segment chain. */
- le = SLIST_FIRST(&lc->lro_free);
- SLIST_REMOVE_HEAD(&lc->lro_free, next);
- SLIST_INSERT_HEAD(&lc->lro_active, le, next);
+ le = LIST_FIRST(&lc->lro_free);
+ LIST_REMOVE(le, next);
+ LIST_INSERT_HEAD(&lc->lro_active, le, next);
getmicrotime(&le->mtime);
/* Start filling in details. */
diff --git a/sys/netinet/tcp_lro.h b/sys/netinet/tcp_lro.h
index 3fc627c..b81a950 100644
--- a/sys/netinet/tcp_lro.h
+++ b/sys/netinet/tcp_lro.h
@@ -41,9 +41,8 @@
#define TCP_LRO_SEQUENCE(mb) \
(mb)->m_pkthdr.PH_loc.thirtytwo[0]
-struct lro_entry
-{
- SLIST_ENTRY(lro_entry) next;
+struct lro_entry {
+ LIST_ENTRY(lro_entry) next;
struct mbuf *m_head;
struct mbuf *m_tail;
union {
@@ -72,7 +71,7 @@ struct lro_entry
uint16_t timestamp; /* flag, not a TCP hdr field. */
struct timeval mtime;
};
-SLIST_HEAD(lro_head, lro_entry);
+LIST_HEAD(lro_head, lro_entry);
#define le_ip4 leip.ip4
#define le_ip6 leip.ip6
@@ -110,6 +109,7 @@ void tcp_lro_flush_all(struct lro_ctrl *);
int tcp_lro_rx(struct lro_ctrl *, struct mbuf *, uint32_t);
void tcp_lro_queue_mbuf(struct lro_ctrl *, struct mbuf *);
+#define TCP_LRO_NO_ENTRIES -2
#define TCP_LRO_CANNOT -1
#define TCP_LRO_NOT_SUPPORTED 1
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 96a8700..2043fc9 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -1379,9 +1379,6 @@ send:
#endif
#ifdef INET
{
- struct route ro;
-
- bzero(&ro, sizeof(ro));
ip->ip_len = htons(m->m_pkthdr.len);
#ifdef INET6
if (tp->t_inpcb->inp_vflag & INP_IPV6PROTO)
@@ -1412,13 +1409,12 @@ send:
tcp_pcap_add(th, m, &(tp->t_outpkts));
#endif
- error = ip_output(m, tp->t_inpcb->inp_options, &ro,
+ error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0,
tp->t_inpcb);
- if (error == EMSGSIZE && ro.ro_rt != NULL)
- mtu = ro.ro_rt->rt_mtu;
- RO_RTFREE(&ro);
+ if (error == EMSGSIZE && tp->t_inpcb->inp_route.ro_rt != NULL)
+ mtu = tp->t_inpcb->inp_route.ro_rt->rt_mtu;
}
#endif /* INET */
@@ -1652,7 +1648,7 @@ tcp_setpersist(struct tcpcb *tp)
int
tcp_addoptions(struct tcpopt *to, u_char *optp)
{
- u_int mask, optlen = 0;
+ u_int32_t mask, optlen = 0;
for (mask = 1; mask < TOF_MAXOPT; mask <<= 1) {
if ((to->to_flags & mask) != mask)
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index ff218dd..33b16ad 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1542,7 +1542,7 @@ tcp_close(struct tcpcb *tp)
#endif
in_pcbdrop(inp);
TCPSTAT_INC(tcps_closed);
- TCPSTAT_DEC(tcps_states[tp->t_state]);
+ TCPSTATES_DEC(tp->t_state);
KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
so = inp->inp_socket;
soisdisconnected(so);
@@ -1632,6 +1632,10 @@ tcp_notify(struct inpcb *inp, int error)
if (tp->t_state == TCPS_ESTABLISHED &&
(error == EHOSTUNREACH || error == ENETUNREACH ||
error == EHOSTDOWN)) {
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
return (inp);
} else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
tp->t_softerror) {
@@ -1665,7 +1669,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
*/
if (req->oldptr == NULL) {
n = V_tcbinfo.ipi_count +
- TCPSTAT_FETCH(tcps_states[TCPS_SYN_RECEIVED]);
+ counter_u64_fetch(VNET(tcps_states)[TCPS_SYN_RECEIVED]);
n += imax(n / 8, 10);
req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xtcpcb);
return (0);
@@ -1682,7 +1686,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
n = V_tcbinfo.ipi_count;
INP_LIST_RUNLOCK(&V_tcbinfo);
- m = TCPSTAT_FETCH(tcps_states[TCPS_SYN_RECEIVED]);
+ m = counter_u64_fetch(VNET(tcps_states)[TCPS_SYN_RECEIVED]);
error = sysctl_wire_old_buffer(req, 2 * (sizeof xig)
+ (n + m) * sizeof(struct xtcpcb));
@@ -1702,8 +1706,6 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
return (error);
inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
- if (inp_list == NULL)
- return (ENOMEM);
INP_INFO_WLOCK(&V_tcbinfo);
for (inp = LIST_FIRST(V_tcbinfo.ipi_listhead), i = 0;
@@ -1926,11 +1928,11 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip)
notify = tcp_drop_syn_sent;
- /*
- * Redirects don't need to be handled up here.
- */
- else if (PRC_IS_REDIRECT(cmd))
+ else if (PRC_IS_REDIRECT(cmd)) {
+ /* signal EHOSTDOWN, as it flushes the cached route */
+ in_pcbnotifyall(&V_tcbinfo, faddr, EHOSTDOWN, notify);
return;
+ }
/*
* Hostdead is ugly because it goes linearly through all PCBs.
* XXX: We never get this from ICMP, otherwise it makes an
@@ -2986,8 +2988,8 @@ tcp_state_change(struct tcpcb *tp, int newstate)
int pstate = tp->t_state;
#endif
- TCPSTAT_DEC(tcps_states[tp->t_state]);
- TCPSTAT_INC(tcps_states[newstate]);
+ TCPSTATES_DEC(tp->t_state);
+ TCPSTATES_INC(newstate);
tp->t_state = newstate;
TCP_PROBE6(state__change, NULL, tp, NULL, tp, NULL, pstate);
}
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 0ff7318..b898c49 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -351,7 +351,7 @@ syncache_insert(struct syncache *sc, struct syncache_head *sch)
SCH_UNLOCK(sch);
- TCPSTAT_INC(tcps_states[TCPS_SYN_RECEIVED]);
+ TCPSTATES_INC(TCPS_SYN_RECEIVED);
TCPSTAT_INC(tcps_sc_added);
}
@@ -365,7 +365,7 @@ syncache_drop(struct syncache *sc, struct syncache_head *sch)
SCH_LOCK_ASSERT(sch);
- TCPSTAT_DEC(tcps_states[TCPS_SYN_RECEIVED]);
+ TCPSTATES_DEC(TCPS_SYN_RECEIVED);
TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
sch->sch_length--;
@@ -1003,7 +1003,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
* sonewconn->tcp_usr_attach in TCPS_CLOSED state, then
* syncache_socket() will change it to TCPS_SYN_RECEIVED.
*/
- TCPSTAT_DEC(tcps_states[TCPS_SYN_RECEIVED]);
+ TCPSTATES_DEC(TCPS_SYN_RECEIVED);
TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
sch->sch_length--;
#ifdef TCP_OFFLOAD
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 046feba..172c394 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -786,7 +786,9 @@ tcp_timer_rexmt(void * xtp)
#ifdef INET6
if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0)
in6_losing(tp->t_inpcb);
+ else
#endif
+ in_losing(tp->t_inpcb);
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
}
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index c98de24..ff36ce7 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -660,7 +660,7 @@ tcp_tw_2msl_stop(struct tcptw *tw, int reuse)
if (!reuse)
uma_zfree(V_tcptw_zone, tw);
- TCPSTAT_DEC(tcps_states[TCPS_TIME_WAIT]);
+ TCPSTATES_DEC(TCPS_TIME_WAIT);
}
struct tcptw *
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 09493f0..6a3cde6 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1883,7 +1883,7 @@ tcp_attach(struct socket *so)
tp->t_state = TCPS_CLOSED;
INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
- TCPSTAT_INC(tcps_states[TCPS_CLOSED]);
+ TCPSTATES_INC(TCPS_CLOSED);
return (0);
}
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 2f23881..d60ad9f 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -364,7 +364,7 @@ struct tcpcb {
* options in tcp_addoptions.
*/
struct tcpopt {
- u_int64_t to_flags; /* which options are present */
+ u_int32_t to_flags; /* which options are present */
#define TOF_MSS 0x0001 /* maximum segment size */
#define TOF_SCALE 0x0002 /* window scaling */
#define TOF_SACKPERM 0x0004 /* SACK permitted */
@@ -588,9 +588,6 @@ struct tcpstat {
uint64_t tcps_sig_err_sigopt; /* No signature expected by socket */
uint64_t tcps_sig_err_nosigopt; /* No signature provided by segment */
- /* Running connection count. */
- uint64_t tcps_states[TCP_NSTATES];
-
uint64_t _pad[12]; /* 6 UTO, 6 TBD */
};
@@ -609,9 +606,6 @@ VNET_PCPUSTAT_DECLARE(struct tcpstat, tcpstat); /* tcp statistics */
#define TCPSTAT_ADD(name, val) \
VNET_PCPUSTAT_ADD(struct tcpstat, tcpstat, name, (val))
#define TCPSTAT_INC(name) TCPSTAT_ADD(name, 1)
-#define TCPSTAT_DEC(name) TCPSTAT_ADD(name, -1)
-#define TCPSTAT_FETCH(name) VNET_PCPUSTAT_FETCH(struct tcpstat, tcpstat, \
- name)
/*
* Kernel module consumers must use this accessor macro.
@@ -621,6 +615,13 @@ void kmod_tcpstat_inc(int statnum);
kmod_tcpstat_inc(offsetof(struct tcpstat, name) / sizeof(uint64_t))
/*
+ * Running TCP connection count by state.
+ */
+VNET_DECLARE(counter_u64_t, tcps_states[TCP_NSTATES]);
+#define TCPSTATES_INC(state) counter_u64_add(VNET(tcps_states)[state], 1)
+#define TCPSTATES_DEC(state) counter_u64_add(VNET(tcps_states)[state], -1)
+
+/*
* TCP specific helper hook point identifiers.
*/
#define HHOOK_TCP_EST_IN 0
@@ -678,6 +679,7 @@ struct xtcpcb {
#define TCPCTL_V6MSSDFLT 13 /* MSS default for IPv6 */
#define TCPCTL_SACK 14 /* Selective Acknowledgement,rfc 2018 */
#define TCPCTL_DROP 15 /* drop tcp connection */
+#define TCPCTL_STATES 16 /* connection counts by TCP state */
#ifdef _KERNEL
#ifdef SYSCTL_DECL
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index f474a54..56aa56f 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -740,6 +740,11 @@ udp_notify(struct inpcb *inp, int errno)
* or a write lock, but a read lock is sufficient.
*/
INP_LOCK_ASSERT(inp);
+ if ((errno == EHOSTUNREACH || errno == ENETUNREACH ||
+ errno == EHOSTDOWN) && inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
inp->inp_socket->so_error = errno;
sorwakeup(inp->inp_socket);
@@ -761,11 +766,11 @@ udp_common_ctlinput(int cmd, struct sockaddr *sa, void *vip,
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
- /*
- * Redirects don't need to be handled up here.
- */
- if (PRC_IS_REDIRECT(cmd))
+ if (PRC_IS_REDIRECT(cmd)) {
+ /* signal EHOSTDOWN, as it flushes the cached route */
+ in_pcbnotifyall(&V_udbinfo, faddr, EHOSTDOWN, udp_notify);
return;
+ }
/*
* Hostdead is ugly because it goes linearly through all PCBs.
@@ -1116,7 +1121,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
int error = 0;
int ipflags;
u_short fport, lport;
- int unlock_udbinfo;
+ int unlock_udbinfo, unlock_inp;
u_char tos;
uint8_t pr;
uint16_t cscov = 0;
@@ -1137,7 +1142,15 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
}
src.sin_family = 0;
- INP_RLOCK(inp);
+ sin = (struct sockaddr_in *)addr;
+ if (sin == NULL ||
+ (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) {
+ INP_WLOCK(inp);
+ unlock_inp = UH_WLOCKED;
+ } else {
+ INP_RLOCK(inp);
+ unlock_inp = UH_RLOCKED;
+ }
tos = inp->inp_ip_tos;
if (control != NULL) {
/*
@@ -1145,7 +1158,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
* stored in a single mbuf.
*/
if (control->m_next) {
- INP_RUNLOCK(inp);
+ if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
+ INP_RUNLOCK(inp);
m_freem(control);
m_freem(m);
return (EINVAL);
@@ -1220,7 +1236,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
m_freem(control);
}
if (error) {
- INP_RUNLOCK(inp);
+ if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
+ INP_RUNLOCK(inp);
m_freem(m);
return (error);
}
@@ -1246,8 +1265,6 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
sin = (struct sockaddr_in *)addr;
if (sin != NULL &&
(inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0)) {
- INP_RUNLOCK(inp);
- INP_WLOCK(inp);
INP_HASH_WLOCK(pcbinfo);
unlock_udbinfo = UH_WLOCKED;
} else if ((sin != NULL && (
@@ -1514,9 +1531,10 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
else if (unlock_udbinfo == UH_RLOCKED)
INP_HASH_RUNLOCK(pcbinfo);
UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
- error = ip_output(m, inp->inp_options, NULL, ipflags,
+ error = ip_output(m, inp->inp_options,
+ (unlock_inp == UH_WLOCKED ? &inp->inp_route : NULL), ipflags,
inp->inp_moptions, inp);
- if (unlock_udbinfo == UH_WLOCKED)
+ if (unlock_inp == UH_WLOCKED)
INP_WUNLOCK(inp);
else
INP_RUNLOCK(inp);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 393bb7e..797093a 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -2367,7 +2367,7 @@ in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
sdl->sdl_alen = ifp->if_addrlen;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = ifp->if_type;
- bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
if (lle->la_expire != 0)
ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire +
lle->lle_remtime / hz +
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 64981b3..471dd82 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -890,3 +890,29 @@ in6_purgemaddrs(struct ifnet *ifp)
IN6_MULTI_UNLOCK();
}
+
+void
+in6_ifattach_destroy(void)
+{
+
+ callout_drain(&V_in6_tmpaddrtimer_ch);
+}
+
+static void
+in6_ifattach_init(void *dummy)
+{
+
+ /* Timer for regeneranation of temporary addresses randomize ID. */
+ callout_init(&V_in6_tmpaddrtimer_ch, 0);
+ callout_reset(&V_in6_tmpaddrtimer_ch,
+ (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
+ V_ip6_temp_regen_advance) * hz,
+ in6_tmpaddrtimer, curvnet);
+}
+
+/*
+ * Cheat.
+ * This must be after route_init(), which is now SI_ORDER_THIRD.
+ */
+SYSINIT(in6_ifattach_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE,
+ in6_ifattach_init, NULL);
diff --git a/sys/netinet6/in6_ifattach.h b/sys/netinet6/in6_ifattach.h
index af62731..a5a82c0 100644
--- a/sys/netinet6/in6_ifattach.h
+++ b/sys/netinet6/in6_ifattach.h
@@ -35,6 +35,7 @@
#ifdef _KERNEL
void in6_ifattach(struct ifnet *, struct ifnet *);
+void in6_ifattach_destroy(void);
void in6_ifdetach(struct ifnet *);
int in6_get_tmpifid(struct ifnet *, u_int8_t *, const u_int8_t *, int);
void in6_tmpaddrtimer(void *);
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index a779b8d..98f4cd3 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -827,9 +827,10 @@ void
in6_losing(struct inpcb *in6p)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+ if (in6p->inp_route6.ro_rt) {
+ RTFREE(in6p->inp_route6.ro_rt);
+ in6p->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
return;
}
@@ -840,9 +841,11 @@ in6_losing(struct inpcb *in6p)
struct inpcb *
in6_rtchange(struct inpcb *inp, int errno)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+
+ if (inp->inp_route6.ro_rt) {
+ RTFREE(inp->inp_route6.ro_rt);
+ inp->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
return inp;
}
diff --git a/sys/netinet6/in6_pcbgroup.c b/sys/netinet6/in6_pcbgroup.c
index 694de99..4a68432 100644
--- a/sys/netinet6/in6_pcbgroup.c
+++ b/sys/netinet6/in6_pcbgroup.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mbuf.h>
+#include <sys/socket.h>
#include <net/rss_config.h>
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 4029402..40b4723 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -226,9 +226,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
*/
if (opts && (pi = opts->ip6po_pktinfo) &&
!IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
- struct sockaddr_in6 srcsock;
- struct in6_ifaddr *ia6;
-
/* get the outgoing interface */
if ((error = in6_selectif(dstsock, opts, mopts, &ifp, oifp,
fibnum))
@@ -242,33 +239,36 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
* the interface must be specified; otherwise, ifa_ifwithaddr()
* will fail matching the address.
*/
- bzero(&srcsock, sizeof(srcsock));
- srcsock.sin6_family = AF_INET6;
- srcsock.sin6_len = sizeof(srcsock);
- srcsock.sin6_addr = pi->ipi6_addr;
+ tmp = pi->ipi6_addr;
if (ifp) {
- error = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
+ error = in6_setscope(&tmp, ifp, &odstzone);
if (error)
return (error);
}
if (cred != NULL && (error = prison_local_ip6(cred,
- &srcsock.sin6_addr, (inp != NULL &&
- (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
+ &tmp, (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0)
return (error);
- ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(
- (struct sockaddr *)&srcsock);
- if (ia6 == NULL ||
- (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
- if (ia6 != NULL)
- ifa_free(&ia6->ia_ifa);
- return (EADDRNOTAVAIL);
- }
- pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
+ /*
+ * If IPV6_BINDANY socket option is set, we allow to specify
+ * non local addresses as source address in IPV6_PKTINFO
+ * ancillary data.
+ */
+ if ((inp->inp_flags & INP_BINDANY) == 0) {
+ ia = in6ifa_ifwithaddr(&tmp, odstzone);
+ if (ia == NULL || (ia->ia6_flags & (IN6_IFF_ANYCAST |
+ IN6_IFF_NOTREADY))) {
+ if (ia != NULL)
+ ifa_free(&ia->ia_ifa);
+ return (EADDRNOTAVAIL);
+ }
+ bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp));
+ ifa_free(&ia->ia_ifa);
+ } else
+ bcopy(&tmp, srcp, sizeof(*srcp));
+ pi->ipi6_addr = tmp; /* XXX: this overrides pi */
if (ifpp)
*ifpp = ifp;
- bcopy(&ia6->ia_addr.sin6_addr, srcp, sizeof(*srcp));
- ifa_free(&ia6->ia_ifa);
return (0);
}
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index e6c16a9..6b49b26 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -156,9 +156,6 @@ static struct netisr_handler ip6_direct_nh = {
};
#endif
-VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch);
-#define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch)
-
VNET_DEFINE(struct pfil_head, inet6_pfil_hook);
VNET_PCPUSTAT_DEFINE(struct ip6stat, ip6stat);
@@ -170,7 +167,6 @@ VNET_PCPUSTAT_SYSUNINIT(ip6stat);
struct rmlock in6_ifaddr_lock;
RM_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
-static void ip6_init2(void *);
static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
#ifdef PULLDOWN_TEST
static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
@@ -331,40 +327,11 @@ ip6_destroy()
}
hashdestroy(V_in6_ifaddrhashtbl, M_IFADDR, V_in6_ifaddrhmask);
nd6_destroy();
- callout_drain(&V_in6_tmpaddrtimer_ch);
+ in6_ifattach_destroy();
}
#endif
static int
-ip6_init2_vnet(const void *unused __unused)
-{
-
- /* nd6_timer_init */
- callout_init(&V_nd6_timer_ch, 0);
- callout_reset(&V_nd6_timer_ch, hz, nd6_timer, curvnet);
-
- /* timer for regeneranation of temporary addresses randomize ID */
- callout_init(&V_in6_tmpaddrtimer_ch, 0);
- callout_reset(&V_in6_tmpaddrtimer_ch,
- (V_ip6_temp_preferred_lifetime - V_ip6_desync_factor -
- V_ip6_temp_regen_advance) * hz,
- in6_tmpaddrtimer, curvnet);
-
- return (0);
-}
-
-static void
-ip6_init2(void *dummy)
-{
-
- ip6_init2_vnet(NULL);
-}
-
-/* cheat */
-/* This must be after route_init(), which is now SI_ORDER_THIRD */
-SYSINIT(netinet6init2, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ip6_init2, NULL);
-
-static int
ip6_input_hbh(struct mbuf *m, uint32_t *plen, uint32_t *rtalert, int *off,
int *nxt, int *ours)
{
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 3a47285..7895139 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -546,7 +546,18 @@ again:
/* adjust pointer */
ip6 = mtod(m, struct ip6_hdr *);
- if (ro->ro_rt && fwd_tag == NULL) {
+ /*
+ * Validate route against routing table additions;
+ * a better/more specific route might have been added.
+ * Make sure address family is set in route.
+ */
+ if (inp) {
+ ro->ro_dst.sin6_family = AF_INET6;
+ RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum);
+ }
+ if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) &&
+ ro->ro_dst.sin6_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) {
rt = ro->ro_rt;
ifp = ro->ro_rt->rt_ifp;
} else {
@@ -939,7 +950,8 @@ passout:
m->m_pkthdr.len);
ifa_free(&ia6->ia_ifa);
}
- error = nd6_output_ifp(ifp, origifp, m, dst, NULL);
+ error = nd6_output_ifp(ifp, origifp, m, dst,
+ (struct route *)ro);
goto done;
}
@@ -1038,7 +1050,8 @@ sendorfree:
counter_u64_add(ia->ia_ifa.ifa_obytes,
m->m_pkthdr.len);
}
- error = nd6_output_ifp(ifp, origifp, m, dst, NULL);
+ error = nd6_output_ifp(ifp, origifp, m, dst,
+ (struct route *)ro);
} else
m_freem(m);
}
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 60693e1..8b1da24 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -127,7 +127,7 @@ static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *,
static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *);
static void nd6_slowtimo(void *);
static int regen_tmpaddr(struct in6_ifaddr *);
-static void nd6_free(struct llentry *, int);
+static void nd6_free(struct llentry **, int);
static void nd6_free_redirect(const struct llentry *);
static void nd6_llinfo_timer(void *);
static void nd6_llinfo_settimer_locked(struct llentry *, long);
@@ -142,6 +142,7 @@ static VNET_DEFINE(struct callout, nd6_slowtimo_ch);
#define V_nd6_slowtimo_ch VNET(nd6_slowtimo_ch)
VNET_DEFINE(struct callout, nd6_timer_ch);
+#define V_nd6_timer_ch VNET(nd6_timer_ch)
static void
nd6_lle_event(void *arg __unused, struct llentry *lle, int evt)
@@ -213,11 +214,14 @@ nd6_init(void)
/* initialization of the default router list */
TAILQ_INIT(&V_nd_defrouter);
- /* start timer */
+ /* Start timers. */
callout_init(&V_nd6_slowtimo_ch, 0);
callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
nd6_slowtimo, curvnet);
+ callout_init(&V_nd6_timer_ch, 0);
+ callout_reset(&V_nd6_timer_ch, hz, nd6_timer, curvnet);
+
nd6_dad_init();
if (IS_DEFAULT_VNET(curvnet)) {
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, nd6_lle_event,
@@ -723,12 +727,16 @@ nd6_llinfo_timer(void *arg)
struct llentry *ln;
struct in6_addr *dst, *pdst, *psrc, src;
struct ifnet *ifp;
- struct nd_ifinfo *ndi = NULL;
+ struct nd_ifinfo *ndi;
int do_switch, send_ns;
long delay;
KASSERT(arg != NULL, ("%s: arg NULL", __func__));
ln = (struct llentry *)arg;
+ ifp = lltable_get_ifp(ln->lle_tbl);
+ CURVNET_SET(ifp->if_vnet);
+
+ ND6_RLOCK();
LLE_WLOCK(ln);
if (callout_pending(&ln->lle_timer)) {
/*
@@ -748,10 +756,10 @@ nd6_llinfo_timer(void *arg)
* would have been 1.
*/
LLE_WUNLOCK(ln);
+ ND6_RUNLOCK();
+ CURVNET_RESTORE();
return;
}
- ifp = ln->lle_tbl->llt_ifp;
- CURVNET_SET(ifp->if_vnet);
ndi = ND_IFINFO(ifp);
send_ns = 0;
dst = &ln->r_l3addr.addr6;
@@ -773,8 +781,7 @@ nd6_llinfo_timer(void *arg)
}
if (ln->la_flags & LLE_DELETED) {
- nd6_free(ln, 0);
- ln = NULL;
+ nd6_free(&ln, 0);
goto done;
}
@@ -799,9 +806,7 @@ nd6_llinfo_timer(void *arg)
ln->la_hold = m0;
clear_llinfo_pqueue(ln);
}
- EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_TIMEDOUT);
- nd6_free(ln, 0);
- ln = NULL;
+ nd6_free(&ln, 0);
if (m != NULL)
icmp6_error2(m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0, ifp);
@@ -830,12 +835,8 @@ nd6_llinfo_timer(void *arg)
* GC timer has ended and entry hasn't been used.
* Run Garbage collector (RFC 4861, 5.3)
*/
- if (!ND6_LLINFO_PERMANENT(ln)) {
- EVENTHANDLER_INVOKE(lle_event, ln,
- LLENTRY_EXPIRED);
- nd6_free(ln, 1);
- ln = NULL;
- }
+ if (!ND6_LLINFO_PERMANENT(ln))
+ nd6_free(&ln, 1);
break;
}
@@ -857,9 +858,7 @@ nd6_llinfo_timer(void *arg)
ln->la_asked++;
send_ns = 1;
} else {
- EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
- nd6_free(ln, 0);
- ln = NULL;
+ nd6_free(&ln, 0);
}
break;
default:
@@ -867,6 +866,8 @@ nd6_llinfo_timer(void *arg)
__func__, ln->ln_state);
}
done:
+ if (ln != NULL)
+ ND6_RUNLOCK();
if (send_ns != 0) {
nd6_llinfo_settimer_locked(ln, (long)ndi->retrans * hz / 1000);
psrc = nd6_llinfo_get_holdsrc(ln, &src);
@@ -1363,12 +1364,27 @@ nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
* Set noinline to be dtrace-friendly
*/
static __noinline void
-nd6_free(struct llentry *ln, int gc)
+nd6_free(struct llentry **lnp, int gc)
{
- struct nd_defrouter *dr;
struct ifnet *ifp;
+ struct llentry *ln;
+ struct nd_defrouter *dr;
+
+ ln = *lnp;
+ *lnp = NULL;
LLE_WLOCK_ASSERT(ln);
+ ND6_RLOCK_ASSERT();
+
+ ifp = lltable_get_ifp(ln->lle_tbl);
+ if ((ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) != 0)
+ dr = defrouter_lookup_locked(&ln->r_l3addr.addr6, ifp);
+ else
+ dr = NULL;
+ ND6_RUNLOCK();
+
+ if ((ln->la_flags & LLE_DELETED) == 0)
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_EXPIRED);
/*
* we used to have pfctlinput(PRC_HOSTDEAD) here.
@@ -1378,11 +1394,7 @@ nd6_free(struct llentry *ln, int gc)
/* cancel timer */
nd6_llinfo_settimer_locked(ln, -1);
- dr = NULL;
- ifp = ln->lle_tbl->llt_ifp;
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
- dr = defrouter_lookup(&ln->r_l3addr.addr6, ifp);
-
if (dr != NULL && dr->expire &&
ln->ln_state == ND6_LLINFO_STALE && gc) {
/*
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 4c83467..3b1aa96 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -355,9 +355,6 @@ VNET_DECLARE(struct rwlock, nd6_lock);
#define nd6log(x) do { if (V_nd6_debug) log x; } while (/*CONSTCOND*/ 0)
-VNET_DECLARE(struct callout, nd6_timer_ch);
-#define V_nd6_timer_ch VNET(nd6_timer_ch)
-
/* nd6_rtr.c */
VNET_DECLARE(int, nd6_defifindex);
VNET_DECLARE(int, ip6_desync_factor); /* seconds */
@@ -459,7 +456,7 @@ void defrouter_reset(void);
void defrouter_select(void);
void defrouter_ref(struct nd_defrouter *);
void defrouter_rele(struct nd_defrouter *);
-void defrouter_remove(struct nd_defrouter *);
+bool defrouter_remove(struct in6_addr *, struct ifnet *);
void defrouter_unlink(struct nd_defrouter *, struct nd_drhead *);
void defrouter_del(struct nd_defrouter *);
void prelist_remove(struct nd_prefix *);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index d528575..d621b52 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -857,30 +857,19 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
* Remove the sender from the Default Router List and
* update the Destination Cache entries.
*/
- struct nd_defrouter *dr;
struct ifnet *nd6_ifp;
nd6_ifp = lltable_get_ifp(ln->lle_tbl);
- ND6_WLOCK();
- dr = defrouter_lookup_locked(&ln->r_l3addr.addr6,
- nd6_ifp);
- if (dr != NULL) {
- /* releases the ND lock */
- defrouter_remove(dr);
- dr = NULL;
- } else {
- ND6_WUNLOCK();
- if ((ND_IFINFO(nd6_ifp)->flags & ND6_IFF_ACCEPT_RTADV) != 0) {
- /*
- * Even if the neighbor is not in the default
- * router list, the neighbor may be used
- * as a next hop for some destinations
- * (e.g. redirect case). So we must
- * call rt6_flush explicitly.
- */
- rt6_flush(&ip6->ip6_src, ifp);
- }
- }
+ if (!defrouter_remove(&ln->r_l3addr.addr6, nd6_ifp) &&
+ (ND_IFINFO(nd6_ifp)->flags &
+ ND6_IFF_ACCEPT_RTADV) != 0)
+ /*
+ * Even if the neighbor is not in the default
+ * router list, the neighbor may be used as a
+ * next hop for some destinations (e.g. redirect
+ * case). So we must call rt6_flush explicitly.
+ */
+ rt6_flush(&ip6->ip6_src, ifp);
}
ln->ln_router = is_router;
}
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index 294c90a..6fee830 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -627,22 +627,26 @@ defrouter_reset(void)
}
/*
- * Remove a router from the global list and free it.
- *
- * The ND lock must be held and is released before returning. The caller must
- * hold a reference on the router object.
+ * Look up a matching default router list entry and remove it. Returns true if a
+ * matching entry was found, false otherwise.
*/
-void
-defrouter_remove(struct nd_defrouter *dr)
+bool
+defrouter_remove(struct in6_addr *addr, struct ifnet *ifp)
{
+ struct nd_defrouter *dr;
- ND6_WLOCK_ASSERT();
- KASSERT(dr->refcnt >= 2, ("unexpected refcount 0x%x", dr->refcnt));
+ ND6_WLOCK();
+ dr = defrouter_lookup_locked(addr, ifp);
+ if (dr == NULL) {
+ ND6_WUNLOCK();
+ return (false);
+ }
defrouter_unlink(dr, NULL);
ND6_WUNLOCK();
defrouter_del(dr);
defrouter_rele(dr);
+ return (true);
}
/*
@@ -850,14 +854,14 @@ defrtrlist_update(struct nd_defrouter *new)
struct nd_defrouter *dr, *n;
int oldpref;
- ND6_WLOCK();
- if ((dr = defrouter_lookup_locked(&new->rtaddr, new->ifp)) != NULL) {
- if (new->rtlifetime == 0) {
- /* releases the ND lock */
- defrouter_remove(dr);
- return (NULL);
- }
+ if (new->rtlifetime == 0) {
+ defrouter_remove(&new->rtaddr, new->ifp);
+ return (NULL);
+ }
+ ND6_WLOCK();
+ dr = defrouter_lookup_locked(&new->rtaddr, new->ifp);
+ if (dr != NULL) {
oldpref = rtpref(dr);
/* override */
@@ -881,25 +885,17 @@ defrtrlist_update(struct nd_defrouter *new)
*/
TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
n = dr;
- goto insert;
- }
-
- /* entry does not exist */
- if (new->rtlifetime == 0) {
- ND6_WUNLOCK();
- return (NULL);
- }
-
- n = malloc(sizeof(*n), M_IP6NDP, M_NOWAIT | M_ZERO);
- if (n == NULL) {
- ND6_WUNLOCK();
- return (NULL);
+ } else {
+ n = malloc(sizeof(*n), M_IP6NDP, M_NOWAIT | M_ZERO);
+ if (n == NULL) {
+ ND6_WUNLOCK();
+ return (NULL);
+ }
+ memcpy(n, new, sizeof(*n));
+ /* Initialize with an extra reference for the caller. */
+ refcount_init(&n->refcnt, 2);
}
- memcpy(n, new, sizeof(*n));
- /* Initialize with an extra reference for the caller. */
- refcount_init(&n->refcnt, 2);
-insert:
/*
* Insert the new router in the Default Router List;
* The Default Router List should be in the descending order
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 9768df5..ebcf6d6 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -876,8 +876,8 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
UDP_PROBE(send, NULL, inp, ip6, inp, udp6);
UDPSTAT_INC(udps_opackets);
- error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions,
- NULL, inp);
+ error = ip6_output(m, optp, &inp->inp_route6, flags,
+ inp->in6p_moptions, NULL, inp);
break;
case AF_INET:
error = EAFNOSUPPORT;
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index 1523e0b..e0523d4 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -441,7 +441,7 @@ ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
setdf = V_ip4_ipsec_dfbit;
break;
default:/* propagate to outer header */
- setdf = (ip->ip_off & ntohs(IP_DF)) != 0;
+ setdf = (ip->ip_off & htons(IP_DF)) != 0;
}
itos = ip->ip_tos;
break;
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 283dddc9..0220286 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -6192,11 +6192,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
* We do need to be careful about bridges. If the
* net.link.bridge.pfil_bridge sysctl is set we can be filtering on a
* bridge, so if the input interface is a bridge member and the output
- * interface is its bridge we're not actually forwarding but bridging.
+ * interface is its bridge or a member of the same bridge we're not
+ * actually forwarding but bridging.
*/
- if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif
- && (m->m_pkthdr.rcvif->if_bridge == NULL
- || m->m_pkthdr.rcvif->if_bridge != ifp->if_softc))
+ if (dir == PF_OUT && m->m_pkthdr.rcvif && ifp != m->m_pkthdr.rcvif &&
+ (m->m_pkthdr.rcvif->if_bridge == NULL ||
+ (m->m_pkthdr.rcvif->if_bridge != ifp->if_softc &&
+ m->m_pkthdr.rcvif->if_bridge != ifp->if_bridge)))
fwdir = PF_FWD;
if (!V_pf_status.running)
diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c
index dd76d7e..51c76e7 100644
--- a/sys/nfs/bootp_subr.c
+++ b/sys/nfs/bootp_subr.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/endian.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/sockio.h>
@@ -158,6 +159,7 @@ struct bootpc_ifcontext {
int dhcpquerytype; /* dhcp type sent */
struct in_addr dhcpserver;
int gotdhcpserver;
+ uint16_t mtu;
};
#define TAG_MAXLEN 1024
@@ -199,6 +201,7 @@ struct bootpc_globalcontext {
#define TAG_ROUTERS 3 /* Routers (in order of preference) */
#define TAG_HOSTNAME 12 /* Client host name */
#define TAG_ROOT 17 /* Root path */
+#define TAG_INTF_MTU 26 /* Interface MTU Size (RFC2132) */
/* DHCP specific tags */
#define TAG_OVERLOAD 52 /* Option Overload */
@@ -273,7 +276,7 @@ static int bootpc_call(struct bootpc_globalcontext *gctx,
static void bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
struct thread *td);
-static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
+static void bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td);
static void bootpc_decode_reply(struct nfsv3_diskless *nd,
@@ -1008,33 +1011,41 @@ bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
panic("%s: SIOCDIFADDR, error=%d", __func__, error);
}
-static int
+static void
bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td)
{
int error;
- struct sockaddr_in defdst;
- struct sockaddr_in defmask;
struct sockaddr_in *sin;
struct ifreq *ifr;
struct in_aliasreq *ifra;
struct sockaddr_in *myaddr;
struct sockaddr_in *netmask;
- struct sockaddr_in *gw;
ifr = &ifctx->ireq;
ifra = &ifctx->iareq;
myaddr = &ifctx->myaddr;
netmask = &ifctx->netmask;
- gw = &ifctx->gw;
if (bootpc_ifctx_isresolved(ifctx) == 0) {
/* Shutdown interfaces where BOOTP failed */
bootpc_shutdown_interface(ifctx, td);
- return (0);
+ return;
}
- printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
+ printf("Adjusted interface %s", ifctx->ireq.ifr_name);
+
+ /* Do BOOTP interface options */
+ if (ifctx->mtu != 0) {
+ printf(" (MTU=%d%s)", ifctx->mtu,
+ (ifctx->mtu > 1514) ? "/JUMBO" : "");
+ ifr->ifr_mtu = ifctx->mtu;
+ error = ifioctl(bootp_so, SIOCSIFMTU, (caddr_t) ifr, td);
+ if (error != 0)
+ panic("%s: SIOCSIFMTU, error=%d", __func__, error);
+ }
+ printf("\n");
+
/*
* Do enough of ifconfig(8) so that the chosen interface
* can talk to the servers. (just set the address)
@@ -1054,24 +1065,48 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
if (error != 0)
panic("%s: SIOCAIFADDR, error=%d", __func__, error);
+}
+
+static void
+bootpc_add_default_route(struct bootpc_ifcontext *ifctx)
+{
+ int error;
+ struct sockaddr_in defdst;
+ struct sockaddr_in defmask;
- /* Add new default route */
+ if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY))
+ return;
- if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
- clear_sinaddr(&defdst);
- clear_sinaddr(&defmask);
- /* XXX MRT just table 0 */
- error = rtrequest_fib(RTM_ADD,
- (struct sockaddr *) &defdst, (struct sockaddr *) gw,
- (struct sockaddr *) &defmask,
- (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB);
- if (error != 0) {
- printf("%s: RTM_ADD, error=%d\n", __func__, error);
- return (error);
- }
+ clear_sinaddr(&defdst);
+ clear_sinaddr(&defmask);
+
+ error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&defdst,
+ (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB);
+ if (error != 0) {
+ printf("%s: RTM_ADD, error=%d\n", __func__, error);
}
+}
+
+static void
+bootpc_remove_default_route(struct bootpc_ifcontext *ifctx)
+{
+ int error;
+ struct sockaddr_in defdst;
+ struct sockaddr_in defmask;
+
+ if (ifctx->gw.sin_addr.s_addr == htonl(INADDR_ANY))
+ return;
+
+ clear_sinaddr(&defdst);
+ clear_sinaddr(&defmask);
- return (0);
+ error = rtrequest_fib(RTM_DELETE, (struct sockaddr *)&defdst,
+ (struct sockaddr *) &ifctx->gw, (struct sockaddr *)&defmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB);
+ if (error != 0) {
+ printf("%s: RTM_DELETE, error=%d\n", __func__, error);
+ }
}
static int
@@ -1463,6 +1498,8 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
if (p == NULL) {
p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
TAG_ROOT);
+ if (p != NULL)
+ ifctx->gotrootpath = 1;
}
#ifdef ROOTDEVNAME
if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) &&
@@ -1482,7 +1519,6 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
}
printf("rootfs %s ", p);
gctx->gotrootpath = 1;
- ifctx->gotrootpath = 1;
gctx->setrootfs = ifctx;
p = bootpc_tag(&gctx->tag, &ifctx->reply,
@@ -1522,6 +1558,11 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
p[i] = '\0';
}
+ p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
+ TAG_INTF_MTU);
+ if (p != NULL) {
+ ifctx->mtu = be16dec(p);
+ }
printf("\n");
@@ -1533,10 +1574,6 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
else
ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
}
- if (ifctx->gotgw == 0) {
- /* Use proxyarp */
- ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
- }
}
void
@@ -1728,9 +1765,11 @@ retry:
kern_setenv("boot.netif.name", ifctx->ifp->if_xname);
+ bootpc_add_default_route(ifctx);
error = md_mount(&nd->root_saddr, nd->root_hostnam,
nd->root_fh, &nd->root_fhsize,
&nd->root_args, td);
+ bootpc_remove_default_route(ifctx);
if (error != 0) {
if (gctx->any_root_overrides == 0)
panic("nfs_boot: mount root, error=%d", error);
@@ -1748,6 +1787,7 @@ retry:
ifctx->myaddr.sin_addr.s_addr |
~ ifctx->netmask.sin_addr.s_addr;
bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
+ bcopy(&ifctx->gw, &nd->mygateway, sizeof(ifctx->gw));
out:
while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) {
diff --git a/sys/nfs/nfs_diskless.c b/sys/nfs/nfs_diskless.c
index 864aae0..e765c2e 100644
--- a/sys/nfs/nfs_diskless.c
+++ b/sys/nfs/nfs_diskless.c
@@ -154,6 +154,7 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd)
* boot.netif.netmask netmask on boot interface
* boot.netif.gateway default gateway (optional)
* boot.netif.hwaddr hardware address of boot interface
+ * boot.netif.mtu interface mtu from bootp/dhcp (optional)
* boot.nfsroot.server IP address of root filesystem server
* boot.nfsroot.path path of the root filesystem on server
* boot.nfsroot.nfshandle NFS handle for root filesystem on server
diff --git a/sys/ofed/drivers/infiniband/core/iwcm.c b/sys/ofed/drivers/infiniband/core/iwcm.c
index a90f907..7e27584 100644
--- a/sys/ofed/drivers/infiniband/core/iwcm.c
+++ b/sys/ofed/drivers/infiniband/core/iwcm.c
@@ -79,7 +79,6 @@ struct iwcm_listen_work {
static LIST_HEAD(listen_port_list);
static DEFINE_MUTEX(listen_port_mutex);
-static DEFINE_MUTEX(dequeue_mutex);
struct listen_port_info {
struct list_head list;
@@ -455,7 +454,6 @@ iw_so_event_handler(struct work_struct *_work)
kfree(work);
return;
}
- mutex_lock(&dequeue_mutex);
/* Dequeue & process all new 'so' connection requests for this cmid */
while ((so = dequeue_socket(work->cm_id->so)) != NULL) {
@@ -475,7 +473,6 @@ iw_so_event_handler(struct work_struct *_work)
}
}
err:
- mutex_unlock(&dequeue_mutex);
kfree(work);
#endif
return;
@@ -487,7 +484,6 @@ iw_so_upcall(struct socket *parent_so, void *arg, int waitflag)
struct socket *so;
struct iw_cm_id *cm_id = arg;
- mutex_lock(&dequeue_mutex);
/* check whether iw_so_event_handler() already dequeued this 'so' */
so = TAILQ_FIRST(&parent_so->so_comp);
if (!so)
@@ -500,7 +496,6 @@ iw_so_upcall(struct socket *parent_so, void *arg, int waitflag)
INIT_WORK(&work->work, iw_so_event_handler);
queue_work(iwcm_wq, &work->work);
- mutex_unlock(&dequeue_mutex);
return SU_OK;
}
diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h
index eb269a4..acf3d54 100644
--- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -322,6 +322,8 @@ struct ipoib_dev_priv {
unsigned long flags;
+ int gone;
+
struct mutex vlan_mutex;
struct rb_root path_tree;
diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 5e69a52..9a68b23 100644
--- a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -258,6 +258,10 @@ ipoib_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
struct ifreq *ifr = (struct ifreq *) data;
int error = 0;
+ /* check if detaching */
+ if (priv == NULL || priv->gone != 0)
+ return (ENXIO);
+
switch (command) {
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
@@ -794,6 +798,7 @@ ipoib_detach(struct ipoib_dev_priv *priv)
dev = priv->dev;
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+ priv->gone = 1;
bpfdetach(dev);
if_detach(dev);
if_free(dev);
diff --git a/sys/ofed/drivers/net/mlx4/en_port.c b/sys/ofed/drivers/net/mlx4/en_port.c
index e4dab0a..2a1c4ba 100644
--- a/sys/ofed/drivers/net/mlx4/en_port.c
+++ b/sys/ofed/drivers/net/mlx4/en_port.c
@@ -60,10 +60,11 @@ int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv)
memset(filter, 0, sizeof(*filter));
for (i = VLAN_FLTR_SIZE - 1; i >= 0; i--) {
entry = 0;
- for (j = 0; j < 32; j++)
+ for (j = 0; j < 32; j++) {
if (test_bit(index, priv->active_vlans))
entry |= 1 << j;
- index++;
+ index++;
+ }
filter->entry[i] = cpu_to_be32(entry);
}
err = mlx4_cmd(dev, mailbox->dma, priv->port, 0, MLX4_CMD_SET_VLAN_FLTR,
diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c
index 7c5b759..b29096d 100644
--- a/sys/ofed/drivers/net/mlx4/en_rx.c
+++ b/sys/ofed/drivers/net/mlx4/en_rx.c
@@ -561,9 +561,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
struct mbuf *mb;
struct mlx4_cq *mcq = &cq->mcq;
struct mlx4_cqe *buf = cq->buf;
-#ifdef INET
- struct lro_entry *queued;
-#endif
int index;
unsigned int length;
int polled = 0;
@@ -616,7 +613,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
goto next;
}
- mb->m_pkthdr.flowid = cq->ring;
+ /* forward Toeplitz compatible hash value */
+ mb->m_pkthdr.flowid = be32_to_cpu(cqe->immed_rss_invalid);
M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE);
mb->m_pkthdr.rcvif = dev;
if (be32_to_cpu(cqe->vlan_my_qpn) &
@@ -668,10 +666,7 @@ next:
/* Flush all pending IP reassembly sessions */
out:
#ifdef INET
- while ((queued = SLIST_FIRST(&ring->lro.lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&ring->lro.lro_active, next);
- tcp_lro_flush(&ring->lro, queued);
- }
+ tcp_lro_flush_all(&ring->lro);
#endif
AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled);
mcq->cons_index = cons_index;
diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c
index 56bb5b2..4358aa6 100644
--- a/sys/ofed/drivers/net/mlx4/en_tx.c
+++ b/sys/ofed/drivers/net/mlx4/en_tx.c
@@ -1060,7 +1060,7 @@ mlx4_en_transmit(struct ifnet *dev, struct mbuf *m)
/* Compute which queue to use */
if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
- i = m->m_pkthdr.flowid % priv->tx_ring_num;
+ i = (m->m_pkthdr.flowid % 128) % priv->tx_ring_num;
}
else {
i = mlx4_en_select_queue(dev, m);
diff --git a/sys/pc98/pc98/canbus.c b/sys/pc98/pc98/canbus.c
index 8c3ee4e..0c54ceb 100644
--- a/sys/pc98/pc98/canbus.c
+++ b/sys/pc98/pc98/canbus.c
@@ -433,9 +433,9 @@ print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return retval;
}
diff --git a/sys/powerpc/include/bus.h b/sys/powerpc/include/bus.h
index 658c4eb..cb6dc77 100644
--- a/sys/powerpc/include/bus.h
+++ b/sys/powerpc/include/bus.h
@@ -79,9 +79,14 @@
#define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFUL
#define BUS_SPACE_MAXSIZE 0xFFFFFFFFFFFFFFFFUL
#else
+#ifdef BOOKE
+#define BUS_SPACE_MAXADDR 0xFFFFFFFFFULL
+#define BUS_SPACE_MAXSIZE 0xFFFFFFFFUL
+#else
#define BUS_SPACE_MAXADDR 0xFFFFFFFFUL
#define BUS_SPACE_MAXSIZE 0xFFFFFFFFUL
#endif
+#endif
#define BUS_SPACE_MAP_CACHEABLE 0x01
#define BUS_SPACE_MAP_LINEAR 0x02
diff --git a/sys/powerpc/mpc85xx/fsl_sdhc.c b/sys/powerpc/mpc85xx/fsl_sdhc.c
index 174a8e6..29bedd8 100644
--- a/sys/powerpc/mpc85xx/fsl_sdhc.c
+++ b/sys/powerpc/mpc85xx/fsl_sdhc.c
@@ -126,7 +126,7 @@ static devclass_t fsl_sdhc_devclass;
DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhc_driver, fsl_sdhc_devclass, 0, 0);
DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL);
-
+MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1);
/*****************************************************************************
* Private methods
diff --git a/sys/powerpc/mpc85xx/lbc.c b/sys/powerpc/mpc85xx/lbc.c
index a94a841..37e3ed0 100644
--- a/sys/powerpc/mpc85xx/lbc.c
+++ b/sys/powerpc/mpc85xx/lbc.c
@@ -718,8 +718,8 @@ lbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
res = rman_reserve_resource(rm, start, end, count, flags, child);
if (res == NULL) {
- device_printf(bus, "failed to reserve resource %#lx - %#lx "
- "(%#lx)\n", start, end, count);
+ device_printf(bus, "failed to reserve resource %#jx - %#jx "
+ "(%#jx)\n", start, end, count);
return (NULL);
}
@@ -749,8 +749,8 @@ lbc_print_child(device_t dev, device_t child)
rv = 0;
rv += bus_print_child_header(dev, child);
- rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
rv += bus_print_child_footer(dev, child);
return (rv);
diff --git a/sys/powerpc/mpc85xx/pci_mpc85xx.c b/sys/powerpc/mpc85xx/pci_mpc85xx.c
index 4397ac0..5a141b6 100644
--- a/sys/powerpc/mpc85xx/pci_mpc85xx.c
+++ b/sys/powerpc/mpc85xx/pci_mpc85xx.c
@@ -58,12 +58,11 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcib_private.h>
-#include <powerpc/ofw/ofw_pci.h>
-
#include "ofw_bus_if.h"
#include "pcib_if.h"
diff --git a/sys/powerpc/ofw/ofw_pci.c b/sys/powerpc/ofw/ofw_pci.c
index 0ca5bc0..20aa81f 100644
--- a/sys/powerpc/ofw/ofw_pci.c
+++ b/sys/powerpc/ofw/ofw_pci.c
@@ -384,10 +384,10 @@ ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
}
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
struct ofw_pci_range *rp;
- vm_offset_t start;
+ vm_paddr_t start;
int space;
- start = (vm_offset_t)rman_get_start(res);
+ start = (vm_paddr_t)rman_get_start(res);
/*
* Map this through the ranges list
@@ -416,8 +416,8 @@ ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
}
if (bootverbose)
- printf("ofw_pci mapdev: start %zx, len %ld\n", start,
- rman_get_size(res));
+ printf("ofw_pci mapdev: start %jx, len %jd\n",
+ (rman_res_t)start, rman_get_size(res));
p = pmap_mapdev(start, (vm_size_t)rman_get_size(res));
if (p == NULL)
diff --git a/sys/powerpc/powermac/cpcht.c b/sys/powerpc/powermac/cpcht.c
index 765d946..3145689 100644
--- a/sys/powerpc/powermac/cpcht.c
+++ b/sys/powerpc/powermac/cpcht.c
@@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <powerpc/ofw/ofw_pci.h>
+#include <dev/ofw/ofwpci.h>
#include <vm/vm.h>
#include <vm/pmap.h>
diff --git a/sys/powerpc/powermac/grackle.c b/sys/powerpc/powermac/grackle.c
index 95d59a1..3d35fea 100644
--- a/sys/powerpc/powermac/grackle.c
+++ b/sys/powerpc/powermac/grackle.c
@@ -35,11 +35,13 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/proc.h>
+#include <sys/rman.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
@@ -50,9 +52,6 @@ __FBSDID("$FreeBSD$");
#include <machine/pio.h>
#include <machine/resource.h>
-#include <sys/rman.h>
-
-#include <powerpc/ofw/ofw_pci.h>
#include <powerpc/powermac/gracklevar.h>
#include <vm/vm.h>
diff --git a/sys/powerpc/powermac/macgpio.c b/sys/powerpc/powermac/macgpio.c
index 6b67514..c72f8d7 100644
--- a/sys/powerpc/powermac/macgpio.c
+++ b/sys/powerpc/powermac/macgpio.c
@@ -236,7 +236,7 @@ macgpio_print_child(device_t dev, device_t child)
printf(" addr 0x%02x", dinfo->gpio_num); /* should not happen */
resource_list_print_type(&dinfo->mdi_resources, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
retval += bus_print_child_footer(dev, child);
return (retval);
@@ -258,7 +258,7 @@ macgpio_probe_nomatch(device_t dev, device_t child)
if (dinfo->gpio_num >= 0)
printf(" gpio %d",dinfo->gpio_num);
resource_list_print_type(&dinfo->mdi_resources, "irq",
- SYS_RES_IRQ, "%ld");
+ SYS_RES_IRQ, "%jd");
printf(" (no driver attached)\n");
}
}
diff --git a/sys/powerpc/powermac/macio.c b/sys/powerpc/powermac/macio.c
index 285d627..7a15b85 100644
--- a/sys/powerpc/powermac/macio.c
+++ b/sys/powerpc/powermac/macio.c
@@ -447,8 +447,8 @@ macio_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
@@ -470,8 +470,8 @@ macio_probe_nomatch(device_t dev, device_t child)
if ((type = ofw_bus_get_type(child)) == NULL)
type = "(unknown)";
device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child));
- resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
printf(" (no driver attached)\n");
}
}
diff --git a/sys/powerpc/powermac/uninorth.c b/sys/powerpc/powermac/uninorth.c
index e34c9d8..2d32a49 100644
--- a/sys/powerpc/powermac/uninorth.c
+++ b/sys/powerpc/powermac/uninorth.c
@@ -425,8 +425,8 @@ unin_chip_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
@@ -447,8 +447,8 @@ unin_chip_probe_nomatch(device_t dev, device_t child)
if ((type = ofw_bus_get_type(child)) == NULL)
type = "(unknown)";
device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child));
- resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
printf(" (no driver attached)\n");
}
}
@@ -591,7 +591,7 @@ unin_chip_activate_resource(device_t bus, device_t child, int type, int rid,
start = (vm_offset_t) rman_get_start(res);
if (bootverbose)
- printf("unin mapdev: start %zx, len %ld\n", start,
+ printf("unin mapdev: start %zx, len %jd\n", start,
rman_get_size(res));
p = pmap_mapdev(start, (vm_size_t) rman_get_size(res));
diff --git a/sys/powerpc/powermac/uninorthpci.c b/sys/powerpc/powermac/uninorthpci.c
index 9da06ff..6149af5 100644
--- a/sys/powerpc/powermac/uninorthpci.c
+++ b/sys/powerpc/powermac/uninorthpci.c
@@ -32,11 +32,13 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/rman.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
@@ -47,9 +49,6 @@ __FBSDID("$FreeBSD$");
#include <machine/pio.h>
#include <machine/resource.h>
-#include <sys/rman.h>
-
-#include <powerpc/ofw/ofw_pci.h>
#include <powerpc/powermac/uninorthvar.h>
#include <vm/vm.h>
diff --git a/sys/powerpc/powermac/uninorthvar.h b/sys/powerpc/powermac/uninorthvar.h
index e08478d..e570da0 100644
--- a/sys/powerpc/powermac/uninorthvar.h
+++ b/sys/powerpc/powermac/uninorthvar.h
@@ -30,7 +30,7 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/ofw/ofw_pci.h>
-#include <powerpc/ofw/ofw_pci.h>
+#include <dev/ofw/ofwpci.h>
struct uninorth_softc {
struct ofw_pci_softc pci_sc;
diff --git a/sys/powerpc/powerpc/nexus.c b/sys/powerpc/powerpc/nexus.c
index 1ad118c..f5a3da8 100644
--- a/sys/powerpc/powerpc/nexus.c
+++ b/sys/powerpc/powerpc/nexus.c
@@ -203,7 +203,7 @@ nexus_activate_resource(device_t bus __unused, device_t child __unused,
start = (vm_paddr_t) rman_get_start(r);
if (bootverbose)
- printf("nexus mapdev: start %jx, len %ld\n",
+ printf("nexus mapdev: start %jx, len %jd\n",
(uintmax_t)start, rman_get_size(r));
p = pmap_mapdev(start, (vm_size_t) rman_get_size(r));
diff --git a/sys/powerpc/ps3/ps3bus.c b/sys/powerpc/ps3/ps3bus.c
index bbb40c8..37ea0b7 100644
--- a/sys/powerpc/ps3/ps3bus.c
+++ b/sys/powerpc/ps3/ps3bus.c
@@ -480,9 +480,9 @@ ps3bus_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
retval += resource_list_print_type(&dinfo->resources, "mem",
- SYS_RES_MEMORY, "%#lx");
+ SYS_RES_MEMORY, "%#jx");
retval += resource_list_print_type(&dinfo->resources, "irq",
- SYS_RES_IRQ, "%ld");
+ SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
diff --git a/sys/powerpc/pseries/rtas_pci.c b/sys/powerpc/pseries/rtas_pci.c
index bb72b71..873168e 100644
--- a/sys/powerpc/pseries/rtas_pci.c
+++ b/sys/powerpc/pseries/rtas_pci.c
@@ -32,11 +32,13 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/rman.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
@@ -48,12 +50,9 @@ __FBSDID("$FreeBSD$");
#include <machine/resource.h>
#include <machine/rtas.h>
-#include <sys/rman.h>
-
#include <vm/vm.h>
#include <vm/pmap.h>
-#include <powerpc/ofw/ofw_pci.h>
#include <powerpc/pseries/plpar_iommu.h>
#include "pcib_if.h"
diff --git a/sys/powerpc/pseries/vdevice.c b/sys/powerpc/pseries/vdevice.c
index 2323bc7..72b76c7 100644
--- a/sys/powerpc/pseries/vdevice.c
+++ b/sys/powerpc/pseries/vdevice.c
@@ -180,7 +180,7 @@ vdevice_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
diff --git a/sys/powerpc/psim/iobus.c b/sys/powerpc/psim/iobus.c
index 741b62a..ce4a93a 100644
--- a/sys/powerpc/psim/iobus.c
+++ b/sys/powerpc/psim/iobus.c
@@ -253,7 +253,7 @@ iobus_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
retval += printf(" offset 0x%x", dinfo->id_reg[1]);
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
diff --git a/sys/rpc/rpc_generic.c b/sys/rpc/rpc_generic.c
index 28aa849..80d658d 100644
--- a/sys/rpc/rpc_generic.c
+++ b/sys/rpc/rpc_generic.c
@@ -390,15 +390,11 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr)
}
ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
- if (ret == NULL)
- goto out;
switch (af) {
case AF_INET:
sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
M_WAITOK);
- if (sin == NULL)
- goto out;
memset(sin, 0, sizeof *sin);
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
@@ -415,8 +411,6 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr)
case AF_INET6:
sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
M_WAITOK);
- if (sin6 == NULL)
- goto out;
memset(sin6, 0, sizeof *sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
@@ -433,8 +427,6 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr)
case AF_LOCAL:
sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
M_WAITOK);
- if (sun == NULL)
- goto out;
memset(sun, 0, sizeof *sun);
sun->sun_family = AF_LOCAL;
strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
diff --git a/sys/rpc/svc.c b/sys/rpc/svc.c
index f725d53..b436c18 100644
--- a/sys/rpc/svc.c
+++ b/sys/rpc/svc.c
@@ -560,7 +560,7 @@ svc_loss_reg(SVCXPRT *xprt, void (*dispatch)(SVCXPRT *))
mtx_unlock(&pool->sp_lock);
return (TRUE);
}
- s = malloc(sizeof (struct svc_callout), M_RPC, M_NOWAIT);
+ s = malloc(sizeof(struct svc_loss_callout), M_RPC, M_NOWAIT);
if (s == NULL) {
mtx_unlock(&pool->sp_lock);
return (FALSE);
diff --git a/sys/sparc64/central/central.c b/sys/sparc64/central/central.c
index 15876f0..9b16364 100644
--- a/sys/sparc64/central/central.c
+++ b/sys/sparc64/central/central.c
@@ -295,5 +295,5 @@ central_print_res(struct central_devinfo *cdi)
{
return (resource_list_print_type(&cdi->cdi_rl, "mem", SYS_RES_MEMORY,
- "%#lx"));
+ "%#jx"));
}
diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c
index a53b20b..49abe18 100644
--- a/sys/sparc64/ebus/ebus.c
+++ b/sys/sparc64/ebus/ebus.c
@@ -721,8 +721,8 @@ ebus_print_res(struct ebus_devinfo *edi)
retval = 0;
retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
return (retval);
}
diff --git a/sys/sparc64/fhc/fhc.c b/sys/sparc64/fhc/fhc.c
index b9d8bc6..85aa67d 100644
--- a/sys/sparc64/fhc/fhc.c
+++ b/sys/sparc64/fhc/fhc.c
@@ -529,7 +529,7 @@ fhc_print_res(struct fhc_devinfo *fdi)
rv = 0;
rv += resource_list_print_type(&fdi->fdi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
- rv += resource_list_print_type(&fdi->fdi_rl, "irq", SYS_RES_IRQ, "%ld");
+ "%#jx");
+ rv += resource_list_print_type(&fdi->fdi_rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c
index ba3643c..55f1313 100644
--- a/sys/sparc64/pci/apb.c
+++ b/sys/sparc64/pci/apb.c
@@ -136,7 +136,7 @@ apb_map_print(uint8_t map, rman_res_t scale)
for (first = 1, i = 0; i < 8; i++) {
if ((map & (1 << i)) != 0) {
- printf("%s0x%lx-0x%lx", first ? "" : ", ",
+ printf("%s0x%jx-0x%jx", first ? "" : ", ",
i * scale, (i + 1) * scale - 1);
first = 0;
}
@@ -253,26 +253,26 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
case SYS_RES_IOPORT:
if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end)) {
device_printf(dev, "device %s requested unsupported "
- "I/O range 0x%lx-0x%lx\n",
+ "I/O range 0x%jx-0x%jx\n",
device_get_nameunit(child), start, end);
return (NULL);
}
if (bootverbose)
device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
- "%s requested decoded I/O range 0x%lx-0x%lx\n",
+ "%s requested decoded I/O range 0x%jx-0x%jx\n",
device_get_nameunit(child), start, end);
break;
case SYS_RES_MEMORY:
if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start,
end)) {
device_printf(dev, "device %s requested unsupported "
- "memory range 0x%lx-0x%lx\n",
+ "memory range 0x%jx-0x%jx\n",
device_get_nameunit(child), start, end);
return (NULL);
}
if (bootverbose)
device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
- "%s requested decoded memory range 0x%lx-0x%lx\n",
+ "%s requested decoded memory range 0x%jx-0x%jx\n",
device_get_nameunit(child), start, end);
break;
}
diff --git a/sys/sparc64/sbus/dma_sbus.c b/sys/sparc64/sbus/dma_sbus.c
index cf22569..4a83c92 100644
--- a/sys/sparc64/sbus/dma_sbus.c
+++ b/sys/sparc64/sbus/dma_sbus.c
@@ -409,7 +409,7 @@ dma_print_res(struct dma_devinfo *ddi)
rv = 0;
rv += resource_list_print_type(&ddi->ddi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
- rv += resource_list_print_type(&ddi->ddi_rl, "irq", SYS_RES_IRQ, "%ld");
+ "%#jx");
+ rv += resource_list_print_type(&ddi->ddi_rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/sparc64/sbus/sbus.c b/sys/sparc64/sbus/sbus.c
index af46c77..65e44ff 100644
--- a/sys/sparc64/sbus/sbus.c
+++ b/sys/sparc64/sbus/sbus.c
@@ -929,8 +929,8 @@ sbus_print_res(struct sbus_devinfo *sdi)
rv = 0;
rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
return (rv);
}
diff --git a/sys/sparc64/sparc64/nexus.c b/sys/sparc64/sparc64/nexus.c
index 3e099bd..3e72b6c 100644
--- a/sys/sparc64/sparc64/nexus.c
+++ b/sys/sparc64/sparc64/nexus.c
@@ -605,8 +605,8 @@ nexus_print_res(struct nexus_devinfo *ndi)
rv = 0;
rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
return (rv);
}
diff --git a/sys/sparc64/sparc64/upa.c b/sys/sparc64/sparc64/upa.c
index 504d001..34bc50f 100644
--- a/sys/sparc64/sparc64/upa.c
+++ b/sys/sparc64/sparc64/upa.c
@@ -588,8 +588,8 @@ upa_print_res(struct upa_devinfo *udi)
rv = 0;
rv += resource_list_print_type(&udi->udi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
rv += resource_list_print_type(&udi->udi_rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
return (rv);
}
diff --git a/sys/sys/_types.h b/sys/sys/_types.h
index 3b3c16d..16039a6 100644
--- a/sys/sys/_types.h
+++ b/sys/sys/_types.h
@@ -112,6 +112,6 @@ typedef union {
__int64_t _mbstateL; /* for alignment */
} __mbstate_t;
-typedef unsigned long __rman_res_t;
+typedef __uintmax_t __rman_res_t;
#endif /* !_SYS__TYPES_H_ */
diff --git a/sys/sys/aio.h b/sys/sys/aio.h
index 25ffb28..0abee2d 100644
--- a/sys/sys/aio.h
+++ b/sys/sys/aio.h
@@ -238,7 +238,7 @@ int aio_suspend(const struct aiocb * const[], int, const struct timespec *);
int aio_mlock(struct aiocb *);
#ifdef __BSD_VISIBLE
-int aio_waitcomplete(struct aiocb **, struct timespec *);
+ssize_t aio_waitcomplete(struct aiocb **, struct timespec *);
#endif
int aio_fsync(int op, struct aiocb *aiocbp);
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index 5f0df65..e0297cc 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -141,6 +141,7 @@ void devctl_notify(const char *__system, const char *__subsystem,
const char *__type, const char *__data);
void devctl_queue_data_f(char *__data, int __flags);
void devctl_queue_data(char *__data);
+void devctl_safe_quote(char *__dst, const char *__src, size_t len);
/**
* Device name parsers. Hook to allow device enumerators to map
diff --git a/sys/sys/fail.h b/sys/sys/fail.h
index e011459..bd2eab1 100644
--- a/sys/sys/fail.h
+++ b/sys/sys/fail.h
@@ -37,6 +37,11 @@
#include <sys/linker_set.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
/**
* Failpoint return codes, used internally.
@@ -49,7 +54,8 @@ enum fail_point_return_code {
};
struct fail_point_entry;
-TAILQ_HEAD(fail_point_entries, fail_point_entry);
+struct fail_point_setting;
+
/**
* Internal failpoint structure, tracking all the current details of the
* failpoint. This structure is the core component shared between the
@@ -57,22 +63,42 @@ TAILQ_HEAD(fail_point_entries, fail_point_entry);
* @ingroup failpoint_private
*/
struct fail_point {
- const char *fp_name; /**< name of fail point */
- const char *fp_location; /**< file:line of fail point */
- struct fail_point_entries fp_entries; /**< list of entries */
+ const char *fp_name; /* name of fail point */
+ const char *fp_location; /* file:line of fail point */
+ volatile int fp_ref_cnt; /**
+ * protects fp_setting: while holding
+ * a ref, fp_setting points to an
+ * unfreed fail_point_setting
+ */
+ struct fail_point_setting * volatile fp_setting;
int fp_flags;
- void (*fp_sleep_fn)(void *); /**< Function to call at end of
- * sleep for sleep failpoints */
- void *fp_sleep_arg; /**< Arg for sleep_fn */
+
+ /**< Function to call before sleep or pause */
+ void (*fp_pre_sleep_fn)(void *);
+ /**< Arg for fp_pre_sleep_fn */
+ void *fp_pre_sleep_arg;
+
+ /**< Function to call after waking from sleep or pause */
+ void (*fp_post_sleep_fn)(void *);
+ /**< Arg for fp_post_sleep_fn */
+ void *fp_post_sleep_arg;
};
#define FAIL_POINT_DYNAMIC_NAME 0x01 /**< Must free name on destroy */
+/**< Use timeout path for sleep instead of msleep */
+#define FAIL_POINT_USE_TIMEOUT_PATH 0x02
+/**< If fail point is set to sleep, replace the sleep call with delay */
+#define FAIL_POINT_NONSLEEPABLE 0x04
+
+#define FAIL_POINT_CV_DESC "fp cv no iterators"
+#define FAIL_POINT_IS_OFF(fp) (__predict_true((fp)->fp_setting == NULL) || \
+ __predict_true(fail_point_is_off(fp)))
__BEGIN_DECLS
/* Private failpoint eval function -- use fail_point_eval() instead. */
enum fail_point_return_code fail_point_eval_nontrivial(struct fail_point *,
- int *ret);
+ int *ret);
/**
* @addtogroup failpoint
@@ -86,26 +112,62 @@ enum fail_point_return_code fail_point_eval_nontrivial(struct fail_point *,
void fail_point_init(struct fail_point *, const char *fmt, ...)
__printflike(2, 3);
+/* Return true iff this fail point is set to off, false otherwise */
+bool fail_point_is_off(struct fail_point *fp);
+
+/**
+ * Set the pre-sleep function for a fail point
+ * If fp_post_sleep_fn is specified, then FAIL_POINT_SLEEP will result in a
+ * (*fp->fp_pre_sleep_fn)(fp->fp_pre_sleep_arg) call by the thread.
+ */
+static inline void
+fail_point_sleep_set_pre_func(struct fail_point *fp, void (*sleep_fn)(void *))
+{
+ fp->fp_pre_sleep_fn = sleep_fn;
+}
+
+static inline void
+fail_point_sleep_set_pre_arg(struct fail_point *fp, void *sleep_arg)
+{
+ fp->fp_pre_sleep_arg = sleep_arg;
+}
+
/**
- * Set the sleep function for a fail point
- * If sleep_fn is specified, then FAIL_POINT_SLEEP will result in a
- * (*fp->sleep_fn)(fp->sleep_arg) call by the timer thread. Otherwise,
- * if sleep_fn is NULL (default), then FAIL_POINT_SLEEP will result in the
- * fail_point_eval() call sleeping.
+ * Set the post-sleep function. This will be passed to timeout if we take
+ * the timeout path. This must be set if you sleep using the timeout path.
*/
-static __inline void
-fail_point_sleep_set_func(struct fail_point *fp, void (*sleep_fn)(void *))
+static inline void
+fail_point_sleep_set_post_func(struct fail_point *fp, void (*sleep_fn)(void *))
{
- fp->fp_sleep_fn = sleep_fn;
+ fp->fp_post_sleep_fn = sleep_fn;
}
+static inline void
+fail_point_sleep_set_post_arg(struct fail_point *fp, void *sleep_arg)
+{
+ fp->fp_post_sleep_arg = sleep_arg;
+}
/**
- * Set the argument for the sleep function for a fail point
+ * If the FAIL_POINT_USE_TIMEOUT flag is set on a failpoint, then
+ * FAIL_POINT_SLEEP will result in a call to timeout instead of
+ * msleep. Note that if you sleep while this flag is set, you must
+ * set fp_post_sleep_fn or an error will occur upon waking.
*/
-static __inline void
-fail_point_sleep_set_arg(struct fail_point *fp, void *sleep_arg)
+static inline void
+fail_point_use_timeout_path(struct fail_point *fp, bool use_timeout,
+ void (*post_sleep_fn)(void *))
{
- fp->fp_sleep_arg = sleep_arg;
+ KASSERT(!use_timeout || post_sleep_fn != NULL ||
+ (post_sleep_fn == NULL && fp->fp_post_sleep_fn != NULL),
+ ("Setting fp to use timeout, but not setting post_sleep_fn\n"));
+
+ if (use_timeout)
+ fp->fp_flags |= FAIL_POINT_USE_TIMEOUT_PATH;
+ else
+ fp->fp_flags &= ~FAIL_POINT_USE_TIMEOUT_PATH;
+
+ if (post_sleep_fn != NULL)
+ fp->fp_post_sleep_fn = post_sleep_fn;
}
/**
@@ -116,33 +178,64 @@ void fail_point_destroy(struct fail_point *);
/**
* Evaluate a failpoint.
*/
-static __inline enum fail_point_return_code
+static inline enum fail_point_return_code
fail_point_eval(struct fail_point *fp, int *ret)
{
- if (TAILQ_EMPTY(&fp->fp_entries)) {
+ if (__predict_true(fp->fp_setting == NULL))
return (FAIL_POINT_RC_CONTINUE);
- }
return (fail_point_eval_nontrivial(fp, ret));
}
__END_DECLS
/* Declare a fail_point and its sysctl in a function. */
-#define _FAIL_POINT_NAME(name) _fail_point_##name
-#define _FAIL_POINT_LOCATION() "(" __FILE__ ":" __XSTRING(__LINE__) ")"
+#define _FAIL_POINT_NAME(name) _fail_point_##name
+#define _FAIL_POINT_LOCATION() "(" __FILE__ ":" __XSTRING(__LINE__) ")"
+#define _FAIL_POINT_INIT(parent, name, flags) \
+ static struct fail_point _FAIL_POINT_NAME(name) = { \
+ .fp_name = #name, \
+ .fp_location = _FAIL_POINT_LOCATION(), \
+ .fp_ref_cnt = 0, \
+ .fp_setting = NULL, \
+ .fp_flags = (flags), \
+ .fp_pre_sleep_fn = NULL, \
+ .fp_pre_sleep_arg = NULL, \
+ .fp_post_sleep_fn = NULL, \
+ .fp_post_sleep_arg = NULL, \
+ }; \
+ SYSCTL_OID(parent, OID_AUTO, name, \
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, \
+ &_FAIL_POINT_NAME(name), 0, fail_point_sysctl, \
+ "A", ""); \
+ SYSCTL_OID(parent, OID_AUTO, status_##name, \
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, \
+ &_FAIL_POINT_NAME(name), 0, \
+ fail_point_sysctl_status, "A", "");
+#define _FAIL_POINT_EVAL(name, cond, code...) \
+ int RETURN_VALUE; \
+ \
+ if (__predict_false(cond && \
+ fail_point_eval(&_FAIL_POINT_NAME(name), &RETURN_VALUE))) { \
+ \
+ code; \
+ \
+ }
+
/**
- * Instantiate a failpoint which returns "value" from the function when triggered.
- * @param parent The parent sysctl under which to locate the sysctl
+ * Instantiate a failpoint which returns "RETURN_VALUE" from the function
+ * when triggered.
+ * @param parent The parent sysctl under which to locate the fp's sysctl
* @param name The name of the failpoint in the sysctl tree (and printouts)
- * @return Instantly returns the return("value") specified in the
+ * @return Instantly returns the RETURN_VALUE specified in the
* failpoint, if triggered.
*/
#define KFAIL_POINT_RETURN(parent, name) \
KFAIL_POINT_CODE(parent, name, return RETURN_VALUE)
/**
- * Instantiate a failpoint which returns (void) from the function when triggered.
+ * Instantiate a failpoint which returns (void) from the function when
+ * triggered.
* @param parent The parent sysctl under which to locate the sysctl
* @param name The name of the failpoint in the sysctl tree (and printouts)
* @return Instantly returns void, if triggered in the failpoint.
@@ -153,7 +246,8 @@ __END_DECLS
/**
* Instantiate a failpoint which sets an error when triggered.
* @param parent The parent sysctl under which to locate the sysctl
- * @param name The name of the failpoint in the sysctl tree (and printouts)
+ * @param name The name of the failpoint in the sysctl tree (and
+ * printouts)
* @param error_var A variable to set to the failpoint's specified
* return-value when triggered
*/
@@ -164,7 +258,8 @@ __END_DECLS
* Instantiate a failpoint which sets an error and then goes to a
* specified label in the function when triggered.
* @param parent The parent sysctl under which to locate the sysctl
- * @param name The name of the failpoint in the sysctl tree (and printouts)
+ * @param name The name of the failpoint in the sysctl tree (and
+ * printouts)
* @param error_var A variable to set to the failpoint's specified
* return-value when triggered
* @param label The location to goto when triggered.
@@ -173,39 +268,81 @@ __END_DECLS
KFAIL_POINT_CODE(parent, name, (error_var) = RETURN_VALUE; goto label)
/**
+ * Instantiate a failpoint which sets its pre- and post-sleep callback
+ * mechanisms.
+ * @param parent The parent sysctl under which to locate the sysctl
+ * @param name The name of the failpoint in the sysctl tree (and
+ * printouts)
+ * @param pre_func Function pointer to the pre-sleep function, which will be
+ * called directly before going to sleep.
+ * @param pre_arg Argument to the pre-sleep function
+ * @param post_func Function pointer to the pot-sleep function, which will be
+ * called directly before going to sleep.
+ * @param post_arg Argument to the post-sleep function
+ */
+#define KFAIL_POINT_SLEEP_CALLBACKS(parent, name, pre_func, pre_arg, \
+ post_func, post_arg) \
+ KFAIL_POINT_CODE_SLEEP_CALLBACKS(parent, name, pre_func, \
+ pre_arg, post_func, post_arg, return RETURN_VALUE)
+
+/**
+ * Instantiate a failpoint which runs arbitrary code when triggered, and sets
+ * its pre- and post-sleep callback mechanisms
+ * @param parent The parent sysctl under which to locate the sysctl
+ * @param name The name of the failpoint in the sysctl tree (and
+ * printouts)
+ * @param pre_func Function pointer to the pre-sleep function, which will be
+ * called directly before going to sleep.
+ * @param pre_arg Argument to the pre-sleep function
+ * @param post_func Function pointer to the pot-sleep function, which will be
+ * called directly before going to sleep.
+ * @param post_arg Argument to the post-sleep function
+ * @param code The arbitrary code to run when triggered. Can reference
+ * "RETURN_VALUE" if desired to extract the specified
+ * user return-value when triggered. Note that this is
+ * implemented with a do-while loop so be careful of
+ * break and continue statements.
+ */
+#define KFAIL_POINT_CODE_SLEEP_CALLBACKS(parent, name, pre_func, pre_arg, \
+ post_func, post_arg, code...) \
+ do { \
+ _FAIL_POINT_INIT(parent, name) \
+ _FAIL_POINT_NAME(name).fp_pre_sleep_fn = pre_func; \
+ _FAIL_POINT_NAME(name).fp_pre_sleep_arg = pre_arg; \
+ _FAIL_POINT_NAME(name).fp_post_sleep_fn = post_func; \
+ _FAIL_POINT_NAME(name).fp_post_sleep_arg = post_arg; \
+ _FAIL_POINT_EVAL(name, true, code) \
+ } while (0)
+
+
+/**
* Instantiate a failpoint which runs arbitrary code when triggered.
* @param parent The parent sysctl under which to locate the sysctl
* @param name The name of the failpoint in the sysctl tree
- * (and printouts)
+ * (and printouts)
* @param code The arbitrary code to run when triggered. Can reference
* "RETURN_VALUE" if desired to extract the specified
* user return-value when triggered. Note that this is
* implemented with a do-while loop so be careful of
* break and continue statements.
*/
-#define KFAIL_POINT_CODE(parent, name, code) \
-do { \
- int RETURN_VALUE; \
- static struct fail_point _FAIL_POINT_NAME(name) = { \
- #name, \
- _FAIL_POINT_LOCATION(), \
- TAILQ_HEAD_INITIALIZER(_FAIL_POINT_NAME(name).fp_entries), \
- 0, \
- NULL, NULL, \
- }; \
- SYSCTL_OID(parent, OID_AUTO, name, \
- CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, \
- &_FAIL_POINT_NAME(name), 0, fail_point_sysctl, \
- "A", ""); \
- \
- if (__predict_false( \
- fail_point_eval(&_FAIL_POINT_NAME(name), &RETURN_VALUE))) { \
- \
- code; \
- \
- } \
-} while (0)
+#define KFAIL_POINT_CODE(parent, name, code...) \
+ do { \
+ _FAIL_POINT_INIT(parent, name, 0) \
+ _FAIL_POINT_EVAL(name, true, code) \
+ } while (0)
+
+#define KFAIL_POINT_CODE_FLAGS(parent, name, flags, code...) \
+ do { \
+ _FAIL_POINT_INIT(parent, name, flags) \
+ _FAIL_POINT_EVAL(name, true, code) \
+ } while (0)
+#define KFAIL_POINT_CODE_COND(parent, name, cond, flags, code...) \
+ do { \
+ _FAIL_POINT_INIT(parent, name, flags) \
+ _FAIL_POINT_EVAL(name, cond, code) \
+ } while (0)
/**
* @}
@@ -214,6 +351,7 @@ do { \
#ifdef _KERNEL
int fail_point_sysctl(SYSCTL_HANDLER_ARGS);
+int fail_point_sysctl_status(SYSCTL_HANDLER_ARGS);
/* The fail point sysctl tree. */
SYSCTL_DECL(_debug_fail_point);
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 524c1ce..c30eb05 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -112,7 +112,7 @@ typedef int fo_chown_t(struct file *fp, uid_t uid, gid_t gid,
struct ucred *active_cred, struct thread *td);
typedef int fo_sendfile_t(struct file *fp, int sockfd, struct uio *hdr_uio,
struct uio *trl_uio, off_t offset, size_t nbytes,
- off_t *sent, int flags, int kflags, struct thread *td);
+ off_t *sent, int flags, struct thread *td);
typedef int fo_seek_t(struct file *fp, off_t offset, int whence,
struct thread *td);
typedef int fo_fill_kinfo_t(struct file *fp, struct kinfo_file *kif,
@@ -376,11 +376,11 @@ fo_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
static __inline int
fo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
- int kflags, struct thread *td)
+ struct thread *td)
{
return ((*fp->f_ops->fo_sendfile)(fp, sockfd, hdr_uio, trl_uio, offset,
- nbytes, sent, flags, kflags, td));
+ nbytes, sent, flags, td));
}
static __inline int
diff --git a/sys/sys/intr.h b/sys/sys/intr.h
index 5ef2379..04325c1 100644
--- a/sys/sys/intr.h
+++ b/sys/sys/intr.h
@@ -1,7 +1,6 @@
-/* $NetBSD: intr.h,v 1.7 2003/06/16 20:01:00 thorpej Exp $ */
-
/*-
- * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 2015-2016 Svatopluk Kraus
+ * Copyright (c) 2015-2016 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -12,28 +11,20 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Mark Brinicombe
- * for the NetBSD Project.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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)
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
- *
*/
#ifndef _SYS_INTR_H_
@@ -41,6 +32,37 @@
#include <sys/systm.h>
+enum intr_map_data_type {
+ INTR_MAP_DATA_ACPI,
+ INTR_MAP_DATA_FDT,
+};
+
+#ifdef DEV_ACPI
+struct intr_map_data_acpi {
+ u_int irq;
+ enum intr_polarity pol;
+ enum intr_trigger trig;
+};
+#endif
+#ifdef FDT
+struct intr_map_data_fdt {
+ u_int ncells;
+ pcell_t *cells;
+};
+#endif
+
+struct intr_map_data {
+ enum intr_map_data_type type;
+ union {
+#ifdef DEV_ACPI
+ struct intr_map_data_acpi acpi;
+#endif
+#ifdef FDT
+ struct intr_map_data_fdt fdt;
+#endif
+ };
+};
+
#ifdef notyet
#define INTR_SOLO INTR_MD1
typedef int intr_irq_filter_t(void *arg, struct trapframe *tf);
@@ -50,30 +72,16 @@ typedef int intr_irq_filter_t(void *arg);
#define INTR_ISRC_NAMELEN (MAXCOMLEN + 1)
-typedef void intr_ipi_filter_t(void *arg);
-
-enum intr_isrc_type {
- INTR_ISRCT_NAMESPACE,
- INTR_ISRCT_FDT
-};
-
-#define INTR_ISRCF_REGISTERED 0x01 /* registered in a controller */
-#define INTR_ISRCF_PERCPU 0x02 /* per CPU interrupt */
+#define INTR_ISRCF_IPI 0x01 /* IPI interrupt */
+#define INTR_ISRCF_PPI 0x02 /* PPI interrupt */
#define INTR_ISRCF_BOUND 0x04 /* bound to a CPU */
/* Interrupt source definition. */
struct intr_irqsrc {
device_t isrc_dev; /* where isrc is mapped */
- intptr_t isrc_xref; /* device reference key */
- uintptr_t isrc_data; /* device data for isrc */
u_int isrc_irq; /* unique identificator */
- enum intr_isrc_type isrc_type; /* how is isrc decribed */
u_int isrc_flags;
char isrc_name[INTR_ISRC_NAMELEN];
- uint16_t isrc_nspc_type;
- uint16_t isrc_nspc_num;
- enum intr_trigger isrc_trig;
- enum intr_polarity isrc_pol;
cpuset_t isrc_cpu; /* on which CPUs is enabled */
u_int isrc_index;
u_long * isrc_count;
@@ -81,47 +89,46 @@ struct intr_irqsrc {
struct intr_event * isrc_event;
#ifdef INTR_SOLO
intr_irq_filter_t * isrc_filter;
-#endif
- intr_ipi_filter_t * isrc_ipifilter;
void * isrc_arg;
-#ifdef FDT
- u_int isrc_ncells;
- pcell_t isrc_cells[]; /* leave it last */
#endif
};
-void intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
- __printflike(2, 3);
+/* Intr interface for PIC. */
+int intr_isrc_deregister(struct intr_irqsrc *);
+int intr_isrc_register(struct intr_irqsrc *, device_t, u_int, const char *, ...)
+ __printflike(4, 5);
-void intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf);
-
-#define INTR_IRQ_NSPC_NONE 0
-#define INTR_IRQ_NSPC_PLAIN 1
-#define INTR_IRQ_NSPC_IRQ 2
-#define INTR_IRQ_NSPC_IPI 3
+int intr_isrc_dispatch(struct intr_irqsrc *, struct trapframe *);
+u_int intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask);
-u_int intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num);
-#ifdef FDT
-u_int intr_fdt_map_irq(phandle_t, pcell_t *, u_int);
-#endif
+int intr_pic_register(device_t, intptr_t);
+int intr_pic_deregister(device_t, intptr_t);
+int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *, u_int);
extern device_t intr_irq_root_dev;
-int intr_pic_register(device_t dev, intptr_t xref);
-int intr_pic_unregister(device_t dev, intptr_t xref);
-int intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
- void *arg, u_int ipicount);
+/* Intr interface for BUS. */
+int intr_map_irq(device_t, intptr_t, struct intr_map_data *, u_int *);
-int intr_irq_add_handler(device_t dev, driver_filter_t, driver_intr_t, void *,
- u_int, int, void **);
-int intr_irq_remove_handler(device_t dev, u_int, void *);
-int intr_irq_config(u_int, enum intr_trigger, enum intr_polarity);
-int intr_irq_describe(u_int, void *, const char *);
+int intr_alloc_irq(device_t, struct resource *);
+int intr_release_irq(device_t, struct resource *);
-u_int intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask);
+int intr_setup_irq(device_t, struct resource *, driver_filter_t, driver_intr_t,
+ void *, int, void **);
+int intr_teardown_irq(device_t, struct resource *, void *);
+
+int intr_describe_irq(device_t, struct resource *, void *, const char *);
+
+#ifdef DEV_ACPI
+u_int intr_acpi_map_irq(device_t, u_int, enum intr_polarity,
+ enum intr_trigger);
+#endif
+#ifdef FDT
+u_int intr_fdt_map_irq(phandle_t, pcell_t *, u_int);
+#endif
#ifdef SMP
-int intr_irq_bind(u_int, int);
+int intr_bind_irq(device_t, struct resource *, int);
void intr_pic_init_secondary(void);
diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h
index efbaa4a..b1b7257 100644
--- a/sys/sys/libkern.h
+++ b/sys/sys/libkern.h
@@ -65,6 +65,16 @@ static __inline u_quad_t uqmax(u_quad_t a, u_quad_t b) { return (a > b ? a : b);
static __inline u_quad_t uqmin(u_quad_t a, u_quad_t b) { return (a < b ? a : b); }
static __inline u_long ulmax(u_long a, u_long b) { return (a > b ? a : b); }
static __inline u_long ulmin(u_long a, u_long b) { return (a < b ? a : b); }
+static __inline __uintmax_t ummax(__uintmax_t a, __uintmax_t b)
+{
+
+ return (a > b ? a : b);
+}
+static __inline __uintmax_t ummin(__uintmax_t a, __uintmax_t b)
+{
+
+ return (a < b ? a : b);
+}
static __inline off_t omax(off_t a, off_t b) { return (a > b ? a : b); }
static __inline off_t omin(off_t a, off_t b) { return (a < b ? a : b); }
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 0b9fb2b..4a48d47 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -44,6 +44,32 @@
#endif
#endif
+#ifdef _KERNEL
+#include <sys/sdt.h>
+
+#define MBUF_PROBE1(probe, arg0) \
+ SDT_PROBE1(sdt, , , probe, arg0)
+#define MBUF_PROBE2(probe, arg0, arg1) \
+ SDT_PROBE2(sdt, , , probe, arg0, arg1)
+#define MBUF_PROBE3(probe, arg0, arg1, arg2) \
+ SDT_PROBE3(sdt, , , probe, arg0, arg1, arg2)
+#define MBUF_PROBE4(probe, arg0, arg1, arg2, arg3) \
+ SDT_PROBE4(sdt, , , probe, arg0, arg1, arg2, arg3)
+#define MBUF_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \
+ SDT_PROBE5(sdt, , , probe, arg0, arg1, arg2, arg3, arg4)
+
+SDT_PROBE_DECLARE(sdt, , , m__init);
+SDT_PROBE_DECLARE(sdt, , , m__gethdr);
+SDT_PROBE_DECLARE(sdt, , , m__get);
+SDT_PROBE_DECLARE(sdt, , , m__getcl);
+SDT_PROBE_DECLARE(sdt, , , m__clget);
+SDT_PROBE_DECLARE(sdt, , , m__cljget);
+SDT_PROBE_DECLARE(sdt, , , m__cljset);
+SDT_PROBE_DECLARE(sdt, , , m__free);
+SDT_PROBE_DECLARE(sdt, , , m__freem);
+
+#endif /* _KERNEL */
+
/*
* Mbufs are of a single size, MSIZE (sys/param.h), which includes overhead.
* An mbuf may add a single "mbuf cluster" of size MCLBYTES (also in
@@ -672,42 +698,52 @@ m_init(struct mbuf *m, int how, short type, int flags)
m->m_len = 0;
m->m_flags = flags;
m->m_type = type;
- if (flags & M_PKTHDR) {
- if ((error = m_pkthdr_init(m, how)) != 0)
- return (error);
- }
+ if (flags & M_PKTHDR)
+ error = m_pkthdr_init(m, how);
+ else
+ error = 0;
- return (0);
+ MBUF_PROBE5(m__init, m, how, type, flags, error);
+ return (error);
}
static __inline struct mbuf *
m_get(int how, short type)
{
+ struct mbuf *m;
struct mb_args args;
args.flags = 0;
args.type = type;
- return (uma_zalloc_arg(zone_mbuf, &args, how));
+ m = uma_zalloc_arg(zone_mbuf, &args, how);
+ MBUF_PROBE3(m__get, how, type, m);
+ return (m);
}
static __inline struct mbuf *
m_gethdr(int how, short type)
{
+ struct mbuf *m;
struct mb_args args;
args.flags = M_PKTHDR;
args.type = type;
- return (uma_zalloc_arg(zone_mbuf, &args, how));
+ m = uma_zalloc_arg(zone_mbuf, &args, how);
+ MBUF_PROBE3(m__gethdr, how, type, m);
+ return (m);
}
static __inline struct mbuf *
m_getcl(int how, short type, int flags)
{
+ struct mbuf *m;
struct mb_args args;
args.flags = flags;
args.type = type;
- return (uma_zalloc_arg(zone_pack, &args, how));
+ m = uma_zalloc_arg(zone_pack, &args, how);
+ MBUF_PROBE4(m__getcl, how, type, flags, m);
+ return (m);
}
/*
@@ -747,6 +783,7 @@ m_cljset(struct mbuf *m, void *cl, int type)
m->m_ext.ext_flags = EXT_FLAG_EMBREF;
m->m_ext.ext_count = 1;
m->m_flags |= M_EXT;
+ MBUF_PROBE3(m__cljset, m, cl, type);
}
static __inline void
@@ -1122,6 +1159,7 @@ m_free(struct mbuf *m)
{
struct mbuf *n = m->m_next;
+ MBUF_PROBE1(m__free, m);
if ((m->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
m_tag_delete_chain(m, NULL);
if (m->m_flags & M_EXT)
diff --git a/sys/sys/osd.h b/sys/sys/osd.h
index 14316ae..820e0f4 100644
--- a/sys/sys/osd.h
+++ b/sys/sys/osd.h
@@ -59,6 +59,10 @@ int osd_register(u_int type, osd_destructor_t destructor,
void osd_deregister(u_int type, u_int slot);
int osd_set(u_int type, struct osd *osd, u_int slot, void *value);
+void *osd_reserve(u_int slot);
+int osd_set_reserved(u_int type, struct osd *osd, u_int slot, void *rsv,
+ void *value);
+void osd_free_reserved(void *rsv);
void *osd_get(u_int type, struct osd *osd, u_int slot);
void osd_del(u_int type, struct osd *osd, u_int slot);
int osd_call(u_int type, u_int method, void *obj, void *data);
@@ -71,6 +75,8 @@ void osd_exit(u_int type, struct osd *osd);
osd_deregister(OSD_THREAD, (slot))
#define osd_thread_set(td, slot, value) \
osd_set(OSD_THREAD, &(td)->td_osd, (slot), (value))
+#define osd_thread_set_reserved(td, slot, rsv, value) \
+ osd_set_reserved(OSD_THREAD, &(td)->td_osd, (slot), (rsv), (value))
#define osd_thread_get(td, slot) \
osd_get(OSD_THREAD, &(td)->td_osd, (slot))
#define osd_thread_del(td, slot) do { \
@@ -88,6 +94,8 @@ void osd_exit(u_int type, struct osd *osd);
osd_deregister(OSD_JAIL, (slot))
#define osd_jail_set(pr, slot, value) \
osd_set(OSD_JAIL, &(pr)->pr_osd, (slot), (value))
+#define osd_jail_set_reserved(pr, slot, rsv, value) \
+ osd_set_reserved(OSD_JAIL, &(pr)->pr_osd, (slot), (rsv), (value))
#define osd_jail_get(pr, slot) \
osd_get(OSD_JAIL, &(pr)->pr_osd, (slot))
#define osd_jail_del(pr, slot) \
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 9108576..987453c 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1100102 /* Master, propagated to newvers */
+#define __FreeBSD_version 1100104 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index f9ca6d9..2d1769e 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -162,6 +162,7 @@ struct pargs {
*/
struct cpuset;
struct filecaps;
+struct filemon;
struct kaioinfo;
struct kaudit_record;
struct kdtrace_proc;
@@ -253,6 +254,7 @@ struct thread {
int td_slptick; /* (t) Time at sleep. */
int td_blktick; /* (t) Time spent blocked. */
int td_swvoltick; /* (t) Time at last SW_VOL switch. */
+ int td_swinvoltick; /* (t) Time at last SW_INVOL switch. */
u_int td_cow; /* (*) Number of copy-on-write faults */
struct rusage td_ru; /* (t) rusage information. */
struct rusage_ext td_rux; /* (t) Internal rusage information. */
@@ -580,6 +582,7 @@ struct proc {
struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */
u_int p_treeflag; /* (e) P_TREE flags */
int p_pendingexits; /* (c) Count of pending thread exits. */
+ struct filemon *p_filemon; /* (c) filemon-specific data. */
/* End area that is zeroed on creation. */
#define p_endzero p_magic
diff --git a/sys/sys/racct.h b/sys/sys/racct.h
index 3075856..8d1f2fa 100644
--- a/sys/sys/racct.h
+++ b/sys/sys/racct.h
@@ -98,7 +98,7 @@ extern int racct_enable;
/*
* Resource usage can drop, as opposed to only grow. When the process
- * terminates, its resource usage is freed from the respective
+ * terminates, its resource usage is subtracted from the respective
* per-credential racct containers.
*/
#define RACCT_IS_RECLAIMABLE(X) (racct_types[X] & RACCT_RECLAIMABLE)
@@ -126,8 +126,7 @@ extern int racct_enable;
* When a process terminates, its resource usage is not automatically
* subtracted from per-credential racct containers. Instead, the resource
* usage of per-credential racct containers decays in time.
- * Resource usage can olso drop for such resource.
- * So far, the only such resource is RACCT_PCTCPU.
+ * Resource usage can also drop for such resource.
*/
#define RACCT_IS_DECAYING(X) (racct_types[X] & RACCT_DECAYING)
diff --git a/sys/sys/sleepqueue.h b/sys/sys/sleepqueue.h
index cdb7a39..d59dc7e 100644
--- a/sys/sys/sleepqueue.h
+++ b/sys/sys/sleepqueue.h
@@ -107,5 +107,11 @@ int sleepq_type(void *wchan);
void sleepq_wait(void *wchan, int pri);
int sleepq_wait_sig(void *wchan, int pri);
+#ifdef STACK
+struct sbuf;
+int sleepq_sbuf_print_stacks(struct sbuf *sb, void *wchan, int queue,
+ int *count_stacks_printed);
+#endif
+
#endif /* _KERNEL */
#endif /* !_SYS_SLEEPQUEUE_H_ */
diff --git a/sys/sys/smp.h b/sys/sys/smp.h
index 58b1754..904b9f7 100644
--- a/sys/sys/smp.h
+++ b/sys/sys/smp.h
@@ -17,9 +17,52 @@
#ifndef LOCORE
#include <sys/cpuset.h>
+#include <sys/queue.h>
/*
- * Topology of a NUMA or HTT system.
+ * Types of nodes in the topological tree.
+ */
+typedef enum {
+ /* No node has this type; can be used in topo API calls. */
+ TOPO_TYPE_DUMMY,
+ /* Processing unit aka computing unit aka logical CPU. */
+ TOPO_TYPE_PU,
+ /* Physical subdivision of a package. */
+ TOPO_TYPE_CORE,
+ /* CPU L1/L2/L3 cache. */
+ TOPO_TYPE_CACHE,
+ /* Package aka chip, equivalent to socket. */
+ TOPO_TYPE_PKG,
+ /* NUMA node. */
+ TOPO_TYPE_NODE,
+ /* Other logical or physical grouping of PUs. */
+ /* E.g. PUs on the same dye, or PUs sharing an FPU. */
+ TOPO_TYPE_GROUP,
+ /* The whole system. */
+ TOPO_TYPE_SYSTEM
+} topo_node_type;
+
+/* Hardware indenitifier of a topology component. */
+typedef unsigned int hwid_t;
+/* Logical CPU idenitifier. */
+typedef int cpuid_t;
+
+/* A node in the topology. */
+struct topo_node {
+ struct topo_node *parent;
+ TAILQ_HEAD(topo_children, topo_node) children;
+ TAILQ_ENTRY(topo_node) siblings;
+ cpuset_t cpuset;
+ topo_node_type type;
+ uintptr_t subtype;
+ hwid_t hwid;
+ cpuid_t id;
+ int nchildren;
+ int cpu_count;
+};
+
+/*
+ * Scheduling topology of a NUMA or SMP system.
*
* The top level topology is an array of pointers to groups. Each group
* contains a bitmask of cpus in its group or subgroups. It may also
@@ -52,6 +95,8 @@ typedef struct cpu_group *cpu_group_t;
#define CG_SHARE_L2 2
#define CG_SHARE_L3 3
+#define MAX_CACHE_LEVELS CG_SHARE_L3
+
/*
* Behavior modifiers for load balancing and affinity.
*/
@@ -60,10 +105,29 @@ typedef struct cpu_group *cpu_group_t;
#define CG_FLAG_THREAD (CG_FLAG_HTT | CG_FLAG_SMT) /* Any threading. */
/*
- * Convenience routines for building topologies.
+ * Convenience routines for building and traversing topologies.
*/
#ifdef SMP
+void topo_init_node(struct topo_node *node);
+void topo_init_root(struct topo_node *root);
+struct topo_node * topo_add_node_by_hwid(struct topo_node *parent, int hwid,
+ topo_node_type type, uintptr_t subtype);
+struct topo_node * topo_find_node_by_hwid(struct topo_node *parent, int hwid,
+ topo_node_type type, uintptr_t subtype);
+void topo_promote_child(struct topo_node *child);
+struct topo_node * topo_next_node(struct topo_node *top,
+ struct topo_node *node);
+struct topo_node * topo_next_nonchild_node(struct topo_node *top,
+ struct topo_node *node);
+void topo_set_pu_id(struct topo_node *node, cpuid_t id);
+int topo_analyze(struct topo_node *topo_root, int all, int *pkg_count,
+ int *cores_per_pkg, int *thrs_per_core);
+
+#define TOPO_FOREACH(i, root) \
+ for (i = root; i != NULL; i = topo_next_node(root, i))
+
struct cpu_group *smp_topo(void);
+struct cpu_group *smp_topo_alloc(u_int count);
struct cpu_group *smp_topo_none(void);
struct cpu_group *smp_topo_1level(int l1share, int l1count, int l1flags);
struct cpu_group *smp_topo_2level(int l2share, int l2count, int l1share,
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index c20b075..649ba00 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -594,7 +594,6 @@ struct sf_hdtr {
#define SF_FLAGS(rh, flags) (((rh) << 16) | (flags))
#ifdef _KERNEL
-#define SFK_COMPAT 0x00000001
#define SF_READAHEAD(flags) ((flags) >> 16)
#endif /* _KERNEL */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index fef33b8..8a32a64 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 296572 2016-03-09 19:05:11Z jhb
+ * created from FreeBSD: head/sys/kern/syscalls.master 297167 2016-03-21 21:37:33Z jhb
*/
#define SYS_syscall 0
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index 3f62141..a264838 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -1,7 +1,7 @@
# FreeBSD system call object files.
# DO NOT EDIT-- this file is automatically generated.
# $FreeBSD$
-# created from FreeBSD: head/sys/kern/syscalls.master 296572 2016-03-09 19:05:11Z jhb
+# created from FreeBSD: head/sys/kern/syscalls.master 297167 2016-03-21 21:37:33Z jhb
MIASM = \
syscall.o \
exit.o \
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index 7c1e79c..eb5eef0 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -204,6 +204,7 @@ int sysctl_handle_long(SYSCTL_HANDLER_ARGS);
int sysctl_handle_string(SYSCTL_HANDLER_ARGS);
int sysctl_handle_opaque(SYSCTL_HANDLER_ARGS);
int sysctl_handle_counter_u64(SYSCTL_HANDLER_ARGS);
+int sysctl_handle_counter_u64_array(SYSCTL_HANDLER_ARGS);
int sysctl_handle_uma_zone_max(SYSCTL_HANDLER_ARGS);
int sysctl_handle_uma_zone_cur(SYSCTL_HANDLER_ARGS);
@@ -640,11 +641,34 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
#define SYSCTL_ADD_COUNTER_U64(ctx, parent, nbr, name, access, ptr, descr) \
({ \
+ counter_u64_t *__ptr = (ptr); \
CTASSERT(((access) & CTLTYPE) == 0 || \
((access) & SYSCTL_CT_ASSERT_MASK) == CTLTYPE_U64); \
sysctl_add_oid(ctx, parent, nbr, name, \
CTLTYPE_U64 | CTLFLAG_MPSAFE | (access), \
- ptr, 0, sysctl_handle_counter_u64, "QU", __DESCR(descr)); \
+ __ptr, 0, sysctl_handle_counter_u64, "QU", __DESCR(descr)); \
+})
+
+/* Oid for an array of counter(9)s. The pointer and length must be non zero. */
+#define SYSCTL_COUNTER_U64_ARRAY(parent, nbr, name, access, ptr, len, descr) \
+ SYSCTL_OID(parent, nbr, name, \
+ CTLTYPE_OPAQUE | CTLFLAG_MPSAFE | (access), \
+ (ptr), (len), sysctl_handle_counter_u64_array, "S", descr); \
+ CTASSERT((((access) & CTLTYPE) == 0 || \
+ ((access) & SYSCTL_CT_ASSERT_MASK) == CTLTYPE_OPAQUE) && \
+ sizeof(counter_u64_t) == sizeof(*(ptr)) && \
+ sizeof(uint64_t) == sizeof(**(ptr)))
+
+#define SYSCTL_ADD_COUNTER_U64_ARRAY(ctx, parent, nbr, name, access, \
+ ptr, len, descr) \
+({ \
+ counter_u64_t *__ptr = (ptr); \
+ CTASSERT(((access) & CTLTYPE) == 0 || \
+ ((access) & SYSCTL_CT_ASSERT_MASK) == CTLTYPE_OPAQUE); \
+ sysctl_add_oid(ctx, parent, nbr, name, \
+ CTLTYPE_OPAQUE | CTLFLAG_MPSAFE | (access), \
+ __ptr, len, sysctl_handle_counter_u64_array, "S", \
+ __DESCR(descr)); \
})
/* Oid for an opaque object. Specified by a pointer and a length. */
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index e3151f6..6d2357a 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -3,7 +3,7 @@
*
* DO NOT EDIT-- this file is automatically generated.
* $FreeBSD$
- * created from FreeBSD: head/sys/kern/syscalls.master 296572 2016-03-09 19:05:11Z jhb
+ * created from FreeBSD: head/sys/kern/syscalls.master 297167 2016-03-21 21:37:33Z jhb
*/
#ifndef _SYS_SYSPROTO_H_
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 026a03c..9c6e450 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -148,10 +148,14 @@ extern char **kenvp;
extern const void *zero_region; /* address space maps to a zeroed page */
extern int unmapped_buf_allowed;
-extern int iosize_max_clamp;
-extern int devfs_iosize_max_clamp;
-#define IOSIZE_MAX (iosize_max_clamp ? INT_MAX : SSIZE_MAX)
-#define DEVFS_IOSIZE_MAX (devfs_iosize_max_clamp ? INT_MAX : SSIZE_MAX)
+
+#ifdef __LP64__
+#define IOSIZE_MAX iosize_max()
+#define DEVFS_IOSIZE_MAX devfs_iosize_max()
+#else
+#define IOSIZE_MAX SSIZE_MAX
+#define DEVFS_IOSIZE_MAX SSIZE_MAX
+#endif
/*
* General function declarations.
@@ -403,6 +407,11 @@ struct cdev;
dev_t dev2udev(struct cdev *x);
const char *devtoname(struct cdev *cdev);
+#ifdef __LP64__
+size_t devfs_iosize_max(void);
+size_t iosize_max(void);
+#endif
+
int poll_no_poll(int events);
/* XXX: Should be void nanodelay(u_int nsec); */
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 19c00de..799efe3 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -2270,8 +2270,6 @@ ffs_blkfree_cg(ump, fs, devvp, bno, size, inum, dephd)
bdwrite(bp);
}
-TASKQUEUE_DEFINE_THREAD(ffs_trim);
-
struct ffs_blkfree_trim_params {
struct task task;
struct ufsmount *ump;
@@ -2294,6 +2292,7 @@ ffs_blkfree_trim_task(ctx, pending)
ffs_blkfree_cg(tp->ump, tp->ump->um_fs, tp->devvp, tp->bno, tp->size,
tp->inum, tp->pdephd);
vn_finished_secondary_write(UFSTOVFS(tp->ump));
+ atomic_add_int(&tp->ump->um_trim_inflight, -1);
free(tp, M_TEMP);
}
@@ -2306,7 +2305,7 @@ ffs_blkfree_trim_completed(bip)
tp = bip->bio_caller2;
g_destroy_bio(bip);
TASK_INIT(&tp->task, 0, ffs_blkfree_trim_task, tp);
- taskqueue_enqueue(taskqueue_ffs_trim, &tp->task);
+ taskqueue_enqueue(tp->ump->um_trim_tq, &tp->task);
}
void
@@ -2350,6 +2349,7 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum, vtype, dephd)
* reordering, TRIM might be issued after we reuse the block
* and write some new data into it.
*/
+ atomic_add_int(&ump->um_trim_inflight, 1);
tp = malloc(sizeof(struct ffs_blkfree_trim_params), M_TEMP, M_WAITOK);
tp->ump = ump;
tp->devvp = devvp;
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 04ea39c..bedc8e1 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -1937,9 +1937,9 @@ softdep_waitidle(struct mount *mp, int flags __unused)
vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_FSYNC(devvp, MNT_WAIT, td);
VOP_UNLOCK(devvp, 0);
+ ACQUIRE_LOCK(ump);
if (error != 0)
break;
- ACQUIRE_LOCK(ump);
}
ump->softdep_req = 0;
if (i == SU_WAITIDLE_RETRIES && error == 0 && ump->softdep_deps != 0) {
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index a82ef61..b89dc33 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/namei.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/taskqueue.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/mount.h>
@@ -1005,6 +1006,12 @@ ffs_mountfs(devvp, mp, td)
mp->mnt_stat.f_mntonname);
ump->um_candelete = 0;
}
+ if (ump->um_candelete) {
+ ump->um_trim_tq = taskqueue_create("trim", M_WAITOK,
+ taskqueue_thread_enqueue, &ump->um_trim_tq);
+ taskqueue_start_threads(&ump->um_trim_tq, 1, PVFS,
+ "%s trim", mp->mnt_stat.f_mntonname);
+ }
}
ump->um_mountp = mp;
@@ -1260,6 +1267,12 @@ ffs_unmount(mp, mntflags)
}
if (susp)
vfs_write_resume(mp, VR_START_WRITE);
+ if (ump->um_trim_tq != NULL) {
+ while (ump->um_trim_inflight != 0)
+ pause("ufsutr", hz);
+ taskqueue_drain_all(ump->um_trim_tq);
+ taskqueue_free(ump->um_trim_tq);
+ }
DROP_GIANT();
g_topology_lock();
if (ump->um_fsckpid > 0) {
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
index 209d93e..b521a42 100644
--- a/sys/ufs/ufs/ufs_extattr.c
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -597,8 +597,6 @@ ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
attribute = malloc(sizeof(struct ufs_extattr_list_entry),
M_UFS_EXTATTR, M_WAITOK);
- if (attribute == NULL)
- return (ENOMEM);
if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
error = EOPNOTSUPP;
diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h
index 7148b76..838c1e3 100644
--- a/sys/ufs/ufs/ufsmount.h
+++ b/sys/ufs/ufs/ufsmount.h
@@ -50,6 +50,7 @@ MALLOC_DECLARE(M_UFSMNT);
struct buf;
struct inode;
struct nameidata;
+struct taskqueue;
struct timeval;
struct ucred;
struct uio;
@@ -85,11 +86,15 @@ struct ufsmount {
int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */
int um_candelete; /* devvp supports TRIM */
int um_writesuspended; /* suspension in progress */
- int (*um_balloc)(struct vnode *, off_t, int, struct ucred *, int, struct buf **);
+ u_int um_trim_inflight;
+ struct taskqueue *um_trim_tq;
+ int (*um_balloc)(struct vnode *, off_t, int, struct ucred *,
+ int, struct buf **);
int (*um_blkatoff)(struct vnode *, off_t, char **, struct buf **);
int (*um_truncate)(struct vnode *, off_t, int, struct ucred *);
int (*um_update)(struct vnode *, int);
- int (*um_valloc)(struct vnode *, int, struct ucred *, struct vnode **);
+ int (*um_valloc)(struct vnode *, int, struct ucred *,
+ struct vnode **);
int (*um_vfree)(struct vnode *, ino_t, int);
void (*um_ifree)(struct ufsmount *, struct inode *);
int (*um_rdonly)(struct inode *);
diff --git a/sys/x86/include/apicreg.h b/sys/x86/include/apicreg.h
index 35630c7..d3cfaaf 100644
--- a/sys/x86/include/apicreg.h
+++ b/sys/x86/include/apicreg.h
@@ -399,10 +399,11 @@ typedef struct IOAPIC ioapic_t;
#define APIC_LVTT_VECTOR 0x000000ff
#define APIC_LVTT_DS 0x00001000
#define APIC_LVTT_M 0x00010000
-#define APIC_LVTT_TM 0x00020000
+#define APIC_LVTT_TM 0x00060000
# define APIC_LVTT_TM_ONE_SHOT 0x00000000
# define APIC_LVTT_TM_PERIODIC 0x00020000
-
+# define APIC_LVTT_TM_TSCDLT 0x00040000
+# define APIC_LVTT_TM_RSRV 0x00060000
/* APIC timer current count */
#define APIC_TIMER_MAX_COUNT 0xffffffff
diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
index 5f2c010..c2d2c59 100644
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -457,6 +457,7 @@
#define MSR_DRAM_ENERGY_STATUS 0x619
#define MSR_PP0_ENERGY_STATUS 0x639
#define MSR_PP1_ENERGY_STATUS 0x641
+#define MSR_TSC_DEADLINE 0x6e0 /* Writes are not serializing */
/*
* VMX MSRs
@@ -478,7 +479,8 @@
#define MSR_VMX_TRUE_ENTRY_CTLS 0x490
/*
- * X2APIC MSRs
+ * X2APIC MSRs.
+ * Writes are not serializing.
*/
#define MSR_APIC_000 0x800
#define MSR_APIC_ID 0x802
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index c349913..46ce1a0 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -86,6 +86,13 @@ struct fpreg;
struct dbreg;
struct dumperinfo;
+/*
+ * The interface type of the interrupt handler entry point cannot be
+ * expressed in C. Use simplest non-variadic function type as an
+ * approximation.
+ */
+typedef void alias_for_inthand_t(void);
+
void *alloc_fpusave(int flags);
void busdma_swi(void);
bool cpu_mwait_usable(void);
diff --git a/sys/i386/i386/autoconf.c b/sys/x86/x86/autoconf.c
index 029ed2e..813fe4c 100644
--- a/sys/i386/i386/autoconf.c
+++ b/sys/x86/x86/autoconf.c
@@ -65,7 +65,9 @@ __FBSDID("$FreeBSD$");
#include <net/ethernet.h>
#include <netinet/in.h>
+#ifdef PC98
#include <machine/bootinfo.h>
+#endif
#include <machine/md_var.h>
#ifdef DEV_ISA
@@ -92,7 +94,7 @@ configure_first(dummy)
void *dummy;
{
- /* nexus0 is the top of the i386 device tree */
+ /* nexus0 is the top of the x86 device tree */
device_add_child(root_bus, "nexus", 0);
}
@@ -101,13 +103,6 @@ configure(dummy)
void *dummy;
{
- /*
- * Enable interrupts on the processor. The interrupts are still
- * disabled in the interrupt controllers until interrupt handlers
- * are registered.
- */
- enable_intr();
-
/* initialize new bus architecture */
root_bus_configure();
diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c
index 35ec992..6678887 100644
--- a/sys/x86/x86/intr_machdep.c
+++ b/sys/x86/x86/intr_machdep.c
@@ -393,6 +393,21 @@ intr_init(void *dummy __unused)
}
SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
+static void
+intr_init_final(void *dummy __unused)
+{
+
+ /*
+ * Enable interrupts on the BSP after all of the interrupt
+ * controllers are initialized. Device interrupts are still
+ * disabled in the interrupt controllers until interrupt
+ * handlers are registered. Interrupts are enabled on each AP
+ * after their first context switch.
+ */
+ enable_intr();
+}
+SYSINIT(intr_init_final, SI_SUB_INTR, SI_ORDER_ANY, intr_init_final, NULL);
+
#ifndef DEV_ATPIC
/* Initialize the two 8259A's to a known-good shutdown state. */
void
diff --git a/sys/x86/x86/io_apic.c b/sys/x86/x86/io_apic.c
index 44609e6..1a2cc3c 100644
--- a/sys/x86/x86/io_apic.c
+++ b/sys/x86/x86/io_apic.c
@@ -987,14 +987,6 @@ apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length)
{
int error;
-#ifdef PAE
- /*
- * Resources use long's to track resources, so we can't
- * include memory regions above 4GB.
- */
- if (base >= ~0ul)
- return;
-#endif
error = bus_set_resource(dev, SYS_RES_MEMORY, rid, base, length);
if (error)
panic("apic_add_resource: resource %d failed set with %d", rid,
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 7fc6278..82efae3 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <vm/pmap.h>
#include <x86/apicreg.h>
+#include <machine/clock.h>
#include <machine/cpufunc.h>
#include <machine/cputypes.h>
#include <machine/frame.h>
@@ -94,6 +95,13 @@ CTASSERT(IPI_STOP < APIC_SPURIOUS_INT);
#define IRQ_DTRACE_RET (NUM_IO_INTS + 3)
#define IRQ_EVTCHN (NUM_IO_INTS + 4)
+enum lat_timer_mode {
+ LAT_MODE_UNDEF = 0,
+ LAT_MODE_PERIODIC = 1,
+ LAT_MODE_ONESHOT = 2,
+ LAT_MODE_DEADLINE = 3,
+};
+
/*
* Support for local APICs. Local APICs manage interrupts on each
* individual processor as opposed to I/O APICs which receive interrupts
@@ -119,9 +127,10 @@ struct lapic {
u_int la_cluster_id:2;
u_int la_present:1;
u_long *la_timer_count;
- u_long la_timer_period;
- u_int la_timer_mode;
- uint32_t lvt_timer_cache;
+ uint64_t la_timer_period;
+ enum lat_timer_mode la_timer_mode;
+ uint32_t lvt_timer_base;
+ uint32_t lvt_timer_last;
/* Include IDT_SYSCALL to make indexing easier. */
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
@@ -160,13 +169,19 @@ volatile char *lapic_map;
vm_paddr_t lapic_paddr;
int x2apic_mode;
int lapic_eoi_suppression;
+static int lapic_timer_tsc_deadline;
static u_long lapic_timer_divisor;
static struct eventtimer lapic_et;
+#ifdef SMP
+static uint64_t lapic_ipi_wait_mult;
+#endif
SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
SYSCTL_INT(_hw_apic, OID_AUTO, x2apic_mode, CTLFLAG_RD, &x2apic_mode, 0, "");
SYSCTL_INT(_hw_apic, OID_AUTO, eoi_suppression, CTLFLAG_RD,
&lapic_eoi_suppression, 0, "");
+SYSCTL_INT(_hw_apic, OID_AUTO, timer_tsc_deadline, CTLFLAG_RD,
+ &lapic_timer_tsc_deadline, 0, "");
static uint32_t
lapic_read32(enum LAPIC_REGISTERS reg)
@@ -256,10 +271,10 @@ native_lapic_enable_x2apic(void)
static void lapic_enable(void);
static void lapic_resume(struct pic *pic, bool suspend_cancelled);
-static void lapic_timer_oneshot(struct lapic *,
- u_int count, int enable_int);
-static void lapic_timer_periodic(struct lapic *,
- u_int count, int enable_int);
+static void lapic_timer_oneshot(struct lapic *);
+static void lapic_timer_oneshot_nointr(struct lapic *, uint32_t);
+static void lapic_timer_periodic(struct lapic *);
+static void lapic_timer_deadline(struct lapic *);
static void lapic_timer_stop(struct lapic *);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
@@ -391,6 +406,9 @@ lvt_mode(struct lapic *la, u_int pin, uint32_t value)
static void
native_lapic_init(vm_paddr_t addr)
{
+#ifdef SMP
+ uint64_t r, r1, r2, rx;
+#endif
uint32_t ver;
u_int regs[4];
int i, arat;
@@ -450,7 +468,14 @@ native_lapic_init(vm_paddr_t addr)
if (!arat) {
lapic_et.et_flags |= ET_FLAGS_C3STOP;
lapic_et.et_quality -= 200;
+ } else if ((cpu_feature & CPUID_TSC) != 0 &&
+ (cpu_feature2 & CPUID2_TSCDLT) != 0 &&
+ tsc_is_invariant && tsc_freq != 0) {
+ lapic_timer_tsc_deadline = 1;
+ TUNABLE_INT_FETCH("hw.lapic_tsc_deadline",
+ &lapic_timer_tsc_deadline);
}
+
lapic_et.et_frequency = 0;
/* We don't know frequency yet, so trying to guess. */
lapic_et.et_min_period = 0x00001000LL;
@@ -484,6 +509,38 @@ native_lapic_init(vm_paddr_t addr)
TUNABLE_INT_FETCH("hw.lapic_eoi_suppression",
&lapic_eoi_suppression);
}
+
+#ifdef SMP
+#define LOOPS 1000000
+ /*
+ * Calibrate the busy loop waiting for IPI ack in xAPIC mode.
+ * lapic_ipi_wait_mult contains the number of iterations which
+ * approximately delay execution for 1 microsecond (the
+ * argument to native_lapic_ipi_wait() is in microseconds).
+ *
+ * We assume that TSC is present and already measured.
+ * Possible TSC frequency jumps are irrelevant to the
+ * calibration loop below, the CPU clock management code is
+ * not yet started, and we do not enter sleep states.
+ */
+ KASSERT((cpu_feature & CPUID_TSC) != 0 && tsc_freq != 0,
+ ("TSC not initialized"));
+ r = rdtsc();
+ for (rx = 0; rx < LOOPS; rx++) {
+ (void)lapic_read_icr_lo();
+ ia32_pause();
+ }
+ r = rdtsc() - r;
+ r1 = tsc_freq * LOOPS;
+ r2 = r * 1000000;
+ lapic_ipi_wait_mult = r1 >= r2 ? r1 / r2 : 1;
+ if (bootverbose) {
+ printf("LAPIC: ipi_wait() us multiplier %ju (r %ju tsc %ju)\n",
+ (uintmax_t)lapic_ipi_wait_mult, (uintmax_t)r,
+ (uintmax_t)tsc_freq);
+ }
+#undef LOOPS
+#endif /* SMP */
}
/*
@@ -604,23 +661,35 @@ native_lapic_setup(int boot)
}
/* Program timer LVT and setup handler. */
- la->lvt_timer_cache = lvt_mode(la, APIC_LVT_TIMER,
+ la->lvt_timer_base = lvt_mode(la, APIC_LVT_TIMER,
lapic_read32(LAPIC_LVT_TIMER));
- lapic_write32(LAPIC_LVT_TIMER, la->lvt_timer_cache);
+ la->lvt_timer_last = la->lvt_timer_base;
+ lapic_write32(LAPIC_LVT_TIMER, la->lvt_timer_base);
if (boot) {
snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
intrcnt_add(buf, &la->la_timer_count);
}
/* Setup the timer if configured. */
- if (la->la_timer_mode != 0) {
+ if (la->la_timer_mode != LAT_MODE_UNDEF) {
KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor",
lapic_id()));
- lapic_timer_set_divisor(lapic_timer_divisor);
- if (la->la_timer_mode == 1)
- lapic_timer_periodic(la, la->la_timer_period, 1);
- else
- lapic_timer_oneshot(la, la->la_timer_period, 1);
+ switch (la->la_timer_mode) {
+ case LAT_MODE_PERIODIC:
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ lapic_timer_periodic(la);
+ break;
+ case LAT_MODE_ONESHOT:
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ lapic_timer_oneshot(la);
+ break;
+ case LAT_MODE_DEADLINE:
+ lapic_timer_deadline(la);
+ break;
+ default:
+ panic("corrupted la_timer_mode %p %d", la,
+ la->la_timer_mode);
+ }
}
/* Program error LVT and clear any existing errors. */
@@ -722,46 +791,75 @@ native_lapic_disable_pmc(void)
#endif
}
+static void
+lapic_calibrate_initcount(struct eventtimer *et, struct lapic *la)
+{
+ u_long value;
+
+ /* Start off with a divisor of 2 (power on reset default). */
+ lapic_timer_divisor = 2;
+ /* Try to calibrate the local APIC timer. */
+ do {
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT);
+ DELAY(1000000);
+ value = APIC_TIMER_MAX_COUNT - lapic_read32(LAPIC_CCR_TIMER);
+ if (value != APIC_TIMER_MAX_COUNT)
+ break;
+ lapic_timer_divisor <<= 1;
+ } while (lapic_timer_divisor <= 128);
+ if (lapic_timer_divisor > 128)
+ panic("lapic: Divisor too big");
+ if (bootverbose) {
+ printf("lapic: Divisor %lu, Frequency %lu Hz\n",
+ lapic_timer_divisor, value);
+ }
+ et->et_frequency = value;
+}
+
+static void
+lapic_calibrate_deadline(struct eventtimer *et, struct lapic *la __unused)
+{
+
+ et->et_frequency = tsc_freq;
+ if (bootverbose) {
+ printf("lapic: deadline tsc mode, Frequency %ju Hz\n",
+ (uintmax_t)et->et_frequency);
+ }
+}
+
static int
lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
{
struct lapic *la;
- u_long value;
la = &lapics[PCPU_GET(apic_id)];
if (et->et_frequency == 0) {
- /* Start off with a divisor of 2 (power on reset default). */
- lapic_timer_divisor = 2;
- /* Try to calibrate the local APIC timer. */
- do {
- lapic_timer_set_divisor(lapic_timer_divisor);
- lapic_timer_oneshot(la, APIC_TIMER_MAX_COUNT, 0);
- DELAY(1000000);
- value = APIC_TIMER_MAX_COUNT -
- lapic_read32(LAPIC_CCR_TIMER);
- if (value != APIC_TIMER_MAX_COUNT)
- break;
- lapic_timer_divisor <<= 1;
- } while (lapic_timer_divisor <= 128);
- if (lapic_timer_divisor > 128)
- panic("lapic: Divisor too big");
- if (bootverbose)
- printf("lapic: Divisor %lu, Frequency %lu Hz\n",
- lapic_timer_divisor, value);
- et->et_frequency = value;
+ if (lapic_timer_tsc_deadline)
+ lapic_calibrate_deadline(et, la);
+ else
+ lapic_calibrate_initcount(et, la);
et->et_min_period = (0x00000002LLU << 32) / et->et_frequency;
et->et_max_period = (0xfffffffeLLU << 32) / et->et_frequency;
}
- if (la->la_timer_mode == 0)
- lapic_timer_set_divisor(lapic_timer_divisor);
if (period != 0) {
- la->la_timer_mode = 1;
- la->la_timer_period = ((uint32_t)et->et_frequency * period) >> 32;
- lapic_timer_periodic(la, la->la_timer_period, 1);
+ if (la->la_timer_mode == LAT_MODE_UNDEF)
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ la->la_timer_mode = LAT_MODE_PERIODIC;
+ la->la_timer_period = ((uint32_t)et->et_frequency * period) >>
+ 32;
+ lapic_timer_periodic(la);
+ } else if (lapic_timer_tsc_deadline) {
+ la->la_timer_mode = LAT_MODE_DEADLINE;
+ la->la_timer_period = (et->et_frequency * first) >> 32;
+ lapic_timer_deadline(la);
} else {
- la->la_timer_mode = 2;
- la->la_timer_period = ((uint32_t)et->et_frequency * first) >> 32;
- lapic_timer_oneshot(la, la->la_timer_period, 1);
+ if (la->la_timer_mode == LAT_MODE_UNDEF)
+ lapic_timer_set_divisor(lapic_timer_divisor);
+ la->la_timer_mode = LAT_MODE_ONESHOT;
+ la->la_timer_period = ((uint32_t)et->et_frequency * first) >>
+ 32;
+ lapic_timer_oneshot(la);
}
return (0);
}
@@ -769,10 +867,11 @@ lapic_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
static int
lapic_et_stop(struct eventtimer *et)
{
- struct lapic *la = &lapics[PCPU_GET(apic_id)];
+ struct lapic *la;
- la->la_timer_mode = 0;
+ la = &lapics[PCPU_GET(apic_id)];
lapic_timer_stop(la);
+ la->la_timer_mode = LAT_MODE_UNDEF;
return (0);
}
@@ -1071,42 +1170,76 @@ lapic_timer_set_divisor(u_int divisor)
}
static void
-lapic_timer_oneshot(struct lapic *la, u_int count, int enable_int)
+lapic_timer_oneshot(struct lapic *la)
{
uint32_t value;
- value = la->lvt_timer_cache;
- value &= ~APIC_LVTT_TM;
+ value = la->lvt_timer_base;
+ value &= ~(APIC_LVTT_TM | APIC_LVT_M);
value |= APIC_LVTT_TM_ONE_SHOT;
- if (enable_int)
- value &= ~APIC_LVT_M;
+ la->lvt_timer_last = value;
lapic_write32(LAPIC_LVT_TIMER, value);
- lapic_write32(LAPIC_ICR_TIMER, count);
+ lapic_write32(LAPIC_ICR_TIMER, la->la_timer_period);
}
static void
-lapic_timer_periodic(struct lapic *la, u_int count, int enable_int)
+lapic_timer_oneshot_nointr(struct lapic *la, uint32_t count)
{
uint32_t value;
- value = la->lvt_timer_cache;
+ value = la->lvt_timer_base;
value &= ~APIC_LVTT_TM;
- value |= APIC_LVTT_TM_PERIODIC;
- if (enable_int)
- value &= ~APIC_LVT_M;
+ value |= APIC_LVTT_TM_ONE_SHOT | APIC_LVT_M;
+ la->lvt_timer_last = value;
lapic_write32(LAPIC_LVT_TIMER, value);
lapic_write32(LAPIC_ICR_TIMER, count);
}
static void
-lapic_timer_stop(struct lapic *la)
+lapic_timer_periodic(struct lapic *la)
{
uint32_t value;
- value = la->lvt_timer_cache;
- value &= ~APIC_LVTT_TM;
- value |= APIC_LVT_M;
+ value = la->lvt_timer_base;
+ value &= ~(APIC_LVTT_TM | APIC_LVT_M);
+ value |= APIC_LVTT_TM_PERIODIC;
+ la->lvt_timer_last = value;
lapic_write32(LAPIC_LVT_TIMER, value);
+ lapic_write32(LAPIC_ICR_TIMER, la->la_timer_period);
+}
+
+static void
+lapic_timer_deadline(struct lapic *la)
+{
+ uint32_t value;
+
+ value = la->lvt_timer_base;
+ value &= ~(APIC_LVTT_TM | APIC_LVT_M);
+ value |= APIC_LVTT_TM_TSCDLT;
+ if (value != la->lvt_timer_last) {
+ la->lvt_timer_last = value;
+ lapic_write32_nofence(LAPIC_LVT_TIMER, value);
+ if (!x2apic_mode)
+ mfence();
+ }
+ wrmsr(MSR_TSC_DEADLINE, la->la_timer_period + rdtsc());
+}
+
+static void
+lapic_timer_stop(struct lapic *la)
+{
+ uint32_t value;
+
+ if (la->la_timer_mode == LAT_MODE_DEADLINE) {
+ wrmsr(MSR_TSC_DEADLINE, 0);
+ mfence();
+ } else {
+ value = la->lvt_timer_base;
+ value &= ~APIC_LVTT_TM;
+ value |= APIC_LVT_M;
+ la->lvt_timer_last = value;
+ lapic_write32(LAPIC_LVT_TIMER, value);
+ }
}
void
@@ -1621,31 +1754,25 @@ SYSINIT(apic_setup_io, SI_SUB_INTR, SI_ORDER_THIRD, apic_setup_io, NULL);
* private to the MD code. The public interface for the rest of the
* kernel is defined in mp_machdep.c.
*/
+
+/*
+ * Wait delay microseconds for IPI to be sent. If delay is -1, we
+ * wait forever.
+ */
static int
native_lapic_ipi_wait(int delay)
{
- int x;
+ uint64_t rx;
/* LAPIC_ICR.APIC_DELSTAT_MASK is undefined in x2APIC mode */
if (x2apic_mode)
return (1);
- /*
- * Wait delay microseconds for IPI to be sent. If delay is
- * -1, we wait forever.
- */
- if (delay == -1) {
- while ((lapic_read_icr_lo() & APIC_DELSTAT_MASK) !=
- APIC_DELSTAT_IDLE)
- ia32_pause();
- return (1);
- }
-
- for (x = 0; x < delay; x += 5) {
+ for (rx = 0; delay == -1 || rx < lapic_ipi_wait_mult * delay; rx++) {
if ((lapic_read_icr_lo() & APIC_DELSTAT_MASK) ==
APIC_DELSTAT_IDLE)
return (1);
- DELAY(5);
+ ia32_pause();
}
return (0);
}
diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c
index 9594ff3..90051c8 100644
--- a/sys/x86/x86/mp_x86.c
+++ b/sys/x86/x86/mp_x86.c
@@ -133,19 +133,28 @@ volatile int aps_ready = 0;
* the APs.
*/
struct cpu_info cpu_info[MAX_APIC_ID + 1];
-int cpu_apic_ids[MAXCPU];
int apic_cpuids[MAX_APIC_ID + 1];
+int cpu_apic_ids[MAXCPU];
/* Holds pending bitmap based IPIs per CPU */
volatile u_int cpu_ipi_pending[MAXCPU];
-int cpu_logical; /* logical cpus per core */
-int cpu_cores; /* cores per package */
-
static void release_aps(void *dummy);
-static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */
static int hyperthreading_allowed = 1;
+SYSCTL_INT(_machdep, OID_AUTO, hyperthreading_allowed, CTLFLAG_RDTUN,
+ &hyperthreading_allowed, 0, "Use Intel HTT logical CPUs");
+
+static struct topo_node topo_root;
+
+static int pkg_id_shift;
+static int core_id_shift;
+static int disabled_cpus;
+
+struct cache_info {
+ int id_shift;
+ int present;
+} static caches[MAX_CACHE_LEVELS];
void
mem_range_AP_init(void)
@@ -155,60 +164,125 @@ mem_range_AP_init(void)
mem_range_softc.mr_op->initAP(&mem_range_softc);
}
-static void
-topo_probe_amd(void)
+/*
+ * Round up to the next power of two, if necessary, and then
+ * take log2.
+ * Returns -1 if argument is zero.
+ */
+static __inline int
+mask_width(u_int x)
{
- int core_id_bits;
- int id;
- /* AMD processors do not support HTT. */
- cpu_logical = 1;
+ return (fls(x << (1 - powerof2(x))) - 1);
+}
- if ((amd_feature2 & AMDID2_CMP) == 0) {
- cpu_cores = 1;
- return;
- }
+static int
+add_deterministic_cache(int type, int level, int share_count)
+{
- core_id_bits = (cpu_procinfo2 & AMDID_COREID_SIZE) >>
- AMDID_COREID_SIZE_SHIFT;
- if (core_id_bits == 0) {
- cpu_cores = (cpu_procinfo2 & AMDID_CMP_CORES) + 1;
- return;
+ if (type == 0)
+ return (0);
+ if (type > 3) {
+ printf("unexpected cache type %d\n", type);
+ return (1);
+ }
+ if (type == 2) /* ignore instruction cache */
+ return (1);
+ if (level == 0 || level > MAX_CACHE_LEVELS) {
+ printf("unexpected cache level %d\n", type);
+ return (1);
}
- /* Fam 10h and newer should get here. */
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> core_id_bits) != (boot_cpu_id >> core_id_bits))
- continue;
- cpu_cores++;
+ if (caches[level - 1].present) {
+ printf("WARNING: multiple entries for L%u data cache\n", level);
+ printf("%u => %u\n", caches[level - 1].id_shift,
+ mask_width(share_count));
+ }
+ caches[level - 1].id_shift = mask_width(share_count);
+ caches[level - 1].present = 1;
+
+ if (caches[level - 1].id_shift > pkg_id_shift) {
+ printf("WARNING: L%u data cache covers more "
+ "APIC IDs than a package\n", level);
+ printf("%u > %u\n", caches[level - 1].id_shift, pkg_id_shift);
+ caches[level - 1].id_shift = pkg_id_shift;
}
+ if (caches[level - 1].id_shift < core_id_shift) {
+ printf("WARNING: L%u data cache covers less "
+ "APIC IDs than a core\n", level);
+ printf("%u < %u\n", caches[level - 1].id_shift, core_id_shift);
+ caches[level - 1].id_shift = core_id_shift;
+ }
+
+ return (1);
}
-/*
- * Round up to the next power of two, if necessary, and then
- * take log2.
- * Returns -1 if argument is zero.
- */
-static __inline int
-mask_width(u_int x)
+static void
+topo_probe_amd(void)
{
+ u_int p[4];
+ int level;
+ int share_count;
+ int type;
+ int i;
- return (fls(x << (1 - powerof2(x))) - 1);
+ /* No multi-core capability. */
+ if ((amd_feature2 & AMDID2_CMP) == 0)
+ return;
+
+ /* For families 10h and newer. */
+ pkg_id_shift = (cpu_procinfo2 & AMDID_COREID_SIZE) >>
+ AMDID_COREID_SIZE_SHIFT;
+
+ /* For 0Fh family. */
+ if (pkg_id_shift == 0)
+ pkg_id_shift =
+ mask_width((cpu_procinfo2 & AMDID_CMP_CORES) + 1);
+
+ if ((amd_feature2 & AMDID2_TOPOLOGY) != 0) {
+ for (i = 0; ; i++) {
+ cpuid_count(0x8000001d, i, p);
+ type = p[0] & 0x1f;
+ level = (p[0] >> 5) & 0x7;
+ share_count = 1 + ((p[0] >> 14) & 0xfff);
+
+ if (!add_deterministic_cache(type, level, share_count))
+ break;
+ }
+ } else {
+ if (cpu_exthigh >= 0x80000005) {
+ cpuid_count(0x80000005, 0, p);
+ if (((p[2] >> 24) & 0xff) != 0) {
+ caches[0].id_shift = 0;
+ caches[0].present = 1;
+ }
+ }
+ if (cpu_exthigh >= 0x80000006) {
+ cpuid_count(0x80000006, 0, p);
+ if (((p[2] >> 16) & 0xffff) != 0) {
+ caches[1].id_shift = 0;
+ caches[1].present = 1;
+ }
+ if (((p[3] >> 18) & 0x3fff) != 0) {
+
+ /*
+ * TODO: Account for dual-node processors
+ * where each node within a package has its own
+ * L3 cache.
+ */
+ caches[2].id_shift = pkg_id_shift;
+ caches[2].present = 1;
+ }
+ }
+ }
}
static void
-topo_probe_0x4(void)
+topo_probe_intel_0x4(void)
{
u_int p[4];
- int pkg_id_bits;
- int core_id_bits;
int max_cores;
int max_logical;
- int id;
/* Both zero and one here mean one logical processor per package. */
max_logical = (cpu_feature & CPUID_HTT) != 0 ?
@@ -216,180 +290,432 @@ topo_probe_0x4(void)
if (max_logical <= 1)
return;
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP. Further, we count number of
- * logical processors that belong to the same core
- * as BSP thus deducing number of threads per core.
- */
if (cpu_high >= 0x4) {
cpuid_count(0x04, 0, p);
max_cores = ((p[0] >> 26) & 0x3f) + 1;
} else
max_cores = 1;
- core_id_bits = mask_width(max_logical/max_cores);
- if (core_id_bits < 0)
- return;
- pkg_id_bits = core_id_bits + mask_width(max_cores);
-
- for (id = 0; id <= MAX_APIC_ID; id++) {
- /* Check logical CPU availability. */
- if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled)
- continue;
- /* Check if logical CPU has the same package ID. */
- if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits))
- continue;
- cpu_cores++;
- /* Check if logical CPU has the same package and core IDs. */
- if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits))
- cpu_logical++;
- }
-
- KASSERT(cpu_cores >= 1 && cpu_logical >= 1,
- ("topo_probe_0x4 couldn't find BSP"));
- cpu_cores /= cpu_logical;
- hyperthreading_cpus = cpu_logical;
+ core_id_shift = mask_width(max_logical/max_cores);
+ KASSERT(core_id_shift >= 0,
+ ("intel topo: max_cores > max_logical\n"));
+ pkg_id_shift = core_id_shift + mask_width(max_cores);
}
static void
-topo_probe_0xb(void)
+topo_probe_intel_0xb(void)
{
u_int p[4];
int bits;
- int cnt;
- int i;
- int logical;
int type;
- int x;
+ int i;
+
+ /* Fall back if CPU leaf 11 doesn't really exist. */
+ cpuid_count(0x0b, 0, p);
+ if (p[1] == 0) {
+ topo_probe_intel_0x4();
+ return;
+ }
/* We only support three levels for now. */
- for (i = 0; i < 3; i++) {
+ for (i = 0; ; i++) {
cpuid_count(0x0b, i, p);
- /* Fall back if CPU leaf 11 doesn't really exist. */
- if (i == 0 && p[1] == 0) {
- topo_probe_0x4();
- return;
- }
-
bits = p[0] & 0x1f;
- logical = p[1] &= 0xffff;
type = (p[2] >> 8) & 0xff;
- if (type == 0 || logical == 0)
+
+ if (type == 0)
break;
- /*
- * Because of uniformity assumption we examine only
- * those logical processors that belong to the same
- * package as BSP.
- */
- for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
- if (!cpu_info[x].cpu_present ||
- cpu_info[x].cpu_disabled)
- continue;
- if (x >> bits == boot_cpu_id >> bits)
- cnt++;
- }
+
+ /* TODO: check for duplicate (re-)assignment */
if (type == CPUID_TYPE_SMT)
- cpu_logical = cnt;
+ core_id_shift = bits;
else if (type == CPUID_TYPE_CORE)
- cpu_cores = cnt;
+ pkg_id_shift = bits;
+ else
+ printf("unknown CPU level type %d\n", type);
+ }
+
+ if (pkg_id_shift < core_id_shift) {
+ printf("WARNING: core covers more APIC IDs than a package\n");
+ core_id_shift = pkg_id_shift;
}
- if (cpu_logical == 0)
- cpu_logical = 1;
- cpu_cores /= cpu_logical;
+}
+
+static void
+topo_probe_intel_caches(void)
+{
+ u_int p[4];
+ int level;
+ int share_count;
+ int type;
+ int i;
+
+ if (cpu_high < 0x4) {
+ /*
+ * Available cache level and sizes can be determined
+ * via CPUID leaf 2, but that requires a huge table of hardcoded
+ * values, so for now just assume L1 and L2 caches potentially
+ * shared only by HTT processing units, if HTT is present.
+ */
+ caches[0].id_shift = pkg_id_shift;
+ caches[0].present = 1;
+ caches[1].id_shift = pkg_id_shift;
+ caches[1].present = 1;
+ return;
+ }
+
+ for (i = 0; ; i++) {
+ cpuid_count(0x4, i, p);
+ type = p[0] & 0x1f;
+ level = (p[0] >> 5) & 0x7;
+ share_count = 1 + ((p[0] >> 14) & 0xfff);
+
+ if (!add_deterministic_cache(type, level, share_count))
+ break;
+ }
+}
+
+static void
+topo_probe_intel(void)
+{
+
+ /*
+ * See Intel(R) 64 Architecture Processor
+ * Topology Enumeration article for details.
+ *
+ * Note that 0x1 <= cpu_high < 4 case should be
+ * compatible with topo_probe_intel_0x4() logic when
+ * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
+ * or it should trigger the fallback otherwise.
+ */
+ if (cpu_high >= 0xb)
+ topo_probe_intel_0xb();
+ else if (cpu_high >= 0x1)
+ topo_probe_intel_0x4();
+
+ topo_probe_intel_caches();
}
/*
- * Both topology discovery code and code that consumes topology
- * information assume top-down uniformity of the topology.
- * That is, all physical packages must be identical and each
- * core in a package must have the same number of threads.
* Topology information is queried only on BSP, on which this
* code runs and for which it can query CPUID information.
- * Then topology is extrapolated on all packages using the
- * uniformity assumption.
+ * Then topology is extrapolated on all packages using an
+ * assumption that APIC ID to hardware component ID mapping is
+ * homogenious.
+ * That doesn't necesserily imply that the topology is uniform.
*/
void
topo_probe(void)
{
static int cpu_topo_probed = 0;
+ struct x86_topo_layer {
+ int type;
+ int subtype;
+ int id_shift;
+ } topo_layers[MAX_CACHE_LEVELS + 3];
+ struct topo_node *parent;
+ struct topo_node *node;
+ int layer;
+ int nlayers;
+ int node_id;
+ int i;
if (cpu_topo_probed)
return;
CPU_ZERO(&logical_cpus_mask);
+
if (mp_ncpus <= 1)
- cpu_cores = cpu_logical = 1;
+ ; /* nothing */
else if (cpu_vendor_id == CPU_VENDOR_AMD)
topo_probe_amd();
- else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
- /*
- * See Intel(R) 64 Architecture Processor
- * Topology Enumeration article for details.
- *
- * Note that 0x1 <= cpu_high < 4 case should be
- * compatible with topo_probe_0x4() logic when
- * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
- * or it should trigger the fallback otherwise.
- */
- if (cpu_high >= 0xb)
- topo_probe_0xb();
- else if (cpu_high >= 0x1)
- topo_probe_0x4();
- }
+ else if (cpu_vendor_id == CPU_VENDOR_INTEL)
+ topo_probe_intel();
+
+ KASSERT(pkg_id_shift >= core_id_shift,
+ ("bug in APIC topology discovery"));
+
+ nlayers = 0;
+ bzero(topo_layers, sizeof(topo_layers));
+
+ topo_layers[nlayers].type = TOPO_TYPE_PKG;
+ topo_layers[nlayers].id_shift = pkg_id_shift;
+ if (bootverbose)
+ printf("Package ID shift: %u\n", topo_layers[nlayers].id_shift);
+ nlayers++;
/*
- * Fallback: assume each logical CPU is in separate
- * physical package. That is, no multi-core, no SMT.
+ * Consider all caches to be within a package/chip
+ * and "in front" of all sub-components like
+ * cores and hardware threads.
*/
- if (cpu_cores == 0 || cpu_logical == 0)
- cpu_cores = cpu_logical = 1;
+ for (i = MAX_CACHE_LEVELS - 1; i >= 0; --i) {
+ if (caches[i].present) {
+ KASSERT(caches[i].id_shift <= pkg_id_shift,
+ ("bug in APIC topology discovery"));
+ KASSERT(caches[i].id_shift >= core_id_shift,
+ ("bug in APIC topology discovery"));
+
+ topo_layers[nlayers].type = TOPO_TYPE_CACHE;
+ topo_layers[nlayers].subtype = i + 1;
+ topo_layers[nlayers].id_shift = caches[i].id_shift;
+ if (bootverbose)
+ printf("L%u cache ID shift: %u\n",
+ topo_layers[nlayers].subtype,
+ topo_layers[nlayers].id_shift);
+ nlayers++;
+ }
+ }
+
+ if (pkg_id_shift > core_id_shift) {
+ topo_layers[nlayers].type = TOPO_TYPE_CORE;
+ topo_layers[nlayers].id_shift = core_id_shift;
+ if (bootverbose)
+ printf("Core ID shift: %u\n",
+ topo_layers[nlayers].id_shift);
+ nlayers++;
+ }
+
+ topo_layers[nlayers].type = TOPO_TYPE_PU;
+ topo_layers[nlayers].id_shift = 0;
+ nlayers++;
+
+ topo_init_root(&topo_root);
+ for (i = 0; i <= MAX_APIC_ID; ++i) {
+ if (!cpu_info[i].cpu_present)
+ continue;
+
+ parent = &topo_root;
+ for (layer = 0; layer < nlayers; ++layer) {
+ node_id = i >> topo_layers[layer].id_shift;
+ parent = topo_add_node_by_hwid(parent, node_id,
+ topo_layers[layer].type,
+ topo_layers[layer].subtype);
+ }
+ }
+
+ parent = &topo_root;
+ for (layer = 0; layer < nlayers; ++layer) {
+ node_id = boot_cpu_id >> topo_layers[layer].id_shift;
+ node = topo_find_node_by_hwid(parent, node_id,
+ topo_layers[layer].type,
+ topo_layers[layer].subtype);
+ topo_promote_child(node);
+ parent = node;
+ }
+
cpu_topo_probed = 1;
}
-struct cpu_group *
-cpu_topo(void)
+/*
+ * Assign logical CPU IDs to local APICs.
+ */
+void
+assign_cpu_ids(void)
{
- int cg_flags;
+ struct topo_node *node;
+ u_int smt_mask;
+
+ smt_mask = (1u << core_id_shift) - 1;
/*
- * Determine whether any threading flags are
- * necessry.
+ * Assign CPU IDs to local APIC IDs and disable any CPUs
+ * beyond MAXCPU. CPU 0 is always assigned to the BSP.
*/
- topo_probe();
- if (cpu_logical > 1 && hyperthreading_cpus)
- cg_flags = CG_FLAG_HTT;
- else if (cpu_logical > 1)
- cg_flags = CG_FLAG_SMT;
+ mp_ncpus = 0;
+ TOPO_FOREACH(node, &topo_root) {
+ if (node->type != TOPO_TYPE_PU)
+ continue;
+
+ if ((node->hwid & smt_mask) != (boot_cpu_id & smt_mask))
+ cpu_info[node->hwid].cpu_hyperthread = 1;
+
+ if (resource_disabled("lapic", node->hwid)) {
+ if (node->hwid != boot_cpu_id)
+ cpu_info[node->hwid].cpu_disabled = 1;
+ else
+ printf("Cannot disable BSP, APIC ID = %d\n",
+ node->hwid);
+ }
+
+ if (!hyperthreading_allowed &&
+ cpu_info[node->hwid].cpu_hyperthread)
+ cpu_info[node->hwid].cpu_disabled = 1;
+
+ if (mp_ncpus >= MAXCPU)
+ cpu_info[node->hwid].cpu_disabled = 1;
+
+ if (cpu_info[node->hwid].cpu_disabled) {
+ disabled_cpus++;
+ continue;
+ }
+
+ cpu_apic_ids[mp_ncpus] = node->hwid;
+ apic_cpuids[node->hwid] = mp_ncpus;
+ topo_set_pu_id(node, mp_ncpus);
+ mp_ncpus++;
+ }
+
+ KASSERT(mp_maxid >= mp_ncpus - 1,
+ ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
+ mp_ncpus));
+}
+
+/*
+ * Print various information about the SMP system hardware and setup.
+ */
+void
+cpu_mp_announce(void)
+{
+ struct topo_node *node;
+ const char *hyperthread;
+ int pkg_count;
+ int cores_per_pkg;
+ int thrs_per_core;
+
+ printf("FreeBSD/SMP: ");
+ if (topo_analyze(&topo_root, 1, &pkg_count,
+ &cores_per_pkg, &thrs_per_core)) {
+ printf("%d package(s)", pkg_count);
+ if (cores_per_pkg > 0)
+ printf(" x %d core(s)", cores_per_pkg);
+ if (thrs_per_core > 1)
+ printf(" x %d hardware threads", thrs_per_core);
+ } else {
+ printf("Non-uniform topology");
+ }
+ printf("\n");
+
+ if (disabled_cpus) {
+ printf("FreeBSD/SMP Online: ");
+ if (topo_analyze(&topo_root, 0, &pkg_count,
+ &cores_per_pkg, &thrs_per_core)) {
+ printf("%d package(s)", pkg_count);
+ if (cores_per_pkg > 0)
+ printf(" x %d core(s)", cores_per_pkg);
+ if (thrs_per_core > 1)
+ printf(" x %d hardware threads", thrs_per_core);
+ } else {
+ printf("Non-uniform topology");
+ }
+ printf("\n");
+ }
+
+ if (!bootverbose)
+ return;
+
+ TOPO_FOREACH(node, &topo_root) {
+ switch (node->type) {
+ case TOPO_TYPE_PKG:
+ printf("Package HW ID = %u (%#x)\n",
+ node->hwid, node->hwid);
+ break;
+ case TOPO_TYPE_CORE:
+ printf("\tCore HW ID = %u (%#x)\n",
+ node->hwid, node->hwid);
+ break;
+ case TOPO_TYPE_PU:
+ if (cpu_info[node->hwid].cpu_hyperthread)
+ hyperthread = "/HT";
+ else
+ hyperthread = "";
+
+ if (node->subtype == 0)
+ printf("\t\tCPU (AP%s): APIC ID: %u (%#x)"
+ "(disabled)\n", hyperthread, node->hwid,
+ node->hwid);
+ else if (node->id == 0)
+ printf("\t\tCPU0 (BSP): APIC ID: %u (%#x)\n",
+ node->hwid, node->hwid);
+ else
+ printf("\t\tCPU%u (AP%s): APIC ID: %u (%#x)\n",
+ node->id, hyperthread, node->hwid,
+ node->hwid);
+ break;
+ default:
+ /* ignored */
+ break;
+ }
+ }
+}
+
+static void
+x86topo_add_sched_group(struct topo_node *root, struct cpu_group *cg_root)
+{
+ struct topo_node *node;
+ int nchildren;
+ int ncores;
+ int i;
+
+ KASSERT(root->type == TOPO_TYPE_SYSTEM || root->type == TOPO_TYPE_CACHE,
+ ("x86topo_add_sched_group: bad type: %u", root->type));
+ CPU_COPY(&root->cpuset, &cg_root->cg_mask);
+ cg_root->cg_count = root->cpu_count;
+ if (root->type == TOPO_TYPE_SYSTEM)
+ cg_root->cg_level = CG_SHARE_NONE;
else
- cg_flags = 0;
- if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
- printf("WARNING: Non-uniform processors.\n");
- printf("WARNING: Using suboptimal topology.\n");
- return (smp_topo_none());
+ cg_root->cg_level = root->subtype;
+
+ ncores = 0;
+ node = root;
+ while (node != NULL) {
+ if (node->type != TOPO_TYPE_CORE) {
+ node = topo_next_node(root, node);
+ continue;
+ }
+
+ ncores++;
+ node = topo_next_nonchild_node(root, node);
}
- /*
- * No multi-core or hyper-threaded.
- */
- if (cpu_logical * cpu_cores == 1)
+
+ if (cg_root->cg_level != CG_SHARE_NONE &&
+ root->cpu_count > 1 && ncores < 2)
+ cg_root->cg_flags = CG_FLAG_SMT;
+
+ nchildren = 0;
+ node = root;
+ while (node != NULL) {
+ if (node->type != TOPO_TYPE_CACHE ||
+ (root->type != TOPO_TYPE_SYSTEM &&
+ CPU_CMP(&node->cpuset, &root->cpuset) == 0)) {
+ node = topo_next_node(root, node);
+ continue;
+ }
+ nchildren++;
+ node = topo_next_nonchild_node(root, node);
+ }
+
+ cg_root->cg_child = smp_topo_alloc(nchildren);
+ cg_root->cg_children = nchildren;
+
+ node = root;
+ i = 0;
+ while (node != NULL) {
+ if (node->type != TOPO_TYPE_CACHE ||
+ (root->type != TOPO_TYPE_SYSTEM &&
+ CPU_CMP(&node->cpuset, &root->cpuset) == 0)) {
+ node = topo_next_node(root, node);
+ continue;
+ }
+ cg_root->cg_child[i].cg_parent = cg_root;
+ x86topo_add_sched_group(node, &cg_root->cg_child[i]);
+ i++;
+ node = topo_next_nonchild_node(root, node);
+ }
+}
+
+struct cpu_group *
+cpu_topo(void)
+{
+ struct cpu_group *cg_root;
+
+ if (mp_ncpus <= 1)
return (smp_topo_none());
- /*
- * Only HTT no multi-core.
- */
- if (cpu_logical > 1 && cpu_cores == 1)
- return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
- /*
- * Only multi-core no HTT.
- */
- if (cpu_cores > 1 && cpu_logical == 1)
- return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
- /*
- * Both HTT and multi-core.
- */
- return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
- CG_SHARE_L1, cpu_logical, cg_flags));
+
+ cg_root = smp_topo_alloc(1);
+ x86topo_add_sched_group(&topo_root, cg_root);
+ return (cg_root);
}
@@ -445,47 +771,9 @@ cpu_mp_probe(void)
}
/*
- * Print various information about the SMP system hardware and setup.
+ * AP CPU's call this to initialize themselves.
*/
void
-cpu_mp_announce(void)
-{
- const char *hyperthread;
- int i;
-
- printf("FreeBSD/SMP: %d package(s) x %d core(s)",
- mp_ncpus / (cpu_cores * cpu_logical), cpu_cores);
- if (hyperthreading_cpus > 1)
- printf(" x %d HTT threads", cpu_logical);
- else if (cpu_logical > 1)
- printf(" x %d SMT threads", cpu_logical);
- printf("\n");
-
- /* List active CPUs first. */
- printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id);
- for (i = 1; i < mp_ncpus; i++) {
- if (cpu_info[cpu_apic_ids[i]].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu%d (AP%s): APIC ID: %2d\n", i, hyperthread,
- cpu_apic_ids[i]);
- }
-
- /* List disabled CPUs last. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || !cpu_info[i].cpu_disabled)
- continue;
- if (cpu_info[i].cpu_hyperthread)
- hyperthread = "/HT";
- else
- hyperthread = "";
- printf(" cpu (AP%s): APIC ID: %2d (disabled)\n", hyperthread,
- i);
- }
-}
-
-void
init_secondary_tail(void)
{
u_int cpuid;
@@ -546,8 +834,7 @@ init_secondary_tail(void)
printf("SMP: AP CPU #%d Launched!\n", cpuid);
/* Determine if we are a logical CPU. */
- /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */
- if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0)
+ if (cpu_info[PCPU_GET(apic_id)].cpu_hyperthread)
CPU_SET(cpuid, &logical_cpus_mask);
if (bootverbose)
@@ -612,85 +899,13 @@ set_interrupt_apic_ids(void)
continue;
/* Don't let hyperthreads service interrupts. */
- if (cpu_logical > 1 &&
- apic_id % cpu_logical != 0)
+ if (cpu_info[apic_id].cpu_hyperthread)
continue;
intr_add_cpu(i);
}
}
-/*
- * Assign logical CPU IDs to local APICs.
- */
-void
-assign_cpu_ids(void)
-{
- u_int i;
-
- TUNABLE_INT_FETCH("machdep.hyperthreading_allowed",
- &hyperthreading_allowed);
-
- /* Check for explicitly disabled CPUs. */
- for (i = 0; i <= MAX_APIC_ID; i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp)
- continue;
-
- if (hyperthreading_cpus > 1 && i % hyperthreading_cpus != 0) {
- cpu_info[i].cpu_hyperthread = 1;
-
- /*
- * Don't use HT CPU if it has been disabled by a
- * tunable.
- */
- if (hyperthreading_allowed == 0) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- /* Don't use this CPU if it has been disabled by a tunable. */
- if (resource_disabled("lapic", i)) {
- cpu_info[i].cpu_disabled = 1;
- continue;
- }
- }
-
- if (hyperthreading_allowed == 0 && hyperthreading_cpus > 1) {
- hyperthreading_cpus = 0;
- cpu_logical = 1;
- }
-
- /*
- * Assign CPU IDs to local APIC IDs and disable any CPUs
- * beyond MAXCPU. CPU 0 is always assigned to the BSP.
- *
- * To minimize confusion for userland, we attempt to number
- * CPUs such that all threads and cores in a package are
- * grouped together. For now we assume that the BSP is always
- * the first thread in a package and just start adding APs
- * starting with the BSP's APIC ID.
- */
- mp_ncpus = 1;
- cpu_apic_ids[0] = boot_cpu_id;
- apic_cpuids[boot_cpu_id] = 0;
- for (i = boot_cpu_id + 1; i != boot_cpu_id;
- i == MAX_APIC_ID ? i = 0 : i++) {
- if (!cpu_info[i].cpu_present || cpu_info[i].cpu_bsp ||
- cpu_info[i].cpu_disabled)
- continue;
-
- if (mp_ncpus < MAXCPU) {
- cpu_apic_ids[mp_ncpus] = i;
- apic_cpuids[i] = mp_ncpus;
- mp_ncpus++;
- } else
- cpu_info[i].cpu_disabled = 1;
- }
- KASSERT(mp_maxid >= mp_ncpus - 1,
- ("%s: counters out of sync: max %d, count %d", __func__, mp_maxid,
- mp_ncpus));
-}
#ifdef COUNT_XINVLTLB_HITS
u_int xhits_gbl[MAXCPU];
@@ -910,7 +1125,7 @@ ipi_all_but_self(u_int ipi)
}
int
-ipi_nmi_handler()
+ipi_nmi_handler(void)
{
u_int cpuid;
diff --git a/sys/x86/x86/nexus.c b/sys/x86/x86/nexus.c
index 39eeb82..8b49d41 100644
--- a/sys/x86/x86/nexus.c
+++ b/sys/x86/x86/nexus.c
@@ -301,9 +301,9 @@ nexus_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return retval;
}
OpenPOWER on IntegriCloud