Al Viro (4): Bluetooth: hidp_connection_add() unsafe use of l2cap_pi() Bluetooth: cmtp: cmtp_add_connection() should verify that it's dealing with l2cap socket Bluetooth: bnep: bnep_add_connection() should verify that it's dealing with l2cap socket [regression] braino in "lustre: use is_root_inode()" Alexey Skidanov (1): amdkfd: init aperture once per process Amir Vadai (1): net/mlx4_en: Doorbell is byteswapped in Little Endian archs Antonio Quartulli (1): batman-adv: avoid NULL dereferences and fix if check Appana Durga Kedareswara Rao (1): net: xilinx: Remove unnecessary temac_property in the driver Catalin Marinas (1): arm64: Replace set_arch_dma_coherent_ops with arch_setup_dma_ops Chris Wilson (3): drm/i915: Invalidate media caches on gen7 drm/i915: Force the CS stall for invalidate flushes drm/i915: Disable PSMI sleep messages on all rings around context switches Corey Minyard (2): ipmi: Finish cleanup of BMC attributes ipmi: Fix compile issue with isspace() Dan Collins (1): packet: Fixed TPACKET V3 to signal poll when block is closed rather than every packet Daniel Glöckner (1): net: s6gmac: remove driver Dave Airlie (7): nouveau: bring back legacy mmap handler Merge branch 'msm-fixes-3.19' of git://people.freedesktop.org/~robclark/linux into drm-fixes Merge tag 'topic/atomic-fixes-2014-12-17' of git://anongit.freedesktop.org/drm-intel into drm-fixes Merge tag 'drm-intel-next-fixes-2014-12-17' of git://anongit.freedesktop.org/drm-intel into drm-fixes Merge tag 'drm/tegra/for-3.19-rc1-fixes' of git://people.freedesktop.org/~tagr/linux into drm-fixes Merge tag 'amdkfd-fixes-2014-12-23' of git://people.freedesktop.org/~gabbayo/linux into drm-fixes Revert "drm/gem: Warn on illegal use of the dumb buffer interface v2" Dave Jones (1): agp: Fix up email address & attributions in AGP MODULE_AUTHOR tags David S. Miller (5): Merge branch 'for-upstream' of git://git.kernel.org/.../bluetooth/bluetooth Merge branch 'openvswitch-net' Merge tag 'wireless-drivers-for-davem-2014-12-26' of git://git.kernel.org/.../kvalo/wireless-drivers Merge branch 'for-upstream' of git://git.kernel.org/.../bluetooth/bluetooth Merge branch 'netlink_multicast' Eliad Peller (1): iwlwifi: mvm: clear IN_HW_RESTART flag on stop() Emmanuel Grumbach (3): iwlwifi: pcie: re-ACK all interrupts after device reset iwlwifi: don't double free a pointer if no FW was found iwlwifi: add new device IDs for 3165 Govindarajulu Varadarajan (1): enic: fix rx skb checksum Haiyang Zhang (1): hyperv: Fix some variable name typos in send-buffer init/revoke Hariprasad Shenai (1): cxgb4vf: Fix ethtool get_settings for VF driver Herbert Xu (6): virtio_net: Fix napi poll list corruption caif: Fix napi poll list corruption net: Move napi polling code out of net_rx_action net: Detect drivers that reschedule NAPI and exhaust budget net: Always poll at least one device in net_rx_action net: Rearrange loop in net_rx_action Huacai Chen (1): stmmac: Don't init ptp again when resume from suspend/hibernation Imre Deak (3): drm/i915: vlv: fix IRQ masking when uninstalling interrupts drm/i915: move RPS PM_IER enabling to gen6_enable_rps_interrupts drm/i915: sanitize RPS resetting during GPU reset Jason Wang (1): net: drop the packet when fails to do software segmentation or header check Jay Vosburgh (1): net/core: Handle csum for CHECKSUM_COMPLETE VXLAN forwarding Jesse Gross (1): net: Generalize ndo_gso_check to ndo_features_check Jia-Ju Bai (3): 8139too: Fix the lack of pci_disable_device 8139too: Add netif_napi_del in the driver ne2k-pci: Add pci_disable_device in error handling Jilai Wang (2): drm/msm/hdmi: enable regulators before clocks to avoid warnings drm/msm/hdmi: rework HDMI IRQ handler Joe Thornber (2): dm thin: fix inability to discard blocks when in out-of-data-space mode dm thin: fix missing out-of-data-space to write mode transition if blocks are released Johan Hedberg (1): Bluetooth: Fix accepting connections when not using mgmt Johan Hovold (1): net: phy: micrel: use generic config_init for KSZ8021/KSZ8031 Johannes Berg (6): netlink: rename netlink_unbind() to netlink_undo_bind() genetlink: pass only network namespace to genl_has_listeners() netlink: update listeners directly when removing socket netlink: call unbind when releasing socket genetlink: pass multicast bind/unbind to families netlink/genetlink: pass network namespace to bind/unbind John David Anglin (1): parisc: fix out-of-register compiler error in ldcw inline assembler function Jukka Rissanen (1): Bluetooth: 6lowpan: Do not free skb when packet is dropped Jungseok Lee (1): arm64: mm: Add pgd_page to support RCU fast_gup Kalle Valo (1): Merge tag 'iwlwifi-fixes-for-kalle-2014-12-18' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes Kent Overstreet (3): closures: move to lib/ closures: fix closure_sync() aio: Convert to closure waitlist for aio ring buffer Kirill A. Shutemov (1): Revert "mm/memory.c: share the i_mmap_rwsem" Li RongQing (1): sunvnet: fix a memory leak in vnet_handle_offloads Liad Kaufman (1): iwlwifi: pcie: limit fw chunk sizes given to fh Libin Yang (1): ALSA: hda_intel: apply the Seperate stream_tag for Skylake Linus Torvalds (7): Merge tag 'dm-3.19-fixes' of git://git.kernel.org/.../device-mapper/linux-dm Merge tag 'arm64-fixes' of git://git.kernel.org/.../arm64/linux Merge branch 'upstream' of git://git.infradead.org/users/pcmoore/audit Merge tag 'for-linus-2' of git://git.code.sf.net/p/openipmi/linux-ipmi Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux Merge branch 'parisc-3.19-1' of git://git.kernel.org/.../deller/parisc-linux Merge tag 'sound-3.19-rc2' of git://git.kernel.org/.../tiwai/sound Lorenzo Pieralisi (1): arm64: kernel: fix __cpu_suspend mm switch on warm-boot Marc Dionne (1): dm thin: fix crash by initializing thin device's refcount and completion earlier Marcel Holtmann (1): Bluetooth: Fix controller configuration with HCI_QUIRK_INVALID_BDADDR Markus Elfring (2): drm/msm: Deletion of unnecessary checks before two function calls drm/msm: Deletion of unnecessary checks before the function call "release_firmware" Mika Westerberg (1): brcmfmac: Do not crash if platform data is not populated Nicholas Mc Guire (1): net: incorrect use of init_completion fixup Nicolas Dichtel (2): tcp6: don't move IP6CB before xfrm6_policy_check() neigh: remove next ptr from struct neigh_table Oded Gabbay (3): drm/amd: Add get_fw_version to kfd-->kgd interface drm/radeon: Add implementation of get_fw_version amdkfd: Display MEC fw version in topology node Paul Bolle (1): ipw2200: select CFG80211_WEXT Paul Moore (2): audit: don't attempt to lookup PIDs when changing PID filtering audit rules audit: correctly record file names with different path name types Prashant Sreedharan (1): tg3: tg3_disable_ints using uninitialized mailbox value to disable interrupts Pravin B Shelar (6): mpls: Fix config check for mpls. mpls: Fix allowed protocols for mpls gso openvswitch: Fix MPLS action validation. openvswitch: Fix GSO with multiple MPLS label. openvswitch: Fix vport_send double free vxlan: Fix double free of skb. Rafal Redzimski (1): ALSA: hda_controller: Separate stream_tag for input and output streams. Richard Guy Briggs (2): audit: use supplied gfp_mask from audit_buffer in kauditd_send_multicast_skb audit: restore AUDIT_LOGINUID unset ABI Rickard Strandqvist (1): net: ethernet: micrel: ksz884x.c: Remove unused function Rob Clark (3): drm/atomic: fix potential null ptr on plane enable drm/msm: block incoming update on pending updates drm/msm/mdp5: update irqs on crtc<->encoder link change Sean Paul (1): drm/tegra: dc: Select root window for event dispatch Sedat Dilek (12): kbuild: deb-pkg: Try to determine distribution kbuild: deb-pkg: Bump year in debian/copyright file (v3) kbuild: deb-pkg: Update git repository URL in debian/copyright file (v3) Merge branch 'master' of git://git.kernel.org/.../davem/net into for-3.19/net-fixes genetlink: Comment out WARN_ON() in genl_bind() Merge branch 'for-3.19/deb-pkg-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/vfs-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/net-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/netlink-genetlink-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/aio-ring-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/netlink-fixes' into 3.19.0-rc1-58.2-iniza-small Merge branch 'for-3.19/netlink-genetlink-fixes-dileks' into 3.19.0-rc1-58.2-iniza-small Slava Pestov (1): closures: Add closure_sync_interruptible_hrtimeout Sven Eckelmann (2): batman-adv: Calculate extra tail size based on queued fragments batman-adv: Unify fragment size calculation Thierry Reding (7): drm/irq: Add drm_crtc_send_vblank_event() drm/irq: Add drm_crtc_handle_vblank() drm/irq: Add drm_crtc_vblank_count() drm/tegra: dc: Consistently use the same pipe drm/tegra: dc: Fix a potential race on page-flip completion drm/tegra: gem: Flush buffer objects upon allocation drm/tegra: gem: Use the proper size for GEM objects Thomas Graf (1): net: Reset secmark when scrubbing packet Toshiaki Makita (1): net: Fix stacked vlan offload features computation Wengang Wang (1): bonding: change error message to debug message in __bond_release_one() Will Deacon (1): arm64: defconfig: defconfig update for 3.19 Wolfram Sang (1): net: ethernet: stmicro: stmmac: drop owner assignment from platform_drivers Wu Fengguang (1): openvswitch: fix odd_ptr_err.cocci warnings stephen hemminger (2): in6: fix conflict with glibc netlink: call cond_resched after broadcasting updates zhendong chen (1): dm: fix missed error code if .end_io isn't implemented by target_type arch/arm64/configs/defconfig | 9 +- arch/arm64/include/asm/dma-mapping.h | 11 +- arch/arm64/include/asm/pgtable.h | 5 +- arch/arm64/kernel/suspend.c | 14 +- arch/parisc/include/asm/ldcw.h | 13 +- drivers/char/agp/ali-agp.c | 2 +- drivers/char/agp/amd64-agp.c | 2 +- drivers/char/agp/ati-agp.c | 2 +- drivers/char/agp/backend.c | 2 +- drivers/char/agp/intel-agp.c | 2 +- drivers/char/agp/intel-gtt.c | 2 +- drivers/char/agp/nvidia-agp.c | 2 +- drivers/char/agp/via-agp.c | 2 +- drivers/char/ipmi/ipmi_msghandler.c | 46 +- drivers/char/ipmi/ipmi_ssif.c | 1 + drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 4 - drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c | 6 +- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 9 + drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 8 +- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 15 + drivers/gpu/drm/drm_atomic_helper.c | 2 +- drivers/gpu/drm/drm_irq.c | 60 ++ drivers/gpu/drm/i915/i915_drv.c | 6 +- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_gem.c | 28 +- drivers/gpu/drm/i915/i915_gem_context.c | 48 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 - drivers/gpu/drm/i915/i915_irq.c | 18 +- drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_pm.c | 28 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 + drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 +- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 53 +- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 11 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 12 +- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 12 +- drivers/gpu/drm/msm/mdp/mdp_kms.c | 9 +- drivers/gpu/drm/msm/mdp/mdp_kms.h | 2 +- drivers/gpu/drm/msm/msm_atomic.c | 69 +- drivers/gpu/drm/msm/msm_drv.c | 1 + drivers/gpu/drm/msm/msm_drv.h | 4 + drivers/gpu/drm/msm/msm_fbdev.c | 3 +- drivers/gpu/drm/msm/msm_gem.c | 3 +- drivers/gpu/drm/nouveau/nouveau_display.c | 9 - drivers/gpu/drm/nouveau/nouveau_gem.c | 3 - drivers/gpu/drm/nouveau/nouveau_ttm.c | 3 +- drivers/gpu/drm/radeon/radeon_gem.c | 26 +- drivers/gpu/drm/radeon/radeon_kfd.c | 53 + drivers/gpu/drm/radeon/radeon_object.c | 3 - drivers/gpu/drm/tegra/dc.c | 48 +- drivers/gpu/drm/tegra/drm.c | 16 +- drivers/gpu/drm/tegra/gem.c | 52 +- drivers/md/bcache/Kconfig | 9 - drivers/md/bcache/Makefile | 6 +- drivers/md/bcache/bcache.h | 2 +- drivers/md/bcache/closure.c | 222 ---- drivers/md/bcache/closure.h | 386 ------- drivers/md/bcache/super.c | 1 - drivers/md/bcache/util.h | 3 +- drivers/md/dm-thin.c | 29 +- drivers/md/dm.c | 2 +- drivers/net/bonding/bond_main.c | 2 +- drivers/net/caif/caif_virtio.c | 2 - drivers/net/ethernet/8390/ne2k-pci.c | 6 +- drivers/net/ethernet/Kconfig | 12 - drivers/net/ethernet/Makefile | 1 - drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 8 +- drivers/net/ethernet/broadcom/tg3.c | 34 +- drivers/net/ethernet/brocade/bna/bnad_debugfs.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/adapter.h | 4 + .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 142 ++- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 54 +- drivers/net/ethernet/cisco/enic/enic_main.c | 12 +- drivers/net/ethernet/emulex/benet/be_main.c | 8 +- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 10 +- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 12 +- drivers/net/ethernet/micrel/ksz884x.c | 6 - drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 8 +- drivers/net/ethernet/realtek/8139too.c | 4 +- drivers/net/ethernet/s6gmac.c | 1058 -------------------- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 14 +- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 1 - drivers/net/ethernet/sun/sunvnet.c | 1 + drivers/net/ethernet/xilinx/xilinx_axienet.h | 2 - drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 4 - drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc.c | 15 +- drivers/net/phy/micrel.c | 18 +- drivers/net/virtio_net.c | 2 - drivers/net/vxlan.c | 34 +- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 4 +- drivers/net/wireless/ipw2x00/Kconfig | 3 +- drivers/net/wireless/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/iwlwifi/iwl-fh.h | 1 + drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 +- drivers/net/wireless/iwlwifi/pcie/drv.c | 4 + drivers/net/wireless/iwlwifi/pcie/trans.c | 17 +- drivers/staging/lustre/lustre/llite/namei.c | 2 +- fs/aio.c | 28 +- include/drm/drmP.h | 4 + include/drm/drm_gem.h | 7 - include/linux/audit.h | 4 + include/linux/closure.h | 458 +++++++++ include/linux/netdevice.h | 20 +- include/linux/netlink.h | 4 +- include/net/genetlink.h | 9 +- include/net/neighbour.h | 1 - include/net/vxlan.h | 28 +- include/uapi/linux/in6.h | 3 +- include/uapi/linux/libc-compat.h | 3 + kernel/audit.c | 10 +- kernel/auditfilter.c | 23 +- kernel/auditsc.c | 14 +- lib/Kconfig.debug | 8 + lib/Makefile | 2 +- lib/closure.c | 285 ++++++ mm/memory.c | 4 +- net/batman-adv/fragmentation.c | 4 +- net/batman-adv/gateway_client.c | 2 +- net/bluetooth/6lowpan.c | 1 - net/bluetooth/bnep/core.c | 3 + net/bluetooth/cmtp/core.c | 3 + net/bluetooth/hci_event.c | 16 +- net/bluetooth/hidp/core.c | 3 +- net/core/dev.c | 175 ++-- net/core/skbuff.c | 1 + net/ipv4/geneve.c | 6 +- net/ipv6/tcp_ipv6.c | 45 +- net/mpls/mpls_gso.c | 5 +- net/netfilter/nfnetlink.c | 2 +- net/netlink/af_netlink.c | 42 +- net/netlink/af_netlink.h | 8 +- net/netlink/genetlink.c | 63 ++ net/openvswitch/actions.c | 3 +- net/openvswitch/datapath.c | 3 +- net/openvswitch/flow_netlink.c | 13 +- net/openvswitch/vport-geneve.c | 3 + net/openvswitch/vport-gre.c | 18 +- net/openvswitch/vport-vxlan.c | 2 + net/openvswitch/vport.c | 5 +- net/packet/af_packet.c | 11 +- scripts/package/builddeb | 19 +- sound/pci/hda/hda_controller.c | 24 +- sound/pci/hda/hda_intel.c | 5 +- sound/pci/hda/hda_priv.h | 1 + 146 files changed, 2006 insertions(+), 2341 deletions(-) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index dd301be..5376d90 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -1,6 +1,7 @@ # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_FHANDLE=y CONFIG_AUDIT=y CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y @@ -13,14 +14,12 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_RESOURCE_COUNTERS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_MEMCG_KMEM=y CONFIG_CGROUP_HUGETLB=y # CONFIG_UTS_NS is not set # CONFIG_IPC_NS is not set -# CONFIG_PID_NS is not set # CONFIG_NET_NS is not set CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y @@ -92,7 +91,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set -# CONFIG_HMC_DRV is not set CONFIG_SPI=y CONFIG_SPI_PL022=y CONFIG_GPIO_PL061=y @@ -133,6 +131,8 @@ CONFIG_EXT3_FS=y CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=y CONFIG_CUSE=y CONFIG_VFAT_FS=y @@ -152,14 +152,15 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_LOCKUP_DETECTOR=y # CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set +CONFIG_KEYS=y CONFIG_SECURITY=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_AES_ARM64_CE=y CONFIG_CRYPTO_AES_ARM64_CE_CCM=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index d34189b..9ce3e68 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -52,13 +52,14 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) dev->archdata.dma_ops = ops; } -static inline int set_arch_dma_coherent_ops(struct device *dev) +static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, + struct iommu_ops *iommu, bool coherent) { - dev->archdata.dma_coherent = true; - set_dma_ops(dev, &coherent_swiotlb_dma_ops); - return 0; + dev->archdata.dma_coherent = coherent; + if (coherent) + set_dma_ops(dev, &coherent_swiotlb_dma_ops); } -#define set_arch_dma_coherent_ops set_arch_dma_coherent_ops +#define arch_setup_dma_ops arch_setup_dma_ops /* do not use this function in a driver */ static inline bool is_device_dma_coherent(struct device *dev) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index df22314..210d632 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -298,7 +298,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, #define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) -#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) #define pud_write(pud) pte_write(pud_pte(pud)) #define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT) @@ -401,7 +400,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); } -#define pud_page(pud) pmd_page(pud_pmd(pud)) +#define pud_page(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK)) #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */ @@ -437,6 +436,8 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr) return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr); } +#define pgd_page(pgd) pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK)) + #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */ #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 3771b72..2d6b606 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,18 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) */ ret = __cpu_suspend_enter(arg, fn); if (ret == 0) { - cpu_switch_mm(mm->pgd, mm); + /* + * We are resuming from reset with TTBR0_EL1 set to the + * idmap to enable the MMU; restore the active_mm mappings in + * TTBR0_EL1 unless the active_mm == &init_mm, in which case + * the thread entered __cpu_suspend with TTBR0_EL1 set to + * reserved TTBR0 page tables and should be restored as such. + */ + if (mm == &init_mm) + cpu_set_reserved_ttbr0(); + else + cpu_switch_mm(mm->pgd, mm); + flush_tlb_all(); /* diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h index d2d11b7..8121aa6 100644 --- a/arch/parisc/include/asm/ldcw.h +++ b/arch/parisc/include/asm/ldcw.h @@ -33,11 +33,18 @@ #endif /*!CONFIG_PA20*/ -/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ +/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. + We don't explicitly expose that "*a" may be written as reload + fails to find a register in class R1_REGS when "a" needs to be + reloaded when generating 64-bit PIC code. Instead, we clobber + memory to indicate to the compiler that the assembly code reads + or writes to items other than those listed in the input and output + operands. This may pessimize the code somewhat but __ldcw is + usually used within code blocks surrounded by memory barriors. */ #define __ldcw(a) ({ \ unsigned __ret; \ - __asm__ __volatile__(__LDCW " 0(%2),%0" \ - : "=r" (__ret), "+m" (*(a)) : "r" (a)); \ + __asm__ __volatile__(__LDCW " 0(%1),%0" \ + : "=r" (__ret) : "r" (a) : "memory"); \ __ret; \ }) diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 19db036..dcbbb4e 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void) module_init(agp_ali_init); module_exit(agp_ali_cleanup); -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 3b47ed0..0ef3500 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -813,6 +813,6 @@ static void __exit agp_amd64_cleanup(void) module_init(agp_amd64_mod_init); module_exit(agp_amd64_cleanup); -MODULE_AUTHOR("Dave Jones , Andi Kleen"); +MODULE_AUTHOR("Dave Jones, Andi Kleen"); module_param(agp_try_unsupported, bool, 0); MODULE_LICENSE("GPL"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 18a7a6b..75a9786 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -579,6 +579,6 @@ static void __exit agp_ati_cleanup(void) module_init(agp_ati_init); module_exit(agp_ati_cleanup); -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 317c28c..38ffb28 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -356,7 +356,7 @@ static __init int agp_setup(char *s) __setup("agp=", agp_setup); #endif -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones, Jeff Hartmann"); MODULE_DESCRIPTION("AGP GART driver"); MODULE_LICENSE("GPL and additional rights"); MODULE_ALIAS_MISCDEV(AGPGART_MINOR); diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index f9b9ca5..0a21dae 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -920,5 +920,5 @@ static void __exit agp_intel_cleanup(void) module_init(agp_intel_init); module_exit(agp_intel_cleanup); -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones, Various @Intel"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index f333482..92aa43f 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1438,5 +1438,5 @@ void intel_gmch_remove(void) } EXPORT_SYMBOL(intel_gmch_remove); -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones, Various @Intel"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index a1861b7..6c8d39c 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -1,7 +1,7 @@ /* * Nvidia AGPGART routines. * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up - * to work in 2.5 by Dave Jones + * to work in 2.5 by Dave Jones. */ #include diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 228f20c..a4961d3 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -595,4 +595,4 @@ module_init(agp_via_init); module_exit(agp_via_cleanup); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Dave Jones "); +MODULE_AUTHOR("Dave Jones"); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5fa83f7..6b65fa4 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -199,18 +199,6 @@ struct bmc_device { int guid_set; char name[16]; struct kref usecount; - - /* bmc device attributes */ - struct device_attribute device_id_attr; - struct device_attribute provides_dev_sdrs_attr; - struct device_attribute revision_attr; - struct device_attribute firmware_rev_attr; - struct device_attribute version_attr; - struct device_attribute add_dev_support_attr; - struct device_attribute manufacturer_id_attr; - struct device_attribute product_id_attr; - struct device_attribute guid_attr; - struct device_attribute aux_firmware_rev_attr; }; #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev) @@ -2252,7 +2240,7 @@ static ssize_t device_id_show(struct device *dev, return snprintf(buf, 10, "%u\n", bmc->id.device_id); } -DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); +static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL); static ssize_t provides_device_sdrs_show(struct device *dev, struct device_attribute *attr, @@ -2263,7 +2251,8 @@ static ssize_t provides_device_sdrs_show(struct device *dev, return snprintf(buf, 10, "%u\n", (bmc->id.device_revision & 0x80) >> 7); } -DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, NULL); +static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, + NULL); static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2273,7 +2262,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, 20, "%u\n", bmc->id.device_revision & 0x0F); } -DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); +static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL); static ssize_t firmware_revision_show(struct device *dev, struct device_attribute *attr, @@ -2284,7 +2273,7 @@ static ssize_t firmware_revision_show(struct device *dev, return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1, bmc->id.firmware_revision_2); } -DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); +static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL); static ssize_t ipmi_version_show(struct device *dev, struct device_attribute *attr, @@ -2296,7 +2285,7 @@ static ssize_t ipmi_version_show(struct device *dev, ipmi_version_major(&bmc->id), ipmi_version_minor(&bmc->id)); } -DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); +static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL); static ssize_t add_dev_support_show(struct device *dev, struct device_attribute *attr, @@ -2307,7 +2296,8 @@ static ssize_t add_dev_support_show(struct device *dev, return snprintf(buf, 10, "0x%02x\n", bmc->id.additional_device_support); } -DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL); +static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, + NULL); static ssize_t manufacturer_id_show(struct device *dev, struct device_attribute *attr, @@ -2317,7 +2307,7 @@ static ssize_t manufacturer_id_show(struct device *dev, return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id); } -DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); +static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL); static ssize_t product_id_show(struct device *dev, struct device_attribute *attr, @@ -2327,7 +2317,7 @@ static ssize_t product_id_show(struct device *dev, return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id); } -DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); +static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL); static ssize_t aux_firmware_rev_show(struct device *dev, struct device_attribute *attr, @@ -2341,7 +2331,7 @@ static ssize_t aux_firmware_rev_show(struct device *dev, bmc->id.aux_firmware_revision[1], bmc->id.aux_firmware_revision[0]); } -DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); +static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL); static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2352,7 +2342,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr, (long long) bmc->guid[0], (long long) bmc->guid[8]); } -DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); +static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL); static struct attribute *bmc_dev_attrs[] = { &dev_attr_device_id.attr, @@ -2392,10 +2382,10 @@ cleanup_bmc_device(struct kref *ref) if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); if (bmc->guid_set) device_remove_file(&bmc->pdev.dev, - &bmc->guid_attr); + &dev_attr_guid); platform_device_unregister(&bmc->pdev); } @@ -2422,16 +2412,14 @@ static int create_bmc_files(struct bmc_device *bmc) int err; if (bmc->id.aux_firmware_revision_set) { - bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; err = device_create_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); if (err) goto out; } if (bmc->guid_set) { - bmc->guid_attr.attr.name = "guid"; err = device_create_file(&bmc->pdev.dev, - &bmc->guid_attr); + &dev_attr_guid); if (err) goto out_aux_firm; } @@ -2441,7 +2429,7 @@ static int create_bmc_files(struct bmc_device *bmc) out_aux_firm: if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->pdev.dev, - &bmc->aux_firmware_rev_attr); + &dev_attr_aux_firmware_revision); out: return err; } diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index e178ac2..fd5a5e8 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -52,6 +52,7 @@ #include #include #include +#include #define PFX "ipmi_ssif: " #define DEVICE_NAME "ipmi_ssif" diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 4f7b275..7d4974b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -121,13 +121,9 @@ static int kfd_open(struct inode *inode, struct file *filep) if (IS_ERR(process)) return PTR_ERR(process); - process->is_32bit_user_mode = is_32bit_user_mode; - dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n", process->pasid, process->is_32bit_user_mode); - kfd_init_apertures(process); - return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 66df4da..e64aa99 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -299,13 +299,13 @@ int kfd_init_apertures(struct kfd_process *process) struct kfd_dev *dev; struct kfd_process_device *pdd; - mutex_lock(&process->mutex); - /*Iterating over all devices*/ while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL && id < NUM_OF_SUPPORTED_GPUS) { pdd = kfd_get_process_device_data(dev, process, 1); + if (!pdd) + return -1; /* * For 64 bit process aperture will be statically reserved in @@ -348,8 +348,6 @@ int kfd_init_apertures(struct kfd_process *process) id++; } - mutex_unlock(&process->mutex); - return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index b85eb0b..3c76ef0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -26,6 +26,8 @@ #include #include #include +#include + struct mm_struct; #include "kfd_priv.h" @@ -285,8 +287,15 @@ static struct kfd_process *create_process(const struct task_struct *thread) if (err != 0) goto err_process_pqm_init; + /* init process apertures*/ + process->is_32bit_user_mode = is_compat_task(); + if (kfd_init_apertures(process) != 0) + goto err_init_apretures; + return process; +err_init_apretures: + pqm_uninit(&process->pqm); err_process_pqm_init: hash_del_rcu(&process->kfd_processes); synchronize_rcu(); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 5733e28..b11792d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -700,8 +700,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.simd_per_cu); sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu", dev->node_props.max_slots_scratch_cu); - sysfs_show_32bit_prop(buffer, "engine_id", - dev->node_props.engine_id); sysfs_show_32bit_prop(buffer, "vendor_id", dev->node_props.vendor_id); sysfs_show_32bit_prop(buffer, "device_id", @@ -715,6 +713,12 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->gpu->kgd)); sysfs_show_64bit_prop(buffer, "local_mem_size", kfd2kgd->get_vmem_size(dev->gpu->kgd)); + + sysfs_show_32bit_prop(buffer, "fw_version", + kfd2kgd->get_fw_version( + dev->gpu->kgd, + KGD_ENGINE_MEC1)); + } ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute", diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 9c729dd..47b5519 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -45,6 +45,17 @@ enum kgd_memory_pool { KGD_POOL_FRAMEBUFFER = 3, }; +enum kgd_engine_type { + KGD_ENGINE_PFP = 1, + KGD_ENGINE_ME, + KGD_ENGINE_CE, + KGD_ENGINE_MEC1, + KGD_ENGINE_MEC2, + KGD_ENGINE_RLC, + KGD_ENGINE_SDMA, + KGD_ENGINE_MAX +}; + struct kgd2kfd_shared_resources { /* Bit n == 1 means VMID n is available for KFD. */ unsigned int compute_vmid_bitmap; @@ -137,6 +148,8 @@ struct kgd2kfd_calls { * * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot. * + * @get_fw_version: Returns FW versions from the header + * * This structure contains function pointers to services that the kgd driver * provides to amdkfd driver. * @@ -176,6 +189,8 @@ struct kfd2kgd_calls { int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type, unsigned int timeout, uint32_t pipe_id, uint32_t queue_id); + uint16_t (*get_fw_version)(struct kgd_dev *kgd, + enum kgd_engine_type type); }; bool kgd2kfd_init(unsigned interface_version, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4a78a77..bbdbe47 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -61,7 +61,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state, struct drm_crtc_state *crtc_state; if (plane->state->crtc) { - crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)]; + crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)]; if (WARN_ON(!crtc_state)) return; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f5a5f18..4d79dad 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -830,6 +830,8 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, * vblank events since the system was booted, including lost events due to * modesetting activity. * + * This is the legacy version of drm_crtc_vblank_count(). + * * Returns: * The software vblank counter. */ @@ -844,6 +846,25 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) EXPORT_SYMBOL(drm_vblank_count); /** + * drm_crtc_vblank_count - retrieve "cooked" vblank counter value + * @crtc: which counter to retrieve + * + * Fetches the "cooked" vblank count value that represents the number of + * vblank events since the system was booted, including lost events due to + * modesetting activity. + * + * This is the native KMS version of drm_vblank_count(). + * + * Returns: + * The software vblank counter. + */ +u32 drm_crtc_vblank_count(struct drm_crtc *crtc) +{ + return drm_vblank_count(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_vblank_count); + +/** * drm_vblank_count_and_time - retrieve "cooked" vblank counter value * and the system timestamp corresponding to that vblank counter value. * @@ -904,6 +925,8 @@ static void send_vblank_event(struct drm_device *dev, * * Updates sequence # and timestamp on event, and sends it to userspace. * Caller must hold event lock. + * + * This is the legacy version of drm_crtc_send_vblank_event(). */ void drm_send_vblank_event(struct drm_device *dev, int crtc, struct drm_pending_vblank_event *e) @@ -923,6 +946,23 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, EXPORT_SYMBOL(drm_send_vblank_event); /** + * drm_crtc_send_vblank_event - helper to send vblank event after pageflip + * @crtc: the source CRTC of the vblank event + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + * + * This is the native KMS version of drm_send_vblank_event(). + */ +void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e) +{ + drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e); +} +EXPORT_SYMBOL(drm_crtc_send_vblank_event); + +/** * drm_vblank_enable - enable the vblank interrupt on a CRTC * @dev: DRM device * @crtc: CRTC in question @@ -1594,6 +1634,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) * * Drivers should call this routine in their vblank interrupt handlers to * update the vblank counter and send any signals that may be pending. + * + * This is the legacy version of drm_crtc_handle_vblank(). */ bool drm_handle_vblank(struct drm_device *dev, int crtc) { @@ -1670,3 +1712,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) return true; } EXPORT_SYMBOL(drm_handle_vblank); + +/** + * drm_crtc_handle_vblank - handle a vblank event + * @crtc: where this event occurred + * + * Drivers should call this routine in their vblank interrupt handlers to + * update the vblank counter and send any signals that may be pending. + * + * This is the native KMS version of drm_handle_vblank(). + * + * Returns: + * True if the event was successfully handled, false on failure. + */ +bool drm_crtc_handle_vblank(struct drm_crtc *crtc) +{ + return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc)); +} +EXPORT_SYMBOL(drm_crtc_handle_vblank); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f990ab4..574057c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -811,6 +811,8 @@ int i915_reset(struct drm_device *dev) if (!i915.reset) return 0; + intel_reset_gt_powersave(dev); + mutex_lock(&dev->struct_mutex); i915_gem_reset(dev); @@ -880,7 +882,7 @@ int i915_reset(struct drm_device *dev) * of re-init after reset. */ if (INTEL_INFO(dev)->gen > 5) - intel_reset_gt_powersave(dev); + intel_enable_gt_powersave(dev); } else { mutex_unlock(&dev->struct_mutex); } @@ -1584,7 +1586,7 @@ static struct drm_driver driver = { .gem_prime_import = i915_gem_prime_import, .dumb_create = i915_gem_dumb_create, - .dumb_map_offset = i915_gem_dumb_map_offset, + .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = drm_gem_dumb_destroy, .ioctls = i915_ioctls, .fops = &i915_driver_fops, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 63bcda5..70d0f0f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2501,9 +2501,8 @@ void i915_vma_move_to_active(struct i915_vma *vma, int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); -int i915_gem_dumb_map_offset(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset); +int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle, uint64_t *offset); /** * Returns true if seq1 is later than seq2. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4a9faea6..52adcb6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -401,7 +401,6 @@ static int i915_gem_create(struct drm_file *file, struct drm_device *dev, uint64_t size, - bool dumb, uint32_t *handle_p) { struct drm_i915_gem_object *obj; @@ -417,7 +416,6 @@ i915_gem_create(struct drm_file *file, if (obj == NULL) return -ENOMEM; - obj->base.dumb = dumb; ret = drm_gem_handle_create(file, &obj->base, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(&obj->base); @@ -437,7 +435,7 @@ i915_gem_dumb_create(struct drm_file *file, args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64); args->size = args->pitch * args->height; return i915_gem_create(file, dev, - args->size, true, &args->handle); + args->size, &args->handle); } /** @@ -450,7 +448,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_create *args = data; return i915_gem_create(file, dev, - args->size, false, &args->handle); + args->size, &args->handle); } static inline int @@ -1840,10 +1838,10 @@ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj) drm_gem_free_mmap_offset(&obj->base); } -static int +int i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, - uint32_t handle, bool dumb, + uint32_t handle, uint64_t *offset) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1860,13 +1858,6 @@ i915_gem_mmap_gtt(struct drm_file *file, goto unlock; } - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(dumb && !(obj->base.dumb || obj->base.import_attach), - "Illegal dumb map of accelerated buffer.\n"); - if (obj->base.size > dev_priv->gtt.mappable_end) { ret = -E2BIG; goto out; @@ -1891,15 +1882,6 @@ unlock: return ret; } -int -i915_gem_dumb_map_offset(struct drm_file *file, - struct drm_device *dev, - uint32_t handle, - uint64_t *offset) -{ - return i915_gem_mmap_gtt(file, dev, handle, true, offset); -} - /** * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing * @dev: DRM device @@ -1921,7 +1903,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_mmap_gtt *args = data; - return i915_gem_mmap_gtt(file, dev, args->handle, false, &args->offset); + return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset); } static inline int diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index d17ff43..d011ec8 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -473,7 +473,12 @@ mi_set_context(struct intel_engine_cs *ring, u32 hw_flags) { u32 flags = hw_flags | MI_MM_SPACE_GTT; - int ret; + const int num_rings = + /* Use an extended w/a on ivb+ if signalling from other rings */ + i915_semaphore_is_enabled(ring->dev) ? + hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 : + 0; + int len, i, ret; /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value @@ -490,15 +495,31 @@ mi_set_context(struct intel_engine_cs *ring, if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8) flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN); - ret = intel_ring_begin(ring, 6); + + len = 4; + if (INTEL_INFO(ring->dev)->gen >= 7) + len += 2 + (num_rings ? 4*num_rings + 2 : 0); + + ret = intel_ring_begin(ring, len); if (ret) return ret; /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */ - if (INTEL_INFO(ring->dev)->gen >= 7) + if (INTEL_INFO(ring->dev)->gen >= 7) { intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE); - else - intel_ring_emit(ring, MI_NOOP); + if (num_rings) { + struct intel_engine_cs *signaller; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings)); + for_each_ring(signaller, to_i915(ring->dev), i) { + if (signaller == ring) + continue; + + intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); + } + } + } intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_SET_CONTEXT); @@ -510,10 +531,21 @@ mi_set_context(struct intel_engine_cs *ring, */ intel_ring_emit(ring, MI_NOOP); - if (INTEL_INFO(ring->dev)->gen >= 7) + if (INTEL_INFO(ring->dev)->gen >= 7) { + if (num_rings) { + struct intel_engine_cs *signaller; + + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings)); + for_each_ring(signaller, to_i915(ring->dev), i) { + if (signaller == ring) + continue; + + intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); + } + } intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE); - else - intel_ring_emit(ring, MI_NOOP); + } intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f06027b..1173831 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -121,9 +121,6 @@ eb_lookup_vmas(struct eb_vmas *eb, goto err; } - WARN_ONCE(obj->base.dumb, - "GPU use of dumb buffer is illegal.\n"); - drm_gem_object_reference(&obj->base); list_add_tail(&obj->obj_exec_link, &objects); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 981834b..996c293 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -281,10 +281,14 @@ void gen6_enable_rps_interrupts(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; spin_lock_irq(&dev_priv->irq_lock); + WARN_ON(dev_priv->rps.pm_iir); WARN_ON(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); dev_priv->rps.interrupts_enabled = true; + I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) | + dev_priv->pm_rps_events); gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); + spin_unlock_irq(&dev_priv->irq_lock); } @@ -3307,8 +3311,10 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev) GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs); if (INTEL_INFO(dev)->gen >= 6) { - pm_irqs |= dev_priv->pm_rps_events; - + /* + * RPS interrupts will get enabled/disabled on demand when RPS + * itself is enabled/disabled. + */ if (HAS_VEBOX(dev)) pm_irqs |= PM_VEBOX_USER_INTERRUPT; @@ -3520,7 +3526,11 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv) dev_priv->pm_irq_mask = 0xffffffff; GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]); GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]); - GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events); + /* + * RPS interrupts will get enabled/disabled on demand when RPS itself + * is enabled/disabled. + */ + GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0); GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]); } @@ -3609,7 +3619,7 @@ static void vlv_display_irq_uninstall(struct drm_i915_private *dev_priv) vlv_display_irq_reset(dev_priv); - dev_priv->irq_mask = 0; + dev_priv->irq_mask = ~0; } static void valleyview_irq_uninstall(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index eefdc23..172de3b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -395,6 +395,7 @@ #define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) +#define PIPE_CONTROL_MEDIA_STATE_CLEAR (1<<16) #define PIPE_CONTROL_QW_WRITE (1<<14) #define PIPE_CONTROL_POST_SYNC_OP_MASK (3<<14) #define PIPE_CONTROL_DEPTH_STALL (1<<13) @@ -1128,6 +1129,7 @@ enum punit_power_well { #define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) #define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) #define GEN6_NOSYNC 0 +#define RING_PSMI_CTL(base) ((base)+0x50) #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) @@ -1458,6 +1460,7 @@ enum punit_power_well { #define GEN6_BLITTER_FBC_NOTIFY (1<<3) #define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050 +#define GEN6_PSMI_SLEEP_MSG_DISABLE (1 << 0) #define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) #define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1f4b56e..964b28e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6191,6 +6191,20 @@ void intel_cleanup_gt_powersave(struct drm_device *dev) valleyview_cleanup_gt_powersave(dev); } +static void gen6_suspend_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + flush_delayed_work(&dev_priv->rps.delayed_resume_work); + + /* + * TODO: disable RPS interrupts on GEN9+ too once RPS support + * is added for it. + */ + if (INTEL_INFO(dev)->gen < 9) + gen6_disable_rps_interrupts(dev); +} + /** * intel_suspend_gt_powersave - suspend PM work and helper threads * @dev: drm device @@ -6206,14 +6220,7 @@ void intel_suspend_gt_powersave(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 6) return; - flush_delayed_work(&dev_priv->rps.delayed_resume_work); - - /* - * TODO: disable RPS interrupts on GEN9+ too once RPS support - * is added for it. - */ - if (INTEL_INFO(dev)->gen < 9) - gen6_disable_rps_interrupts(dev); + gen6_suspend_rps(dev); /* Force GPU to min freq during suspend */ gen6_rps_idle(dev_priv); @@ -6316,8 +6323,11 @@ void intel_reset_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (INTEL_INFO(dev)->gen < 6) + return; + + gen6_suspend_rps(dev); dev_priv->rps.enabled = false; - intel_enable_gt_powersave(dev); } static void ibx_init_clock_gating(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9f445e9..c7bc93d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -362,12 +362,15 @@ gen7_render_ring_flush(struct intel_engine_cs *ring, flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE; flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE; flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE; + flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR; /* * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; + flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD; + /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache * invalidate bit set. */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index aa87304..94a5bee 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -386,9 +386,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu) msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id); drm_gem_object_unreference(gpu->memptrs_bo); } - if (gpu->pm4) - release_firmware(gpu->pm4); - if (gpu->pfp) - release_firmware(gpu->pfp); + release_firmware(gpu->pm4); + release_firmware(gpu->pfp); msm_gpu_cleanup(&gpu->base); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index fbebb04..b4e70e0 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -141,6 +141,15 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) uint32_t hpd_ctrl; int i, ret; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } + } + ret = gpio_config(hdmi, true); if (ret) { dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret); @@ -164,15 +173,6 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) } } - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_enable(hdmi->hpd_regs[i]); - if (ret) { - dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } - } - hdmi_set_mode(hdmi, false); phy->funcs->reset(phy); hdmi_set_mode(hdmi, true); @@ -200,7 +200,7 @@ fail: return ret; } -static int hdp_disable(struct hdmi_connector *hdmi_connector) +static void hdp_disable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; const struct hdmi_platform_config *config = hdmi->config; @@ -212,28 +212,19 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector) hdmi_set_mode(hdmi, false); - for (i = 0; i < config->hpd_reg_cnt; i++) { - ret = regulator_disable(hdmi->hpd_regs[i]); - if (ret) { - dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n", - config->hpd_reg_names[i], ret); - goto fail; - } - } - for (i = 0; i < config->hpd_clk_cnt; i++) clk_disable_unprepare(hdmi->hpd_clks[i]); ret = gpio_config(hdmi, false); - if (ret) { - dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); - goto fail; - } - - return 0; + if (ret) + dev_warn(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); -fail: - return ret; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_disable(hdmi->hpd_regs[i]); + if (ret) + dev_warn(dev->dev, "failed to disable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + } } static void @@ -260,11 +251,11 @@ void hdmi_connector_irq(struct drm_connector *connector) (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) { bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED); - DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); - - /* ack the irq: */ + /* ack & disable (temporarily) HPD events: */ hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, - hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); + HDMI_HPD_INT_CTRL_INT_ACK); + + DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl); /* detect disconnect if we are connected or visa versa: */ hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index a7672e1..3449213 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -331,17 +331,8 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct drm_device *dev = crtc->dev; - DBG("%s: check", mdp4_crtc->name); - - if (mdp4_crtc->event) { - dev_err(dev->dev, "already pending flip!\n"); - return -EBUSY; - } - // TODO anything else to check? - return 0; } @@ -357,7 +348,7 @@ static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; unsigned long flags; - DBG("%s: flush", mdp4_crtc->name); + DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event); WARN_ON(mdp4_crtc->event); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 0e9a2e3..f021f96 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -303,11 +303,6 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, DBG("%s: check", mdp5_crtc->name); - if (mdp5_crtc->event) { - dev_err(dev->dev, "already pending flip!\n"); - return -EBUSY; - } - /* request a free CTL, if none is already allocated for this CRTC */ if (state->enable && !mdp5_crtc->ctl) { mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc); @@ -364,7 +359,7 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; unsigned long flags; - DBG("%s: flush", mdp5_crtc->name); + DBG("%s: event: %p", mdp5_crtc->name, crtc->state->event); WARN_ON(mdp5_crtc->event); @@ -460,10 +455,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, /* now that we know what irq's we want: */ mdp5_crtc->err.irqmask = intf2err(intf); mdp5_crtc->vblank.irqmask = intf2vblank(intf); - - /* when called from modeset_init(), skip the rest until later: */ - if (!mdp5_kms) - return; + mdp_irq_update(&mdp5_kms->base); spin_lock_irqsave(&mdp5_kms->resource_lock, flags); intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index a11f1b8..9f01a4f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -216,17 +216,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms) goto fail; } - /* NOTE: the vsync and error irq's are actually associated with - * the INTF/encoder.. the easiest way to deal with this (ie. what - * we do now) is assume a fixed relationship between crtc's and - * encoders. I'm not sure if there is ever a need to more freely - * assign crtcs to encoders, but if there is then we need to take - * care of error and vblank irq's that the crtc has registered, - * and also update user-requested vblank_mask. - */ - encoder->possible_crtcs = BIT(0); - mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI); - + encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;; priv->encoders[priv->num_encoders++] = encoder; /* Construct bridge/connector for HDMI: */ diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c index 03455b6..2a73172 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -42,7 +42,10 @@ static void update_irq(struct mdp_kms *mdp_kms) mdp_kms->funcs->set_irqmask(mdp_kms, irqmask); } -static void update_irq_unlocked(struct mdp_kms *mdp_kms) +/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder + * link changes, this must be called to figure out the new global irqmask + */ +void mdp_irq_update(struct mdp_kms *mdp_kms) { unsigned long flags; spin_lock_irqsave(&list_lock, flags); @@ -122,7 +125,7 @@ void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq) spin_unlock_irqrestore(&list_lock, flags); if (needs_update) - update_irq_unlocked(mdp_kms); + mdp_irq_update(mdp_kms); } void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) @@ -141,5 +144,5 @@ void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) spin_unlock_irqrestore(&list_lock, flags); if (needs_update) - update_irq_unlocked(mdp_kms); + mdp_irq_update(mdp_kms); } diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 99557b5..b268ce9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -75,7 +75,7 @@ void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable) void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask); void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq); void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq); - +void mdp_irq_update(struct mdp_kms *mdp_kms); /* * pixel format helpers: diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index f0de412..1919682 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -23,10 +23,41 @@ struct msm_commit { struct drm_atomic_state *state; uint32_t fence; struct msm_fence_cb fence_cb; + uint32_t crtc_mask; }; static void fence_cb(struct msm_fence_cb *cb); +/* block until specified crtcs are no longer pending update, and + * atomically mark them as pending update + */ +static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) +{ + int ret; + + spin_lock(&priv->pending_crtcs_event.lock); + ret = wait_event_interruptible_locked(priv->pending_crtcs_event, + !(priv->pending_crtcs & crtc_mask)); + if (ret == 0) { + DBG("start: %08x", crtc_mask); + priv->pending_crtcs |= crtc_mask; + } + spin_unlock(&priv->pending_crtcs_event.lock); + + return ret; +} + +/* clear specified crtcs (no longer pending update) + */ +static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask) +{ + spin_lock(&priv->pending_crtcs_event.lock); + DBG("end: %08x", crtc_mask); + priv->pending_crtcs &= ~crtc_mask; + wake_up_all_locked(&priv->pending_crtcs_event); + spin_unlock(&priv->pending_crtcs_event.lock); +} + static struct msm_commit *new_commit(struct drm_atomic_state *state) { struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); @@ -58,12 +89,27 @@ static void complete_commit(struct msm_commit *c) drm_atomic_helper_commit_post_planes(dev, state); + /* NOTE: _wait_for_vblanks() only waits for vblank on + * enabled CRTCs. So we end up faulting when disabling + * due to (potentially) unref'ing the outgoing fb's + * before the vblank when the disable has latched. + * + * But if it did wait on disabled (or newly disabled) + * CRTCs, that would be racy (ie. we could have missed + * the irq. We need some way to poll for pipe shut + * down. Or just live with occasionally hitting the + * timeout in the CRTC disable path (which really should + * not be critical path) + */ + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); + end_atomic(dev->dev_private, c->crtc_mask); + kfree(c); } @@ -97,8 +143,9 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { - struct msm_commit *c; int nplanes = dev->mode_config.num_total_plane; + int ncrtcs = dev->mode_config.num_crtc; + struct msm_commit *c; int i, ret; ret = drm_atomic_helper_prepare_planes(dev, state); @@ -106,6 +153,18 @@ int msm_atomic_commit(struct drm_device *dev, return ret; c = new_commit(state); + if (!c) + return -ENOMEM; + + /* + * Figure out what crtcs we have: + */ + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + if (!crtc) + continue; + c->crtc_mask |= (1 << drm_crtc_index(crtc)); + } /* * Figure out what fence to wait for: @@ -122,6 +181,14 @@ int msm_atomic_commit(struct drm_device *dev, } /* + * Wait for pending updates on any of the same crtc's and then + * mark our set of crtc's as busy: + */ + ret = start_atomic(dev->dev_private, c->crtc_mask); + if (ret) + return ret; + + /* * This is the point of no return - everything below never fails except * when the hw goes bonghits. Which means we can commit the new state on * the software side now. diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c795217..9a61546 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -193,6 +193,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) priv->wq = alloc_ordered_workqueue("msm", 0); init_waitqueue_head(&priv->fence_event); + init_waitqueue_head(&priv->pending_crtcs_event); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->fence_cbs); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 1363038..b69ef2d 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -96,6 +96,10 @@ struct msm_drm_private { /* callbacks deferred until bo is inactive: */ struct list_head fence_cbs; + /* crtcs pending async atomic updates: */ + uint32_t pending_crtcs; + wait_queue_head_t pending_crtcs_event; + /* registered MMUs: */ unsigned int num_mmus; struct msm_mmu *mmus[NUM_DOMAINS]; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 94d55e5..1f3af13 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -190,8 +190,7 @@ fail_unlock: fail: if (ret) { - if (fbi) - framebuffer_release(fbi); + framebuffer_release(fbi); if (fb) { drm_framebuffer_unregister_private(fb); drm_framebuffer_remove(fb); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 4a6f0e4..49dea4f 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -535,8 +535,7 @@ void msm_gem_free_object(struct drm_gem_object *obj) drm_free_large(msm_obj->pages); } else { - if (msm_obj->vaddr) - vunmap(msm_obj->vaddr); + vunmap(msm_obj->vaddr); put_pages(obj); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 5d93902..f804243 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -876,7 +876,6 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, if (ret) return ret; - bo->gem.dumb = true; ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle); drm_gem_object_unreference_unlocked(&bo->gem); return ret; @@ -892,14 +891,6 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, gem = drm_gem_object_lookup(dev, file_priv, handle); if (gem) { struct nouveau_bo *bo = nouveau_gem_object(gem); - - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(!(gem->dumb || gem->import_attach), - "Illegal dumb map of accelerated buffer.\n"); - *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node); drm_gem_object_unreference_unlocked(gem); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 28d51a2..42c34ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -444,9 +444,6 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - WARN_ONCE(nvbo->gem.dumb, - "GPU use of dumb buffer is illegal.\n"); - ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains, b->write_domains, b->valid_domains); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 753a6de..3d1cfcb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -28,6 +28,7 @@ #include "nouveau_ttm.h" #include "nouveau_gem.h" +#include "drm_legacy.h" static int nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { @@ -281,7 +282,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) - return -EINVAL; + return drm_legacy_mmap(filp, vma); return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index fe48f22..a46f737 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -394,10 +394,9 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, return r; } -static int radeon_mode_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, bool dumb, - uint64_t *offset_p) +int radeon_mode_dumb_mmap(struct drm_file *filp, + struct drm_device *dev, + uint32_t handle, uint64_t *offset_p) { struct drm_gem_object *gobj; struct radeon_bo *robj; @@ -406,14 +405,6 @@ static int radeon_mode_mmap(struct drm_file *filp, if (gobj == NULL) { return -ENOENT; } - - /* - * We don't allow dumb mmaps on objects created using another - * interface. - */ - WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach), - "Illegal dumb map of GPU buffer.\n"); - robj = gem_to_radeon_bo(gobj); if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) { drm_gem_object_unreference_unlocked(gobj); @@ -424,20 +415,12 @@ static int radeon_mode_mmap(struct drm_file *filp, return 0; } -int radeon_mode_dumb_mmap(struct drm_file *filp, - struct drm_device *dev, - uint32_t handle, uint64_t *offset_p) -{ - return radeon_mode_mmap(filp, dev, handle, true, offset_p); -} - int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct drm_radeon_gem_mmap *args = data; - return radeon_mode_mmap(filp, dev, args->handle, false, - &args->addr_ptr); + return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr); } int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, @@ -763,7 +746,6 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, return -ENOMEM; r = drm_gem_handle_create(file_priv, gobj, &handle); - gobj->dumb = true; /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index 065d020..242fd8b 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -28,6 +28,8 @@ #include "cikd.h" #include "cik_reg.h" #include "radeon_kfd.h" +#include "radeon_ucode.h" +#include #define CIK_PIPE_PER_MEC (4) @@ -49,6 +51,7 @@ static uint64_t get_vmem_size(struct kgd_dev *kgd); static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd); static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd); +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); /* * Register access functions @@ -91,6 +94,7 @@ static const struct kfd2kgd_calls kfd2kgd = { .hqd_load = kgd_hqd_load, .hqd_is_occupies = kgd_hqd_is_occupies, .hqd_destroy = kgd_hqd_destroy, + .get_fw_version = get_fw_version }; static const struct kgd2kfd_calls *kgd2kfd; @@ -561,3 +565,52 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, release_queue(kgd); return 0; } + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct radeon_device *rdev = (struct radeon_device *) kgd; + const union radeon_firmware_header *hdr; + + BUG_ON(kgd == NULL || rdev->mec_fw == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union radeon_firmware_header *) rdev->pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union radeon_firmware_header *) rdev->me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union radeon_firmware_header *) rdev->ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union radeon_firmware_header *) rdev->mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union radeon_firmware_header *) + rdev->mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data; + break; + + case KGD_ENGINE_SDMA: + hdr = (const union radeon_firmware_header *) + rdev->sdma_fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 7d68223..86fc564 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -529,9 +529,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev, u32 current_domain = radeon_mem_type_to_domain(bo->tbo.mem.mem_type); - WARN_ONCE(bo->gem_base.dumb, - "GPU use of dumb buffer is illegal.\n"); - /* Check if this buffer will be moved and don't move it * if we have moved too many buffers for this IB already. * diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 3367960..978993f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, const struct tegra_dc_window *window) { unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; - unsigned long value; + unsigned long value, flags; bool yuv, planar; /* @@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, else bpp = planar ? 1 : 2; + spin_lock_irqsave(&dc->lock, flags); + value = WINDOW_A_SELECT << index; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, case TEGRA_BO_TILING_MODE_BLOCK: DRM_ERROR("hardware doesn't support block linear mode\n"); + spin_unlock_irqrestore(&dc->lock, flags); return -EINVAL; } @@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, tegra_dc_window_commit(dc, index); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane) { struct tegra_dc *dc = to_tegra_dc(plane->crtc); struct tegra_plane *p = to_tegra_plane(plane); + unsigned long flags; u32 value; if (!plane->crtc) return 0; + spin_lock_irqsave(&dc->lock, flags); + value = WINDOW_A_SELECT << p->index; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane) tegra_dc_window_commit(dc, p->index); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); unsigned int h_offset = 0, v_offset = 0; struct tegra_bo_tiling tiling; + unsigned long value, flags; unsigned int format, swap; - unsigned long value; int err; err = tegra_fb_get_tiling(fb, &tiling); if (err < 0) return err; + spin_lock_irqsave(&dc->lock, flags); + tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); value = fb->offsets[0] + y * fb->pitches[0] + @@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, case TEGRA_BO_TILING_MODE_BLOCK: DRM_ERROR("hardware doesn't support block linear mode\n"); + spin_unlock_irqrestore(&dc->lock, flags); return -EINVAL; } @@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); + spin_unlock_irqrestore(&dc->lock, flags); + return 0; } @@ -814,23 +829,32 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc) unsigned long flags, base; struct tegra_bo *bo; - if (!dc->event) + spin_lock_irqsave(&drm->event_lock, flags); + + if (!dc->event) { + spin_unlock_irqrestore(&drm->event_lock, flags); return; + } bo = tegra_fb_get_plane(crtc->primary->fb, 0); + spin_lock_irqsave(&dc->lock, flags); + /* check if new start address has been latched */ + tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); + spin_unlock_irqrestore(&dc->lock, flags); + if (base == bo->paddr + crtc->primary->fb->offsets[0]) { - spin_lock_irqsave(&drm->event_lock, flags); - drm_send_vblank_event(drm, dc->pipe, dc->event); - drm_vblank_put(drm, dc->pipe); + drm_crtc_send_vblank_event(crtc, dc->event); + drm_crtc_vblank_put(crtc); dc->event = NULL; - spin_unlock_irqrestore(&drm->event_lock, flags); } + + spin_unlock_irqrestore(&drm->event_lock, flags); } void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) @@ -843,7 +867,7 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) if (dc->event && dc->event->base.file_priv == file) { dc->event->base.destroy(&dc->event->base); - drm_vblank_put(drm, dc->pipe); + drm_crtc_vblank_put(crtc); dc->event = NULL; } @@ -853,16 +877,16 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) { + unsigned int pipe = drm_crtc_index(crtc); struct tegra_dc *dc = to_tegra_dc(crtc); - struct drm_device *drm = crtc->dev; if (dc->event) return -EBUSY; if (event) { - event->pipe = dc->pipe; + event->pipe = pipe; dc->event = event; - drm_vblank_get(drm, dc->pipe); + drm_crtc_vblank_get(crtc); } tegra_dc_set_base(dc, 0, 0, fb); @@ -1127,7 +1151,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data) /* dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); */ - drm_handle_vblank(dc->base.dev, dc->pipe); + drm_crtc_handle_vblank(&dc->base); tegra_dc_finish_page_flip(dc); } diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index e549afe..d4f8275 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -694,24 +694,28 @@ static const struct file_operations tegra_drm_fops = { .llseek = noop_llseek, }; -static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) +static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, + unsigned int pipe) { struct drm_crtc *crtc; list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { - struct tegra_dc *dc = to_tegra_dc(crtc); - - if (dc->pipe == pipe) + if (pipe == drm_crtc_index(crtc)) return crtc; } return NULL; } -static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) +static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) { + struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); + + if (!crtc) + return 0; + /* TODO: implement real hardware counter using syncpoints */ - return drm_vblank_count(dev, crtc); + return drm_crtc_vblank_count(crtc); } static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index da32086..8777b7f 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -216,32 +216,58 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) } } -static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo, - size_t size) +static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) { + struct scatterlist *s; + struct sg_table *sgt; + unsigned int i; + bo->pages = drm_gem_get_pages(&bo->gem); if (IS_ERR(bo->pages)) return PTR_ERR(bo->pages); - bo->num_pages = size >> PAGE_SHIFT; - - bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); - if (IS_ERR(bo->sgt)) { - drm_gem_put_pages(&bo->gem, bo->pages, false, false); - return PTR_ERR(bo->sgt); + bo->num_pages = bo->gem.size >> PAGE_SHIFT; + + sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); + if (IS_ERR(sgt)) + goto put_pages; + + /* + * Fake up the SG table so that dma_map_sg() can be used to flush the + * pages associated with it. Note that this relies on the fact that + * the DMA API doesn't hook into IOMMU on Tegra, therefore mapping is + * only cache maintenance. + * + * TODO: Replace this by drm_clflash_sg() once it can be implemented + * without relying on symbols that are not exported. + */ + for_each_sg(sgt->sgl, s, sgt->nents, i) + sg_dma_address(s) = sg_phys(s); + + if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) { + sgt = ERR_PTR(-ENOMEM); + goto release_sgt; } + bo->sgt = sgt; + return 0; + +release_sgt: + sg_free_table(sgt); + kfree(sgt); +put_pages: + drm_gem_put_pages(&bo->gem, bo->pages, false, false); + return PTR_ERR(sgt); } -static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo, - size_t size) +static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) { struct tegra_drm *tegra = drm->dev_private; int err; if (tegra->domain) { - err = tegra_bo_get_pages(drm, bo, size); + err = tegra_bo_get_pages(drm, bo); if (err < 0) return err; @@ -251,6 +277,8 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo, return err; } } else { + size_t size = bo->gem.size; + bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, GFP_KERNEL | __GFP_NOWARN); if (!bo->vaddr) { @@ -274,7 +302,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, if (IS_ERR(bo)) return bo; - err = tegra_bo_alloc(drm, bo, size); + err = tegra_bo_alloc(drm, bo); if (err < 0) goto release; diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index 4d20088..4178abe 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -15,12 +15,3 @@ config BCACHE_DEBUG Enables extra debugging tools, allows expensive runtime checks to be turned on. - -config BCACHE_CLOSURES_DEBUG - bool "Debug closures" - depends on BCACHE - select DEBUG_FS - ---help--- - Keeps all active closures in a linked list and provides a debugfs - interface to list them, which makes it possible to see asynchronous - operations that get stuck. diff --git a/drivers/md/bcache/Makefile b/drivers/md/bcache/Makefile index c488b84..25d7aa3 100644 --- a/drivers/md/bcache/Makefile +++ b/drivers/md/bcache/Makefile @@ -1,8 +1,8 @@ obj-$(CONFIG_BCACHE) += bcache.o -bcache-y := alloc.o bset.o btree.o closure.o debug.o extents.o\ - io.o journal.o movinggc.o request.o stats.o super.o sysfs.o trace.o\ - util.o writeback.o +bcache-y := alloc.o bset.o btree.o debug.o extents.o io.o\ + journal.o movinggc.o request.o stats.o super.o sysfs.o trace.o util.o\ + writeback.o CFLAGS_request.o += -Iblock diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 04f7bc2..21efa45 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -179,6 +179,7 @@ #include #include +#include #include #include #include @@ -189,7 +190,6 @@ #include "bset.h" #include "util.h" -#include "closure.h" struct bucket { atomic_t pin; diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c deleted file mode 100644 index 7a228de..0000000 --- a/drivers/md/bcache/closure.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Asynchronous refcounty things - * - * Copyright 2010, 2011 Kent Overstreet - * Copyright 2012 Google, Inc. - */ - -#include -#include -#include - -#include "closure.h" - -static inline void closure_put_after_sub(struct closure *cl, int flags) -{ - int r = flags & CLOSURE_REMAINING_MASK; - - BUG_ON(flags & CLOSURE_GUARD_MASK); - BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR)); - - /* Must deliver precisely one wakeup */ - if (r == 1 && (flags & CLOSURE_SLEEPING)) - wake_up_process(cl->task); - - if (!r) { - if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) { - atomic_set(&cl->remaining, - CLOSURE_REMAINING_INITIALIZER); - closure_queue(cl); - } else { - struct closure *parent = cl->parent; - closure_fn *destructor = cl->fn; - - closure_debug_destroy(cl); - - if (destructor) - destructor(cl); - - if (parent) - closure_put(parent); - } - } -} - -/* For clearing flags with the same atomic op as a put */ -void closure_sub(struct closure *cl, int v) -{ - closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining)); -} -EXPORT_SYMBOL(closure_sub); - -/** - * closure_put - decrement a closure's refcount - */ -void closure_put(struct closure *cl) -{ - closure_put_after_sub(cl, atomic_dec_return(&cl->remaining)); -} -EXPORT_SYMBOL(closure_put); - -/** - * closure_wake_up - wake up all closures on a wait list, without memory barrier - */ -void __closure_wake_up(struct closure_waitlist *wait_list) -{ - struct llist_node *list; - struct closure *cl; - struct llist_node *reverse = NULL; - - list = llist_del_all(&wait_list->list); - - /* We first reverse the list to preserve FIFO ordering and fairness */ - - while (list) { - struct llist_node *t = list; - list = llist_next(list); - - t->next = reverse; - reverse = t; - } - - /* Then do the wakeups */ - - while (reverse) { - cl = container_of(reverse, struct closure, list); - reverse = llist_next(reverse); - - closure_set_waiting(cl, 0); - closure_sub(cl, CLOSURE_WAITING + 1); - } -} -EXPORT_SYMBOL(__closure_wake_up); - -/** - * closure_wait - add a closure to a waitlist - * - * @waitlist will own a ref on @cl, which will be released when - * closure_wake_up() is called on @waitlist. - * - */ -bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl) -{ - if (atomic_read(&cl->remaining) & CLOSURE_WAITING) - return false; - - closure_set_waiting(cl, _RET_IP_); - atomic_add(CLOSURE_WAITING + 1, &cl->remaining); - llist_add(&cl->list, &waitlist->list); - - return true; -} -EXPORT_SYMBOL(closure_wait); - -/** - * closure_sync - sleep until a closure a closure has nothing left to wait on - * - * Sleeps until the refcount hits 1 - the thread that's running the closure owns - * the last refcount. - */ -void closure_sync(struct closure *cl) -{ - while (1) { - __closure_start_sleep(cl); - closure_set_ret_ip(cl); - - if ((atomic_read(&cl->remaining) & - CLOSURE_REMAINING_MASK) == 1) - break; - - schedule(); - } - - __closure_end_sleep(cl); -} -EXPORT_SYMBOL(closure_sync); - -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - -static LIST_HEAD(closure_list); -static DEFINE_SPINLOCK(closure_list_lock); - -void closure_debug_create(struct closure *cl) -{ - unsigned long flags; - - BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE); - cl->magic = CLOSURE_MAGIC_ALIVE; - - spin_lock_irqsave(&closure_list_lock, flags); - list_add(&cl->all, &closure_list); - spin_unlock_irqrestore(&closure_list_lock, flags); -} -EXPORT_SYMBOL(closure_debug_create); - -void closure_debug_destroy(struct closure *cl) -{ - unsigned long flags; - - BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE); - cl->magic = CLOSURE_MAGIC_DEAD; - - spin_lock_irqsave(&closure_list_lock, flags); - list_del(&cl->all); - spin_unlock_irqrestore(&closure_list_lock, flags); -} -EXPORT_SYMBOL(closure_debug_destroy); - -static struct dentry *debug; - -#define work_data_bits(work) ((unsigned long *)(&(work)->data)) - -static int debug_seq_show(struct seq_file *f, void *data) -{ - struct closure *cl; - spin_lock_irq(&closure_list_lock); - - list_for_each_entry(cl, &closure_list, all) { - int r = atomic_read(&cl->remaining); - - seq_printf(f, "%p: %pF -> %pf p %p r %i ", - cl, (void *) cl->ip, cl->fn, cl->parent, - r & CLOSURE_REMAINING_MASK); - - seq_printf(f, "%s%s%s%s\n", - test_bit(WORK_STRUCT_PENDING, - work_data_bits(&cl->work)) ? "Q" : "", - r & CLOSURE_RUNNING ? "R" : "", - r & CLOSURE_STACK ? "S" : "", - r & CLOSURE_SLEEPING ? "Sl" : ""); - - if (r & CLOSURE_WAITING) - seq_printf(f, " W %pF\n", - (void *) cl->waiting_on); - - seq_printf(f, "\n"); - } - - spin_unlock_irq(&closure_list_lock); - return 0; -} - -static int debug_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_seq_show, NULL); -} - -static const struct file_operations debug_ops = { - .owner = THIS_MODULE, - .open = debug_seq_open, - .read = seq_read, - .release = single_release -}; - -void __init closure_debug_init(void) -{ - debug = debugfs_create_file("closures", 0400, NULL, NULL, &debug_ops); -} - -#endif - -MODULE_AUTHOR("Kent Overstreet "); -MODULE_LICENSE("GPL"); diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h deleted file mode 100644 index a08e3ee..0000000 --- a/drivers/md/bcache/closure.h +++ /dev/null @@ -1,386 +0,0 @@ -#ifndef _LINUX_CLOSURE_H -#define _LINUX_CLOSURE_H - -#include -#include -#include - -/* - * Closure is perhaps the most overused and abused term in computer science, but - * since I've been unable to come up with anything better you're stuck with it - * again. - * - * What are closures? - * - * They embed a refcount. The basic idea is they count "things that are in - * progress" - in flight bios, some other thread that's doing something else - - * anything you might want to wait on. - * - * The refcount may be manipulated with closure_get() and closure_put(). - * closure_put() is where many of the interesting things happen, when it causes - * the refcount to go to 0. - * - * Closures can be used to wait on things both synchronously and asynchronously, - * and synchronous and asynchronous use can be mixed without restriction. To - * wait synchronously, use closure_sync() - you will sleep until your closure's - * refcount hits 1. - * - * To wait asynchronously, use - * continue_at(cl, next_function, workqueue); - * - * passing it, as you might expect, the function to run when nothing is pending - * and the workqueue to run that function out of. - * - * continue_at() also, critically, is a macro that returns the calling function. - * There's good reason for this. - * - * To use safely closures asynchronously, they must always have a refcount while - * they are running owned by the thread that is running them. Otherwise, suppose - * you submit some bios and wish to have a function run when they all complete: - * - * foo_endio(struct bio *bio, int error) - * { - * closure_put(cl); - * } - * - * closure_init(cl); - * - * do_stuff(); - * closure_get(cl); - * bio1->bi_endio = foo_endio; - * bio_submit(bio1); - * - * do_more_stuff(); - * closure_get(cl); - * bio2->bi_endio = foo_endio; - * bio_submit(bio2); - * - * continue_at(cl, complete_some_read, system_wq); - * - * If closure's refcount started at 0, complete_some_read() could run before the - * second bio was submitted - which is almost always not what you want! More - * importantly, it wouldn't be possible to say whether the original thread or - * complete_some_read()'s thread owned the closure - and whatever state it was - * associated with! - * - * So, closure_init() initializes a closure's refcount to 1 - and when a - * closure_fn is run, the refcount will be reset to 1 first. - * - * Then, the rule is - if you got the refcount with closure_get(), release it - * with closure_put() (i.e, in a bio->bi_endio function). If you have a refcount - * on a closure because you called closure_init() or you were run out of a - * closure - _always_ use continue_at(). Doing so consistently will help - * eliminate an entire class of particularly pernicious races. - * - * Lastly, you might have a wait list dedicated to a specific event, and have no - * need for specifying the condition - you just want to wait until someone runs - * closure_wake_up() on the appropriate wait list. In that case, just use - * closure_wait(). It will return either true or false, depending on whether the - * closure was already on a wait list or not - a closure can only be on one wait - * list at a time. - * - * Parents: - * - * closure_init() takes two arguments - it takes the closure to initialize, and - * a (possibly null) parent. - * - * If parent is non null, the new closure will have a refcount for its lifetime; - * a closure is considered to be "finished" when its refcount hits 0 and the - * function to run is null. Hence - * - * continue_at(cl, NULL, NULL); - * - * returns up the (spaghetti) stack of closures, precisely like normal return - * returns up the C stack. continue_at() with non null fn is better thought of - * as doing a tail call. - * - * All this implies that a closure should typically be embedded in a particular - * struct (which its refcount will normally control the lifetime of), and that - * struct can very much be thought of as a stack frame. - */ - -struct closure; -typedef void (closure_fn) (struct closure *); - -struct closure_waitlist { - struct llist_head list; -}; - -enum closure_state { - /* - * CLOSURE_WAITING: Set iff the closure is on a waitlist. Must be set by - * the thread that owns the closure, and cleared by the thread that's - * waking up the closure. - * - * CLOSURE_SLEEPING: Must be set before a thread uses a closure to sleep - * - indicates that cl->task is valid and closure_put() may wake it up. - * Only set or cleared by the thread that owns the closure. - * - * The rest are for debugging and don't affect behaviour: - * - * CLOSURE_RUNNING: Set when a closure is running (i.e. by - * closure_init() and when closure_put() runs then next function), and - * must be cleared before remaining hits 0. Primarily to help guard - * against incorrect usage and accidentally transferring references. - * continue_at() and closure_return() clear it for you, if you're doing - * something unusual you can use closure_set_dead() which also helps - * annotate where references are being transferred. - * - * CLOSURE_STACK: Sanity check - remaining should never hit 0 on a - * closure with this flag set - */ - - CLOSURE_BITS_START = (1 << 23), - CLOSURE_DESTRUCTOR = (1 << 23), - CLOSURE_WAITING = (1 << 25), - CLOSURE_SLEEPING = (1 << 27), - CLOSURE_RUNNING = (1 << 29), - CLOSURE_STACK = (1 << 31), -}; - -#define CLOSURE_GUARD_MASK \ - ((CLOSURE_DESTRUCTOR|CLOSURE_WAITING|CLOSURE_SLEEPING| \ - CLOSURE_RUNNING|CLOSURE_STACK) << 1) - -#define CLOSURE_REMAINING_MASK (CLOSURE_BITS_START - 1) -#define CLOSURE_REMAINING_INITIALIZER (1|CLOSURE_RUNNING) - -struct closure { - union { - struct { - struct workqueue_struct *wq; - struct task_struct *task; - struct llist_node list; - closure_fn *fn; - }; - struct work_struct work; - }; - - struct closure *parent; - - atomic_t remaining; - -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG -#define CLOSURE_MAGIC_DEAD 0xc054dead -#define CLOSURE_MAGIC_ALIVE 0xc054a11e - - unsigned magic; - struct list_head all; - unsigned long ip; - unsigned long waiting_on; -#endif -}; - -void closure_sub(struct closure *cl, int v); -void closure_put(struct closure *cl); -void __closure_wake_up(struct closure_waitlist *list); -bool closure_wait(struct closure_waitlist *list, struct closure *cl); -void closure_sync(struct closure *cl); - -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - -void closure_debug_init(void); -void closure_debug_create(struct closure *cl); -void closure_debug_destroy(struct closure *cl); - -#else - -static inline void closure_debug_init(void) {} -static inline void closure_debug_create(struct closure *cl) {} -static inline void closure_debug_destroy(struct closure *cl) {} - -#endif - -static inline void closure_set_ip(struct closure *cl) -{ -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - cl->ip = _THIS_IP_; -#endif -} - -static inline void closure_set_ret_ip(struct closure *cl) -{ -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - cl->ip = _RET_IP_; -#endif -} - -static inline void closure_set_waiting(struct closure *cl, unsigned long f) -{ -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - cl->waiting_on = f; -#endif -} - -static inline void __closure_end_sleep(struct closure *cl) -{ - __set_current_state(TASK_RUNNING); - - if (atomic_read(&cl->remaining) & CLOSURE_SLEEPING) - atomic_sub(CLOSURE_SLEEPING, &cl->remaining); -} - -static inline void __closure_start_sleep(struct closure *cl) -{ - closure_set_ip(cl); - cl->task = current; - set_current_state(TASK_UNINTERRUPTIBLE); - - if (!(atomic_read(&cl->remaining) & CLOSURE_SLEEPING)) - atomic_add(CLOSURE_SLEEPING, &cl->remaining); -} - -static inline void closure_set_stopped(struct closure *cl) -{ - atomic_sub(CLOSURE_RUNNING, &cl->remaining); -} - -static inline void set_closure_fn(struct closure *cl, closure_fn *fn, - struct workqueue_struct *wq) -{ - BUG_ON(object_is_on_stack(cl)); - closure_set_ip(cl); - cl->fn = fn; - cl->wq = wq; - /* between atomic_dec() in closure_put() */ - smp_mb__before_atomic(); -} - -static inline void closure_queue(struct closure *cl) -{ - struct workqueue_struct *wq = cl->wq; - if (wq) { - INIT_WORK(&cl->work, cl->work.func); - BUG_ON(!queue_work(wq, &cl->work)); - } else - cl->fn(cl); -} - -/** - * closure_get - increment a closure's refcount - */ -static inline void closure_get(struct closure *cl) -{ -#ifdef CONFIG_BCACHE_CLOSURES_DEBUG - BUG_ON((atomic_inc_return(&cl->remaining) & - CLOSURE_REMAINING_MASK) <= 1); -#else - atomic_inc(&cl->remaining); -#endif -} - -/** - * closure_init - Initialize a closure, setting the refcount to 1 - * @cl: closure to initialize - * @parent: parent of the new closure. cl will take a refcount on it for its - * lifetime; may be NULL. - */ -static inline void closure_init(struct closure *cl, struct closure *parent) -{ - memset(cl, 0, sizeof(struct closure)); - cl->parent = parent; - if (parent) - closure_get(parent); - - atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER); - - closure_debug_create(cl); - closure_set_ip(cl); -} - -static inline void closure_init_stack(struct closure *cl) -{ - memset(cl, 0, sizeof(struct closure)); - atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER|CLOSURE_STACK); -} - -/** - * closure_wake_up - wake up all closures on a wait list. - */ -static inline void closure_wake_up(struct closure_waitlist *list) -{ - smp_mb(); - __closure_wake_up(list); -} - -/** - * continue_at - jump to another function with barrier - * - * After @cl is no longer waiting on anything (i.e. all outstanding refs have - * been dropped with closure_put()), it will resume execution at @fn running out - * of @wq (or, if @wq is NULL, @fn will be called by closure_put() directly). - * - * NOTE: This macro expands to a return in the calling function! - * - * This is because after calling continue_at() you no longer have a ref on @cl, - * and whatever @cl owns may be freed out from under you - a running closure fn - * has a ref on its own closure which continue_at() drops. - */ -#define continue_at(_cl, _fn, _wq) \ -do { \ - set_closure_fn(_cl, _fn, _wq); \ - closure_sub(_cl, CLOSURE_RUNNING + 1); \ - return; \ -} while (0) - -/** - * closure_return - finish execution of a closure - * - * This is used to indicate that @cl is finished: when all outstanding refs on - * @cl have been dropped @cl's ref on its parent closure (as passed to - * closure_init()) will be dropped, if one was specified - thus this can be - * thought of as returning to the parent closure. - */ -#define closure_return(_cl) continue_at((_cl), NULL, NULL) - -/** - * continue_at_nobarrier - jump to another function without barrier - * - * Causes @fn to be executed out of @cl, in @wq context (or called directly if - * @wq is NULL). - * - * NOTE: like continue_at(), this macro expands to a return in the caller! - * - * The ref the caller of continue_at_nobarrier() had on @cl is now owned by @fn, - * thus it's not safe to touch anything protected by @cl after a - * continue_at_nobarrier(). - */ -#define continue_at_nobarrier(_cl, _fn, _wq) \ -do { \ - set_closure_fn(_cl, _fn, _wq); \ - closure_queue(_cl); \ - return; \ -} while (0) - -/** - * closure_return - finish execution of a closure, with destructor - * - * Works like closure_return(), except @destructor will be called when all - * outstanding refs on @cl have been dropped; @destructor may be used to safely - * free the memory occupied by @cl, and it is called with the ref on the parent - * closure still held - so @destructor could safely return an item to a - * freelist protected by @cl's parent. - */ -#define closure_return_with_destructor(_cl, _destructor) \ -do { \ - set_closure_fn(_cl, _destructor, NULL); \ - closure_sub(_cl, CLOSURE_RUNNING - CLOSURE_DESTRUCTOR + 1); \ - return; \ -} while (0) - -/** - * closure_call - execute @fn out of a new, uninitialized closure - * - * Typically used when running out of one closure, and we want to run @fn - * asynchronously out of a new closure - @parent will then wait for @cl to - * finish. - */ -static inline void closure_call(struct closure *cl, closure_fn fn, - struct workqueue_struct *wq, - struct closure *parent) -{ - closure_init(cl, parent); - continue_at_nobarrier(cl, fn, wq); -} - -#endif /* _LINUX_CLOSURE_H */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 4dd2bb7..085c535 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2097,7 +2097,6 @@ static int __init bcache_init(void) mutex_init(&bch_register_lock); init_waitqueue_head(&unregister_wait); register_reboot_notifier(&reboot); - closure_debug_init(); bcache_major = register_blkdev(0, "bcache"); if (bcache_major < 0) diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h index 98df757..6cd43c8 100644 --- a/drivers/md/bcache/util.h +++ b/drivers/md/bcache/util.h @@ -3,6 +3,7 @@ #define _BCACHE_UTIL_H #include +#include #include #include #include @@ -10,8 +11,6 @@ #include #include -#include "closure.h" - #define PAGE_SECTORS (PAGE_SIZE / 512) struct closure; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 8735543..4934789 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1127,6 +1127,24 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, schedule_zero(tc, virt_block, data_dest, cell, bio); } +static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); + +static void check_for_space(struct pool *pool) +{ + int r; + dm_block_t nr_free; + + if (get_pool_mode(pool) != PM_OUT_OF_DATA_SPACE) + return; + + r = dm_pool_get_free_block_count(pool->pmd, &nr_free); + if (r) + return; + + if (nr_free) + set_pool_mode(pool, PM_WRITE); +} + /* * A non-zero return indicates read_only or fail_io mode. * Many callers don't care about the return value. @@ -1141,6 +1159,8 @@ static int commit(struct pool *pool) r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); + else + check_for_space(pool); return r; } @@ -1159,8 +1179,6 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks) } } -static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); - static int alloc_data_block(struct thin_c *tc, dm_block_t *result) { int r; @@ -2155,7 +2173,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) pool->process_cell = process_cell_read_only; pool->process_discard_cell = process_discard_cell; pool->process_prepared_mapping = process_prepared_mapping; - pool->process_prepared_discard = process_prepared_discard_passdown; + pool->process_prepared_discard = process_prepared_discard; if (!pool->pf.error_if_no_space && no_space_timeout) queue_delayed_work(pool->wq, &pool->no_space_timeout, no_space_timeout); @@ -3814,6 +3832,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = -EINVAL; goto bad; } + atomic_set(&tc->refcount, 1); + init_completion(&tc->can_destroy); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); spin_unlock_irqrestore(&tc->pool->lock, flags); /* @@ -3826,9 +3846,6 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) dm_put(pool_md); - atomic_set(&tc->refcount, 1); - init_completion(&tc->can_destroy); - return 0; bad: diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4c06585..b98cd9d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -899,7 +899,7 @@ static void disable_write_same(struct mapped_device *md) static void clone_endio(struct bio *bio, int error) { - int r = 0; + int r = error; struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); struct dm_io *io = tio->io; struct mapped_device *md = tio->io->md; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 184c434..0dceba1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1648,7 +1648,7 @@ static int __bond_release_one(struct net_device *bond_dev, /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || !netdev_has_upper_dev(slave_dev, bond_dev)) { - netdev_err(bond_dev, "cannot release %s\n", + netdev_dbg(bond_dev, "cannot release %s\n", slave_dev->name); return -EINVAL; } diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c index a5fefb9..b306210 100644 --- a/drivers/net/caif/caif_virtio.c +++ b/drivers/net/caif/caif_virtio.c @@ -257,7 +257,6 @@ static int cfv_rx_poll(struct napi_struct *napi, int quota) struct vringh_kiov *riov = &cfv->ctx.riov; unsigned int skb_len; -again: do { skb = NULL; @@ -322,7 +321,6 @@ exit: napi_schedule_prep(napi)) { vringh_notify_disable_kern(cfv->vr_rx); __napi_schedule(napi); - goto again; } break; diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 89c8d9f..57e9791 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -246,13 +246,13 @@ static int ne2k_pci_init_one(struct pci_dev *pdev, if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) { dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n"); - return -ENODEV; + goto err_out; } if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) { dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n", NE_IO_EXTENT, ioaddr); - return -EBUSY; + goto err_out; } reg0 = inb(ioaddr); @@ -392,6 +392,8 @@ err_out_free_netdev: free_netdev (dev); err_out_free_res: release_region (ioaddr, NE_IO_EXTENT); +err_out: + pci_disable_device(pdev); return -ENODEV; } diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index df76050..eadcb05 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -156,18 +156,6 @@ source "drivers/net/ethernet/realtek/Kconfig" source "drivers/net/ethernet/renesas/Kconfig" source "drivers/net/ethernet/rdc/Kconfig" source "drivers/net/ethernet/rocker/Kconfig" - -config S6GMAC - tristate "S6105 GMAC ethernet support" - depends on XTENSA_VARIANT_S6000 - select PHYLIB - ---help--- - This driver supports the on chip ethernet device on the - S6105 xtensa processor. - - To compile this driver as a module, choose M here. The module - will be called s6gmac. - source "drivers/net/ethernet/samsung/Kconfig" source "drivers/net/ethernet/seeq/Kconfig" source "drivers/net/ethernet/silan/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index bf56f8b..1367afc 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/ obj-$(CONFIG_SH_ETH) += renesas/ obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/ -obj-$(CONFIG_S6GMAC) += s6gmac.o obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/ obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 9f5e387..72eef9f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12553,9 +12553,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev, return 0; } -static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t bnx2x_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } static const struct net_device_ops bnx2x_netdev_ops = { @@ -12589,7 +12591,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { #endif .ndo_get_phys_port_id = bnx2x_get_phys_port_id, .ndo_set_vf_link_state = bnx2x_set_vf_link_state, - .ndo_gso_check = bnx2x_gso_check, + .ndo_features_check = bnx2x_features_check, }; static int bnx2x_set_coherency_mask(struct bnx2x *bp) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index bb48a61..553dcd8 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17800,23 +17800,6 @@ static int tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - /* - * Reset chip in case UNDI or EFI driver did not shutdown - * DMA self test will enable WDMAC and we'll see (spurious) - * pending DMA on the PCI bus at that point. - */ - if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || - (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - } - - err = tg3_test_dma(tp); - if (err) { - dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); - goto err_out_apeunmap; - } - intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW; rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW; sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW; @@ -17861,6 +17844,23 @@ static int tg3_init_one(struct pci_dev *pdev, sndmbx += 0xc; } + /* + * Reset chip in case UNDI or EFI driver did not shutdown + * DMA self test will enable WDMAC and we'll see (spurious) + * pending DMA on the PCI bus at that point. + */ + if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || + (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + } + + err = tg3_test_dma(tp); + if (err) { + dev_err(&pdev->dev, "DMA engine test failed, aborting\n"); + goto err_out_apeunmap; + } + tg3_init_coal(tp); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 7d6aa8c..619083a 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -172,7 +172,7 @@ bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len) /* Retrieve flash partition info */ fcomp.comp_status = 0; - init_completion(&fcomp.comp); + reinit_completion(&fcomp.comp); spin_lock_irqsave(&bnad->bna_lock, flags); ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr, bnad_cb_completion, &fcomp); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h index d00a751..6049f70 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h @@ -96,6 +96,9 @@ struct port_info { s16 xact_addr_filt; /* index of our MAC address filter */ u16 rss_size; /* size of VI's RSS table slice */ u8 pidx; /* index into adapter port[] */ + s8 mdio_addr; + u8 port_type; /* firmware port type */ + u8 mod_type; /* firmware module type */ u8 port_id; /* physical port ID */ u8 nqsets; /* # of "Queue Sets" */ u8 first_qset; /* index of first "Queue Set" */ @@ -522,6 +525,7 @@ static inline struct adapter *netdev2adap(const struct net_device *dev) * is "contracted" to provide for the common code. */ void t4vf_os_link_changed(struct adapter *, int, int); +void t4vf_os_portmod_changed(struct adapter *, int); /* * SGE function prototype declarations. diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index aa74ec3..2215d43 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "t4vf_common.h" #include "t4vf_defs.h" @@ -210,6 +211,38 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) } /* + * THe port module type has changed on the indicated "port" (Virtual + * Interface). + */ +void t4vf_os_portmod_changed(struct adapter *adapter, int pidx) +{ + static const char * const mod_str[] = { + NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" + }; + const struct net_device *dev = adapter->port[pidx]; + const struct port_info *pi = netdev_priv(dev); + + if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) + dev_info(adapter->pdev_dev, "%s: port module unplugged\n", + dev->name); + else if (pi->mod_type < ARRAY_SIZE(mod_str)) + dev_info(adapter->pdev_dev, "%s: %s port module inserted\n", + dev->name, mod_str[pi->mod_type]); + else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) + dev_info(adapter->pdev_dev, "%s: unsupported optical port " + "module inserted\n", dev->name); + else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) + dev_info(adapter->pdev_dev, "%s: unknown port module inserted," + "forcing TWINAX\n", dev->name); + else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR) + dev_info(adapter->pdev_dev, "%s: transceiver module error\n", + dev->name); + else + dev_info(adapter->pdev_dev, "%s: unknown module type %d " + "inserted\n", dev->name, pi->mod_type); +} + +/* * Net device operations. * ====================== */ @@ -1193,24 +1226,103 @@ static void cxgb4vf_poll_controller(struct net_device *dev) * state of the port to which we're linked. */ -/* - * Return current port link settings. - */ -static int cxgb4vf_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - const struct port_info *pi = netdev_priv(dev); +static unsigned int t4vf_from_fw_linkcaps(enum fw_port_type type, + unsigned int caps) +{ + unsigned int v = 0; + + if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || + type == FW_PORT_TYPE_BT_XAUI) { + v |= SUPPORTED_TP; + if (caps & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { + v |= SUPPORTED_Backplane; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseKX_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_KR) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; + else if (type == FW_PORT_TYPE_BP_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; + else if (type == FW_PORT_TYPE_BP4_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | + SUPPORTED_10000baseKX4_Full; + else if (type == FW_PORT_TYPE_FIBER_XFI || + type == FW_PORT_TYPE_FIBER_XAUI || + type == FW_PORT_TYPE_SFP || + type == FW_PORT_TYPE_QSFP_10G || + type == FW_PORT_TYPE_QSA) { + v |= SUPPORTED_FIBRE; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_BP40_BA || + type == FW_PORT_TYPE_QSFP) { + v |= SUPPORTED_40000baseSR4_Full; + v |= SUPPORTED_FIBRE; + } + + if (caps & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + return v; +} + +static int cxgb4vf_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + const struct port_info *p = netdev_priv(dev); + + if (p->port_type == FW_PORT_TYPE_BT_SGMII || + p->port_type == FW_PORT_TYPE_BT_XFI || + p->port_type == FW_PORT_TYPE_BT_XAUI) + cmd->port = PORT_TP; + else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || + p->port_type == FW_PORT_TYPE_FIBER_XAUI) + cmd->port = PORT_FIBRE; + else if (p->port_type == FW_PORT_TYPE_SFP || + p->port_type == FW_PORT_TYPE_QSFP_10G || + p->port_type == FW_PORT_TYPE_QSA || + p->port_type == FW_PORT_TYPE_QSFP) { + if (p->mod_type == FW_PORT_MOD_TYPE_LR || + p->mod_type == FW_PORT_MOD_TYPE_SR || + p->mod_type == FW_PORT_MOD_TYPE_ER || + p->mod_type == FW_PORT_MOD_TYPE_LRM) + cmd->port = PORT_FIBRE; + else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || + p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) + cmd->port = PORT_DA; + else + cmd->port = PORT_OTHER; + } else + cmd->port = PORT_OTHER; - cmd->supported = pi->link_cfg.supported; - cmd->advertising = pi->link_cfg.advertising; + if (p->mdio_addr >= 0) { + cmd->phy_address = p->mdio_addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? + MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; + } else { + cmd->phy_address = 0; /* not really, but no better option */ + cmd->transceiver = XCVR_INTERNAL; + cmd->mdio_support = 0; + } + + cmd->supported = t4vf_from_fw_linkcaps(p->port_type, + p->link_cfg.supported); + cmd->advertising = t4vf_from_fw_linkcaps(p->port_type, + p->link_cfg.advertising); ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); cmd->duplex = DUPLEX_FULL; - - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = pi->port_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = pi->link_cfg.autoneg; + cmd->autoneg = p->link_cfg.autoneg; cmd->maxtxpkt = 0; cmd->maxrxpkt = 0; return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h index 8d3237f..b9debb4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h @@ -230,7 +230,7 @@ struct adapter_params { static inline bool is_10g_port(const struct link_config *lc) { - return (lc->supported & SUPPORTED_10000baseT_Full) != 0; + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; } static inline bool is_x_10g_port(const struct link_config *lc) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 02e8833..21dc9a2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -245,6 +245,10 @@ static int hash_mac_addr(const u8 *addr) return a & 0x3f; } +#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ + FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG) + /** * init_link_config - initialize a link's SW state * @lc: structure holding the link state @@ -259,8 +263,8 @@ static void init_link_config(struct link_config *lc, unsigned int caps) lc->requested_speed = 0; lc->speed = 0; lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising = lc->supported; + if (lc->supported & FW_PORT_CAP_ANEG) { + lc->advertising = lc->supported & ADVERT_MASK; lc->autoneg = AUTONEG_ENABLE; lc->requested_fc |= PAUSE_AUTONEG; } else { @@ -280,7 +284,6 @@ int t4vf_port_init(struct adapter *adapter, int pidx) struct fw_vi_cmd vi_cmd, vi_rpl; struct fw_port_cmd port_cmd, port_rpl; int v; - u32 word; /* * Execute a VI Read command to get our Virtual Interface information @@ -319,19 +322,11 @@ int t4vf_port_init(struct adapter *adapter, int pidx) if (v) return v; - v = 0; - word = be16_to_cpu(port_rpl.u.info.pcap); - if (word & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (word & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (word & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - if (word & FW_PORT_CAP_SPEED_40G) - v |= SUPPORTED_40000baseSR4_Full; - if (word & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - init_link_config(&pi->link_cfg, v); + v = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype); + pi->port_type = FW_PORT_CMD_PTYPE_G(v); + pi->mod_type = FW_PORT_MOD_TYPE_NA; + + init_link_config(&pi->link_cfg, be16_to_cpu(port_rpl.u.info.pcap)); return 0; } @@ -1491,7 +1486,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) */ const struct fw_port_cmd *port_cmd = (const struct fw_port_cmd *)rpl; - u32 word; + u32 stat, mod; int action, port_id, link_ok, speed, fc, pidx; /* @@ -1509,21 +1504,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) port_id = FW_PORT_CMD_PORTID_G( be32_to_cpu(port_cmd->op_to_portid)); - word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); - link_ok = (word & FW_PORT_CMD_LSTATUS_F) != 0; + stat = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); + link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0; speed = 0; fc = 0; - if (word & FW_PORT_CMD_RXPAUSE_F) + if (stat & FW_PORT_CMD_RXPAUSE_F) fc |= PAUSE_RX; - if (word & FW_PORT_CMD_TXPAUSE_F) + if (stat & FW_PORT_CMD_TXPAUSE_F) fc |= PAUSE_TX; - if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) + if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M)) speed = 100; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G)) speed = 1000; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G)) speed = 10000; - else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) + else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G)) speed = 40000; /* @@ -1540,12 +1535,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) continue; lc = &pi->link_cfg; + + mod = FW_PORT_CMD_MODTYPE_G(stat); + if (mod != pi->mod_type) { + pi->mod_type = mod; + t4vf_os_portmod_changed(adapter, pidx); + } + if (link_ok != lc->link_ok || speed != lc->speed || fc != lc->fc) { /* something changed */ lc->link_ok = link_ok; lc->speed = speed; lc->fc = fc; + lc->supported = + be16_to_cpu(port_cmd->u.info.pcap); t4vf_os_link_changed(adapter, pidx, link_ok); } } diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 868d0f6..705f334 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1060,10 +1060,14 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); } - if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) { - skb->csum = htons(checksum); - skb->ip_summed = CHECKSUM_COMPLETE; - } + /* Hardware does not provide whole packet checksum. It only + * provides pseudo checksum. Since hw validates the packet + * checksum but not provide us the checksum value. use + * CHECSUM_UNNECESSARY. + */ + if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok && + ipv4_csum_ok) + skb->ip_summed = CHECKSUM_UNNECESSARY; if (vlan_stripped) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 1960731..41a0a54 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4459,9 +4459,11 @@ done: adapter->vxlan_port_count--; } -static bool be_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t be_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -4492,7 +4494,7 @@ static const struct net_device_ops be_netdev_ops = { #ifdef CONFIG_BE2NET_VXLAN .ndo_add_vxlan_port = be_add_vxlan_port, .ndo_del_vxlan_port = be_del_vxlan_port, - .ndo_gso_check = be_gso_check, + .ndo_features_check = be_features_check, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 190cbd9..d0d6dc1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2365,9 +2365,11 @@ static void mlx4_en_del_vxlan_port(struct net_device *dev, queue_work(priv->mdev->workqueue, &priv->vxlan_del_task); } -static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t mlx4_en_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -2400,7 +2402,7 @@ static const struct net_device_ops mlx4_netdev_ops = { #ifdef CONFIG_MLX4_EN_VXLAN .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, - .ndo_gso_check = mlx4_en_gso_check, + .ndo_features_check = mlx4_en_features_check, #endif }; @@ -2434,7 +2436,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { #ifdef CONFIG_MLX4_EN_VXLAN .ndo_add_vxlan_port = mlx4_en_add_vxlan_port, .ndo_del_vxlan_port = mlx4_en_del_vxlan_port, - .ndo_gso_check = mlx4_en_gso_check, + .ndo_features_check = mlx4_en_features_check, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index a308d41..e3357bf 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -962,7 +962,17 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) tx_desc->ctrl.owner_opcode = op_own; if (send_doorbell) { wmb(); - iowrite32(ring->doorbell_qpn, + /* Since there is no iowrite*_native() that writes the + * value as is, without byteswapping - using the one + * the doesn't do byteswapping in the relevant arch + * endianness. + */ +#if defined(__LITTLE_ENDIAN) + iowrite32( +#else + iowrite32be( +#endif + ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); } else { ring->xmit_more++; diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index f1ebed6c..2fa6ae0 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -2303,12 +2303,6 @@ static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p) /* Spanning Tree */ -static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set) -{ - port_cfg(hw, p, - KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set); -} - static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set) { port_cfg(hw, p, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1aa25b1..9929b97 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -505,9 +505,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev, adapter->flags |= QLCNIC_DEL_VXLAN_PORT; } -static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev) +static netdev_features_t qlcnic_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) { - return vxlan_gso_check(skb); + return vxlan_features_check(skb, features); } #endif @@ -532,7 +534,7 @@ static const struct net_device_ops qlcnic_netdev_ops = { #ifdef CONFIG_QLCNIC_VXLAN .ndo_add_vxlan_port = qlcnic_add_vxlan_port, .ndo_del_vxlan_port = qlcnic_del_vxlan_port, - .ndo_gso_check = qlcnic_gso_check, + .ndo_features_check = qlcnic_features_check, #endif #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = qlcnic_poll_controller, diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 6d0b9df..78bb4ce 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -787,10 +787,10 @@ static struct net_device *rtl8139_init_board(struct pci_dev *pdev) if (rc) goto err_out; + disable_dev_on_err = 1; rc = pci_request_regions (pdev, DRV_NAME); if (rc) goto err_out; - disable_dev_on_err = 1; pci_set_master (pdev); @@ -1110,6 +1110,7 @@ static int rtl8139_init_one(struct pci_dev *pdev, return 0; err_out: + netif_napi_del(&tp->napi); __rtl8139_cleanup_dev (dev); pci_disable_device (pdev); return i; @@ -1124,6 +1125,7 @@ static void rtl8139_remove_one(struct pci_dev *pdev) assert (dev != NULL); cancel_delayed_work_sync(&tp->thread); + netif_napi_del(&tp->napi); unregister_netdev (dev); diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c deleted file mode 100644 index f537cbe..0000000 --- a/drivers/net/ethernet/s6gmac.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Ethernet driver for S6105 on chip network device - * (c)2008 emlix GmbH http://www.emlix.com - * Authors: Oskar Schirmer - * Daniel Gloeckner - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "s6gmac" -#define DRV_PRMT DRV_NAME ": " - - -/* register declarations */ - -#define S6_GMAC_MACCONF1 0x000 -#define S6_GMAC_MACCONF1_TXENA 0 -#define S6_GMAC_MACCONF1_SYNCTX 1 -#define S6_GMAC_MACCONF1_RXENA 2 -#define S6_GMAC_MACCONF1_SYNCRX 3 -#define S6_GMAC_MACCONF1_TXFLOWCTRL 4 -#define S6_GMAC_MACCONF1_RXFLOWCTRL 5 -#define S6_GMAC_MACCONF1_LOOPBACK 8 -#define S6_GMAC_MACCONF1_RESTXFUNC 16 -#define S6_GMAC_MACCONF1_RESRXFUNC 17 -#define S6_GMAC_MACCONF1_RESTXMACCTRL 18 -#define S6_GMAC_MACCONF1_RESRXMACCTRL 19 -#define S6_GMAC_MACCONF1_SIMULRES 30 -#define S6_GMAC_MACCONF1_SOFTRES 31 -#define S6_GMAC_MACCONF2 0x004 -#define S6_GMAC_MACCONF2_FULL 0 -#define S6_GMAC_MACCONF2_CRCENA 1 -#define S6_GMAC_MACCONF2_PADCRCENA 2 -#define S6_GMAC_MACCONF2_LENGTHFCHK 4 -#define S6_GMAC_MACCONF2_HUGEFRAMENA 5 -#define S6_GMAC_MACCONF2_IFMODE 8 -#define S6_GMAC_MACCONF2_IFMODE_NIBBLE 1 -#define S6_GMAC_MACCONF2_IFMODE_BYTE 2 -#define S6_GMAC_MACCONF2_IFMODE_MASK 3 -#define S6_GMAC_MACCONF2_PREAMBLELEN 12 -#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK 0x0F -#define S6_GMAC_MACIPGIFG 0x008 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP 0 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK 0x7F -#define S6_GMAC_MACIPGIFG_MINIFGENFORCE 8 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2 16 -#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1 24 -#define S6_GMAC_MACHALFDUPLEX 0x00C -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN 0 -#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK 0x3F -#define S6_GMAC_MACHALFDUPLEX_RETXMAX 12 -#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK 0x0F -#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF 16 -#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF 17 -#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF 18 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA 19 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN 20 -#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK 0x0F -#define S6_GMAC_MACMAXFRAMELEN 0x010 -#define S6_GMAC_MACMIICONF 0x020 -#define S6_GMAC_MACMIICONF_CSEL 0 -#define S6_GMAC_MACMIICONF_CSEL_DIV10 0 -#define S6_GMAC_MACMIICONF_CSEL_DIV12 1 -#define S6_GMAC_MACMIICONF_CSEL_DIV14 2 -#define S6_GMAC_MACMIICONF_CSEL_DIV18 3 -#define S6_GMAC_MACMIICONF_CSEL_DIV24 4 -#define S6_GMAC_MACMIICONF_CSEL_DIV34 5 -#define S6_GMAC_MACMIICONF_CSEL_DIV68 6 -#define S6_GMAC_MACMIICONF_CSEL_DIV168 7 -#define S6_GMAC_MACMIICONF_CSEL_MASK 7 -#define S6_GMAC_MACMIICONF_PREAMBLESUPR 4 -#define S6_GMAC_MACMIICONF_SCANAUTOINCR 5 -#define S6_GMAC_MACMIICMD 0x024 -#define S6_GMAC_MACMIICMD_READ 0 -#define S6_GMAC_MACMIICMD_SCAN 1 -#define S6_GMAC_MACMIIADDR 0x028 -#define S6_GMAC_MACMIIADDR_REG 0 -#define S6_GMAC_MACMIIADDR_REG_MASK 0x1F -#define S6_GMAC_MACMIIADDR_PHY 8 -#define S6_GMAC_MACMIIADDR_PHY_MASK 0x1F -#define S6_GMAC_MACMIICTRL 0x02C -#define S6_GMAC_MACMIISTAT 0x030 -#define S6_GMAC_MACMIIINDI 0x034 -#define S6_GMAC_MACMIIINDI_BUSY 0 -#define S6_GMAC_MACMIIINDI_SCAN 1 -#define S6_GMAC_MACMIIINDI_INVAL 2 -#define S6_GMAC_MACINTERFSTAT 0x03C -#define S6_GMAC_MACINTERFSTAT_LINKFAIL 3 -#define S6_GMAC_MACINTERFSTAT_EXCESSDEF 9 -#define S6_GMAC_MACSTATADDR1 0x040 -#define S6_GMAC_MACSTATADDR2 0x044 - -#define S6_GMAC_FIFOCONF0 0x048 -#define S6_GMAC_FIFOCONF0_HSTRSTWT 0 -#define S6_GMAC_FIFOCONF0_HSTRSTSR 1 -#define S6_GMAC_FIFOCONF0_HSTRSTFR 2 -#define S6_GMAC_FIFOCONF0_HSTRSTST 3 -#define S6_GMAC_FIFOCONF0_HSTRSTFT 4 -#define S6_GMAC_FIFOCONF0_WTMENREQ 8 -#define S6_GMAC_FIFOCONF0_SRFENREQ 9 -#define S6_GMAC_FIFOCONF0_FRFENREQ 10 -#define S6_GMAC_FIFOCONF0_STFENREQ 11 -#define S6_GMAC_FIFOCONF0_FTFENREQ 12 -#define S6_GMAC_FIFOCONF0_WTMENRPLY 16 -#define S6_GMAC_FIFOCONF0_SRFENRPLY 17 -#define S6_GMAC_FIFOCONF0_FRFENRPLY 18 -#define S6_GMAC_FIFOCONF0_STFENRPLY 19 -#define S6_GMAC_FIFOCONF0_FTFENRPLY 20 -#define S6_GMAC_FIFOCONF1 0x04C -#define S6_GMAC_FIFOCONF2 0x050 -#define S6_GMAC_FIFOCONF2_CFGLWM 0 -#define S6_GMAC_FIFOCONF2_CFGHWM 16 -#define S6_GMAC_FIFOCONF3 0x054 -#define S6_GMAC_FIFOCONF3_CFGFTTH 0 -#define S6_GMAC_FIFOCONF3_CFGHWMFT 16 -#define S6_GMAC_FIFOCONF4 0x058 -#define S6_GMAC_FIFOCONF_RSV_PREVDROP 0 -#define S6_GMAC_FIFOCONF_RSV_RUNT 1 -#define S6_GMAC_FIFOCONF_RSV_FALSECAR 2 -#define S6_GMAC_FIFOCONF_RSV_CODEERR 3 -#define S6_GMAC_FIFOCONF_RSV_CRCERR 4 -#define S6_GMAC_FIFOCONF_RSV_LENGTHERR 5 -#define S6_GMAC_FIFOCONF_RSV_LENRANGE 6 -#define S6_GMAC_FIFOCONF_RSV_OK 7 -#define S6_GMAC_FIFOCONF_RSV_MULTICAST 8 -#define S6_GMAC_FIFOCONF_RSV_BROADCAST 9 -#define S6_GMAC_FIFOCONF_RSV_DRIBBLE 10 -#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME 11 -#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL 12 -#define S6_GMAC_FIFOCONF_RSV_UNOPCODE 13 -#define S6_GMAC_FIFOCONF_RSV_VLANTAG 14 -#define S6_GMAC_FIFOCONF_RSV_LONGEVENT 15 -#define S6_GMAC_FIFOCONF_RSV_TRUNCATED 16 -#define S6_GMAC_FIFOCONF_RSV_MASK 0x3FFFF -#define S6_GMAC_FIFOCONF5 0x05C -#define S6_GMAC_FIFOCONF5_DROPLT64 18 -#define S6_GMAC_FIFOCONF5_CFGBYTM 19 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE 20 -#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK 0xF - -#define S6_GMAC_STAT_REGS 0x080 -#define S6_GMAC_STAT_SIZE_MIN 12 -#define S6_GMAC_STATTR64 0x080 -#define S6_GMAC_STATTR64_SIZE 18 -#define S6_GMAC_STATTR127 0x084 -#define S6_GMAC_STATTR127_SIZE 18 -#define S6_GMAC_STATTR255 0x088 -#define S6_GMAC_STATTR255_SIZE 18 -#define S6_GMAC_STATTR511 0x08C -#define S6_GMAC_STATTR511_SIZE 18 -#define S6_GMAC_STATTR1K 0x090 -#define S6_GMAC_STATTR1K_SIZE 18 -#define S6_GMAC_STATTRMAX 0x094 -#define S6_GMAC_STATTRMAX_SIZE 18 -#define S6_GMAC_STATTRMGV 0x098 -#define S6_GMAC_STATTRMGV_SIZE 18 -#define S6_GMAC_STATRBYT 0x09C -#define S6_GMAC_STATRBYT_SIZE 24 -#define S6_GMAC_STATRPKT 0x0A0 -#define S6_GMAC_STATRPKT_SIZE 18 -#define S6_GMAC_STATRFCS 0x0A4 -#define S6_GMAC_STATRFCS_SIZE 12 -#define S6_GMAC_STATRMCA 0x0A8 -#define S6_GMAC_STATRMCA_SIZE 18 -#define S6_GMAC_STATRBCA 0x0AC -#define S6_GMAC_STATRBCA_SIZE 22 -#define S6_GMAC_STATRXCF 0x0B0 -#define S6_GMAC_STATRXCF_SIZE 18 -#define S6_GMAC_STATRXPF 0x0B4 -#define S6_GMAC_STATRXPF_SIZE 12 -#define S6_GMAC_STATRXUO 0x0B8 -#define S6_GMAC_STATRXUO_SIZE 12 -#define S6_GMAC_STATRALN 0x0BC -#define S6_GMAC_STATRALN_SIZE 12 -#define S6_GMAC_STATRFLR 0x0C0 -#define S6_GMAC_STATRFLR_SIZE 16 -#define S6_GMAC_STATRCDE 0x0C4 -#define S6_GMAC_STATRCDE_SIZE 12 -#define S6_GMAC_STATRCSE 0x0C8 -#define S6_GMAC_STATRCSE_SIZE 12 -#define S6_GMAC_STATRUND 0x0CC -#define S6_GMAC_STATRUND_SIZE 12 -#define S6_GMAC_STATROVR 0x0D0 -#define S6_GMAC_STATROVR_SIZE 12 -#define S6_GMAC_STATRFRG 0x0D4 -#define S6_GMAC_STATRFRG_SIZE 12 -#define S6_GMAC_STATRJBR 0x0D8 -#define S6_GMAC_STATRJBR_SIZE 12 -#define S6_GMAC_STATRDRP 0x0DC -#define S6_GMAC_STATRDRP_SIZE 12 -#define S6_GMAC_STATTBYT 0x0E0 -#define S6_GMAC_STATTBYT_SIZE 24 -#define S6_GMAC_STATTPKT 0x0E4 -#define S6_GMAC_STATTPKT_SIZE 18 -#define S6_GMAC_STATTMCA 0x0E8 -#define S6_GMAC_STATTMCA_SIZE 18 -#define S6_GMAC_STATTBCA 0x0EC -#define S6_GMAC_STATTBCA_SIZE 18 -#define S6_GMAC_STATTXPF 0x0F0 -#define S6_GMAC_STATTXPF_SIZE 12 -#define S6_GMAC_STATTDFR 0x0F4 -#define S6_GMAC_STATTDFR_SIZE 12 -#define S6_GMAC_STATTEDF 0x0F8 -#define S6_GMAC_STATTEDF_SIZE 12 -#define S6_GMAC_STATTSCL 0x0FC -#define S6_GMAC_STATTSCL_SIZE 12 -#define S6_GMAC_STATTMCL 0x100 -#define S6_GMAC_STATTMCL_SIZE 12 -#define S6_GMAC_STATTLCL 0x104 -#define S6_GMAC_STATTLCL_SIZE 12 -#define S6_GMAC_STATTXCL 0x108 -#define S6_GMAC_STATTXCL_SIZE 12 -#define S6_GMAC_STATTNCL 0x10C -#define S6_GMAC_STATTNCL_SIZE 13 -#define S6_GMAC_STATTPFH 0x110 -#define S6_GMAC_STATTPFH_SIZE 12 -#define S6_GMAC_STATTDRP 0x114 -#define S6_GMAC_STATTDRP_SIZE 12 -#define S6_GMAC_STATTJBR 0x118 -#define S6_GMAC_STATTJBR_SIZE 12 -#define S6_GMAC_STATTFCS 0x11C -#define S6_GMAC_STATTFCS_SIZE 12 -#define S6_GMAC_STATTXCF 0x120 -#define S6_GMAC_STATTXCF_SIZE 12 -#define S6_GMAC_STATTOVR 0x124 -#define S6_GMAC_STATTOVR_SIZE 12 -#define S6_GMAC_STATTUND 0x128 -#define S6_GMAC_STATTUND_SIZE 12 -#define S6_GMAC_STATTFRG 0x12C -#define S6_GMAC_STATTFRG_SIZE 12 -#define S6_GMAC_STATCARRY(n) (0x130 + 4*(n)) -#define S6_GMAC_STATCARRYMSK(n) (0x138 + 4*(n)) -#define S6_GMAC_STATCARRY1_RDRP 0 -#define S6_GMAC_STATCARRY1_RJBR 1 -#define S6_GMAC_STATCARRY1_RFRG 2 -#define S6_GMAC_STATCARRY1_ROVR 3 -#define S6_GMAC_STATCARRY1_RUND 4 -#define S6_GMAC_STATCARRY1_RCSE 5 -#define S6_GMAC_STATCARRY1_RCDE 6 -#define S6_GMAC_STATCARRY1_RFLR 7 -#define S6_GMAC_STATCARRY1_RALN 8 -#define S6_GMAC_STATCARRY1_RXUO 9 -#define S6_GMAC_STATCARRY1_RXPF 10 -#define S6_GMAC_STATCARRY1_RXCF 11 -#define S6_GMAC_STATCARRY1_RBCA 12 -#define S6_GMAC_STATCARRY1_RMCA 13 -#define S6_GMAC_STATCARRY1_RFCS 14 -#define S6_GMAC_STATCARRY1_RPKT 15 -#define S6_GMAC_STATCARRY1_RBYT 16 -#define S6_GMAC_STATCARRY1_TRMGV 25 -#define S6_GMAC_STATCARRY1_TRMAX 26 -#define S6_GMAC_STATCARRY1_TR1K 27 -#define S6_GMAC_STATCARRY1_TR511 28 -#define S6_GMAC_STATCARRY1_TR255 29 -#define S6_GMAC_STATCARRY1_TR127 30 -#define S6_GMAC_STATCARRY1_TR64 31 -#define S6_GMAC_STATCARRY2_TDRP 0 -#define S6_GMAC_STATCARRY2_TPFH 1 -#define S6_GMAC_STATCARRY2_TNCL 2 -#define S6_GMAC_STATCARRY2_TXCL 3 -#define S6_GMAC_STATCARRY2_TLCL 4 -#define S6_GMAC_STATCARRY2_TMCL 5 -#define S6_GMAC_STATCARRY2_TSCL 6 -#define S6_GMAC_STATCARRY2_TEDF 7 -#define S6_GMAC_STATCARRY2_TDFR 8 -#define S6_GMAC_STATCARRY2_TXPF 9 -#define S6_GMAC_STATCARRY2_TBCA 10 -#define S6_GMAC_STATCARRY2_TMCA 11 -#define S6_GMAC_STATCARRY2_TPKT 12 -#define S6_GMAC_STATCARRY2_TBYT 13 -#define S6_GMAC_STATCARRY2_TFRG 14 -#define S6_GMAC_STATCARRY2_TUND 15 -#define S6_GMAC_STATCARRY2_TOVR 16 -#define S6_GMAC_STATCARRY2_TXCF 17 -#define S6_GMAC_STATCARRY2_TFCS 18 -#define S6_GMAC_STATCARRY2_TJBR 19 - -#define S6_GMAC_HOST_PBLKCTRL 0x140 -#define S6_GMAC_HOST_PBLKCTRL_TXENA 0 -#define S6_GMAC_HOST_PBLKCTRL_RXENA 1 -#define S6_GMAC_HOST_PBLKCTRL_TXSRES 2 -#define S6_GMAC_HOST_PBLKCTRL_RXSRES 3 -#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ 8 -#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ 12 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_16 4 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_32 5 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_64 6 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_128 7 -#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK 0xF -#define S6_GMAC_HOST_PBLKCTRL_STATENA 16 -#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ 17 -#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR 18 -#define S6_GMAC_HOST_PBLKCTRL_RGMII 19 -#define S6_GMAC_HOST_INTMASK 0x144 -#define S6_GMAC_HOST_INTSTAT 0x148 -#define S6_GMAC_HOST_INT_TXBURSTOVER 3 -#define S6_GMAC_HOST_INT_TXPREWOVER 4 -#define S6_GMAC_HOST_INT_RXBURSTUNDER 5 -#define S6_GMAC_HOST_INT_RXPOSTRFULL 6 -#define S6_GMAC_HOST_INT_RXPOSTRUNDER 7 -#define S6_GMAC_HOST_RXFIFOHWM 0x14C -#define S6_GMAC_HOST_CTRLFRAMXP 0x150 -#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n)) -#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n)) -#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n)) - -#define S6_GMAC_BURST_PREWR 0x1B0 -#define S6_GMAC_BURST_PREWR_LEN 0 -#define S6_GMAC_BURST_PREWR_LEN_MASK ((1 << 20) - 1) -#define S6_GMAC_BURST_PREWR_CFE 20 -#define S6_GMAC_BURST_PREWR_PPE 21 -#define S6_GMAC_BURST_PREWR_FCS 22 -#define S6_GMAC_BURST_PREWR_PAD 23 -#define S6_GMAC_BURST_POSTRD 0x1D0 -#define S6_GMAC_BURST_POSTRD_LEN 0 -#define S6_GMAC_BURST_POSTRD_LEN_MASK ((1 << 20) - 1) -#define S6_GMAC_BURST_POSTRD_DROP 20 - - -/* data handling */ - -#define S6_NUM_TX_SKB 8 /* must be larger than TX fifo size */ -#define S6_NUM_RX_SKB 16 -#define S6_MAX_FRLEN 1536 - -struct s6gmac { - u32 reg; - u32 tx_dma; - u32 rx_dma; - u32 io; - u8 tx_chan; - u8 rx_chan; - spinlock_t lock; - u8 tx_skb_i, tx_skb_o; - u8 rx_skb_i, rx_skb_o; - struct sk_buff *tx_skb[S6_NUM_TX_SKB]; - struct sk_buff *rx_skb[S6_NUM_RX_SKB]; - unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)]; - unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)]; - struct phy_device *phydev; - struct { - struct mii_bus *bus; - int irq[PHY_MAX_ADDR]; - } mii; - struct { - unsigned int mbit; - u8 giga; - u8 isup; - u8 full; - } link; -}; - -static void s6gmac_rx_fillfifo(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct sk_buff *skb; - while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) && - (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) && - (skb = netdev_alloc_skb(dev, S6_MAX_FRLEN + 2))) { - pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; - s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, - pd->io, (u32)skb->data, S6_MAX_FRLEN); - } -} - -static void s6gmac_rx_interrupt(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - u32 pfx; - struct sk_buff *skb; - while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) > - s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) { - skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]; - pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD); - if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) { - dev_kfree_skb_irq(skb); - } else { - skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN) - & S6_GMAC_BURST_POSTRD_LEN_MASK); - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_rx(skb); - } - } -} - -static void s6gmac_tx_interrupt(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) > - s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) { - dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); - } - if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_wake_queue(dev); -} - -struct s6gmac_statinf { - unsigned reg_size : 4; /* 0: unused */ - unsigned reg_off : 6; - unsigned net_index : 6; -}; - -#define S6_STATS_B (8 * sizeof(u32)) -#define S6_STATS_C(b, r, f) [b] = { \ - BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \ - BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \ - >= (1<<4)) + \ - r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \ - BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \ - >= ((1<<6)-1)) + \ - (r - S6_GMAC_STAT_REGS) / sizeof(u32), \ - BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \ - % sizeof(unsigned long)) + \ - BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \ - / sizeof(unsigned long)) >= (1<<6))) + \ - BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \ - != sizeof(unsigned long))) + \ - (offsetof(struct net_device_stats, f)) / sizeof(unsigned long)}, - -static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { { - S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes) - S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets) - S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast) - S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors) - S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped) -}, { - S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes) - S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets) - S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions) - S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped) - S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors) - S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors) -} }; - -static void s6gmac_stats_collect(struct s6gmac *pd, - const struct s6gmac_statinf *inf) -{ - int b; - for (b = 0; b < S6_STATS_B; b++) { - if (inf[b].reg_size) { - pd->stats[inf[b].net_index] += - readl(pd->reg + S6_GMAC_STAT_REGS - + sizeof(u32) * inf[b].reg_off); - } - } -} - -static void s6gmac_stats_carry(struct s6gmac *pd, - const struct s6gmac_statinf *inf, u32 mask) -{ - int b; - while (mask) { - b = fls(mask) - 1; - mask &= ~(1 << b); - pd->carry[inf[b].net_index] += (1 << inf[b].reg_size); - } -} - -static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry) -{ - int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) & - ~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry)); - return r; -} - -static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry) -{ - u32 mask; - mask = s6gmac_stats_pending(pd, carry); - if (mask) { - writel(mask, pd->reg + S6_GMAC_STATCARRY(carry)); - s6gmac_stats_carry(pd, &statinf[carry][0], mask); - } -} - -static irqreturn_t s6gmac_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct s6gmac *pd = netdev_priv(dev); - if (!dev) - return IRQ_NONE; - spin_lock(&pd->lock); - if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan)) - s6gmac_rx_interrupt(dev); - s6gmac_rx_fillfifo(dev); - if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan)) - s6gmac_tx_interrupt(dev); - s6gmac_stats_interrupt(pd, 0); - s6gmac_stats_interrupt(pd, 1); - spin_unlock(&pd->lock); - return IRQ_HANDLED; -} - -static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n, - u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi) -{ - writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n)); - writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n)); - writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n)); - writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n)); -} - -static inline void s6gmac_stop_device(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - writel(0, pd->reg + S6_GMAC_MACCONF1); -} - -static inline void s6gmac_init_device(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - int is_rgmii = !!(pd->phydev->supported - & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)); -#if 0 - writel(1 << S6_GMAC_MACCONF1_SYNCTX | - 1 << S6_GMAC_MACCONF1_SYNCRX | - 1 << S6_GMAC_MACCONF1_TXFLOWCTRL | - 1 << S6_GMAC_MACCONF1_RXFLOWCTRL | - 1 << S6_GMAC_MACCONF1_RESTXFUNC | - 1 << S6_GMAC_MACCONF1_RESRXFUNC | - 1 << S6_GMAC_MACCONF1_RESTXMACCTRL | - 1 << S6_GMAC_MACCONF1_RESRXMACCTRL, - pd->reg + S6_GMAC_MACCONF1); -#endif - writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1); - udelay(1000); - writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA, - pd->reg + S6_GMAC_MACCONF1); - writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES | - 1 << S6_GMAC_HOST_PBLKCTRL_RXSRES, - pd->reg + S6_GMAC_HOST_PBLKCTRL); - writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | - 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | - 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | - is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, - pd->reg + S6_GMAC_HOST_PBLKCTRL); - writel(1 << S6_GMAC_MACCONF1_TXENA | - 1 << S6_GMAC_MACCONF1_RXENA | - (dev->flags & IFF_LOOPBACK ? 1 : 0) - << S6_GMAC_MACCONF1_LOOPBACK, - pd->reg + S6_GMAC_MACCONF1); - writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ? - dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN, - pd->reg + S6_GMAC_MACMAXFRAMELEN); - writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL | - 1 << S6_GMAC_MACCONF2_PADCRCENA | - 1 << S6_GMAC_MACCONF2_LENGTHFCHK | - (pd->link.giga ? - S6_GMAC_MACCONF2_IFMODE_BYTE : - S6_GMAC_MACCONF2_IFMODE_NIBBLE) - << S6_GMAC_MACCONF2_IFMODE | - 7 << S6_GMAC_MACCONF2_PREAMBLELEN, - pd->reg + S6_GMAC_MACCONF2); - writel(0, pd->reg + S6_GMAC_MACSTATADDR1); - writel(0, pd->reg + S6_GMAC_MACSTATADDR2); - writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ | - 1 << S6_GMAC_FIFOCONF0_SRFENREQ | - 1 << S6_GMAC_FIFOCONF0_FRFENREQ | - 1 << S6_GMAC_FIFOCONF0_STFENREQ | - 1 << S6_GMAC_FIFOCONF0_FTFENREQ, - pd->reg + S6_GMAC_FIFOCONF0); - writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH | - 128 << S6_GMAC_FIFOCONF3_CFGHWMFT, - pd->reg + S6_GMAC_FIFOCONF3); - writel((S6_GMAC_FIFOCONF_RSV_MASK & ~( - 1 << S6_GMAC_FIFOCONF_RSV_RUNT | - 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | - 1 << S6_GMAC_FIFOCONF_RSV_OK | - 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | - 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | - 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | - 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | - 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) | - 1 << S6_GMAC_FIFOCONF5_DROPLT64 | - pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM | - 1 << S6_GMAC_FIFOCONF5_RXDROPSIZE, - pd->reg + S6_GMAC_FIFOCONF5); - writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT | - 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | - 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | - 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | - 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | - 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | - 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED, - pd->reg + S6_GMAC_FIFOCONF4); - s6gmac_set_dstaddr(pd, 0, - 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF); - s6gmac_set_dstaddr(pd, 1, - dev->dev_addr[5] | - dev->dev_addr[4] << 8 | - dev->dev_addr[3] << 16 | - dev->dev_addr[2] << 24, - dev->dev_addr[1] | - dev->dev_addr[0] << 8, - 0xFFFFFFFF, 0x0000FFFF); - s6gmac_set_dstaddr(pd, 2, - 0x00000000, 0x00000100, 0x00000000, 0x00000100); - s6gmac_set_dstaddr(pd, 3, - 0x00000000, 0x00000000, 0x00000000, 0x00000000); - writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA | - 1 << S6_GMAC_HOST_PBLKCTRL_RXENA | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | - S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | - 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | - 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | - is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, - pd->reg + S6_GMAC_HOST_PBLKCTRL); -} - -static void s6mii_enable(struct s6gmac *pd) -{ - writel(readl(pd->reg + S6_GMAC_MACCONF1) & - ~(1 << S6_GMAC_MACCONF1_SOFTRES), - pd->reg + S6_GMAC_MACCONF1); - writel((readl(pd->reg + S6_GMAC_MACMIICONF) - & ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL)) - | (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL), - pd->reg + S6_GMAC_MACMIICONF); -} - -static int s6mii_busy(struct s6gmac *pd, int tmo) -{ - while (readl(pd->reg + S6_GMAC_MACMIIINDI)) { - if (--tmo == 0) - return -ETIME; - udelay(64); - } - return 0; -} - -static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, 256)) - return -ETIME; - writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | - regnum << S6_GMAC_MACMIIADDR_REG, - pd->reg + S6_GMAC_MACMIIADDR); - writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD); - writel(0, pd->reg + S6_GMAC_MACMIICMD); - if (s6mii_busy(pd, 256)) - return -ETIME; - return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT); -} - -static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, 256)) - return -ETIME; - writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | - regnum << S6_GMAC_MACMIIADDR_REG, - pd->reg + S6_GMAC_MACMIIADDR); - writel(value, pd->reg + S6_GMAC_MACMIICTRL); - if (s6mii_busy(pd, 256)) - return -ETIME; - return 0; -} - -static int s6mii_reset(struct mii_bus *bus) -{ - struct s6gmac *pd = bus->priv; - s6mii_enable(pd); - if (s6mii_busy(pd, PHY_INIT_TIMEOUT)) - return -ETIME; - return 0; -} - -static void s6gmac_set_rgmii_txclock(struct s6gmac *pd) -{ - u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); - pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC); - switch (pd->link.mbit) { - case 10: - pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC; - break; - case 100: - pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC; - break; - case 1000: - pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC; - break; - default: - return; - } - writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL); -} - -static inline void s6gmac_linkisup(struct net_device *dev, int isup) -{ - struct s6gmac *pd = netdev_priv(dev); - struct phy_device *phydev = pd->phydev; - - pd->link.full = phydev->duplex; - pd->link.giga = (phydev->speed == 1000); - if (pd->link.mbit != phydev->speed) { - pd->link.mbit = phydev->speed; - s6gmac_set_rgmii_txclock(pd); - } - pd->link.isup = isup; - if (isup) - netif_carrier_on(dev); - phy_print_status(phydev); -} - -static void s6gmac_adjust_link(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct phy_device *phydev = pd->phydev; - if (pd->link.isup && - (!phydev->link || - (pd->link.mbit != phydev->speed) || - (pd->link.full != phydev->duplex))) { - pd->link.isup = 0; - netif_tx_disable(dev); - if (!phydev->link) { - netif_carrier_off(dev); - phy_print_status(phydev); - } - } - if (!pd->link.isup && phydev->link) { - if (pd->link.full != phydev->duplex) { - u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); - if (phydev->duplex) - maccfg |= 1 << S6_GMAC_MACCONF2_FULL; - else - maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL); - writel(maccfg, pd->reg + S6_GMAC_MACCONF2); - } - - if (pd->link.giga != (phydev->speed == 1000)) { - u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5); - u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); - maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK - << S6_GMAC_MACCONF2_IFMODE); - if (phydev->speed == 1000) { - fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM; - maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE - << S6_GMAC_MACCONF2_IFMODE; - } else { - fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM); - maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE - << S6_GMAC_MACCONF2_IFMODE; - } - writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5); - writel(maccfg, pd->reg + S6_GMAC_MACCONF2); - } - - if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_wake_queue(dev); - s6gmac_linkisup(dev, 1); - } -} - -static inline int s6gmac_phy_start(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - int i = 0; - struct phy_device *p = NULL; - while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i]))) - i++; - p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, - PHY_INTERFACE_MODE_RGMII); - if (IS_ERR(p)) { - printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); - return PTR_ERR(p); - } - p->supported &= PHY_GBIT_FEATURES; - p->advertising = p->supported; - pd->phydev = p; - return 0; -} - -static inline void s6gmac_init_stats(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - u32 mask; - mask = 1 << S6_GMAC_STATCARRY1_RDRP | - 1 << S6_GMAC_STATCARRY1_RJBR | - 1 << S6_GMAC_STATCARRY1_RFRG | - 1 << S6_GMAC_STATCARRY1_ROVR | - 1 << S6_GMAC_STATCARRY1_RUND | - 1 << S6_GMAC_STATCARRY1_RCDE | - 1 << S6_GMAC_STATCARRY1_RFLR | - 1 << S6_GMAC_STATCARRY1_RALN | - 1 << S6_GMAC_STATCARRY1_RMCA | - 1 << S6_GMAC_STATCARRY1_RFCS | - 1 << S6_GMAC_STATCARRY1_RPKT | - 1 << S6_GMAC_STATCARRY1_RBYT; - writel(mask, pd->reg + S6_GMAC_STATCARRY(0)); - writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0)); - mask = 1 << S6_GMAC_STATCARRY2_TDRP | - 1 << S6_GMAC_STATCARRY2_TNCL | - 1 << S6_GMAC_STATCARRY2_TXCL | - 1 << S6_GMAC_STATCARRY2_TEDF | - 1 << S6_GMAC_STATCARRY2_TPKT | - 1 << S6_GMAC_STATCARRY2_TBYT | - 1 << S6_GMAC_STATCARRY2_TFRG | - 1 << S6_GMAC_STATCARRY2_TUND | - 1 << S6_GMAC_STATCARRY2_TOVR | - 1 << S6_GMAC_STATCARRY2_TFCS | - 1 << S6_GMAC_STATCARRY2_TJBR; - writel(mask, pd->reg + S6_GMAC_STATCARRY(1)); - writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1)); -} - -static inline void s6gmac_init_dmac(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - s6dmac_disable_chan(pd->tx_dma, pd->tx_chan); - s6dmac_disable_chan(pd->rx_dma, pd->rx_chan); - s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX); - s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX); -} - -static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&pd->lock, flags); - writel(skb->len << S6_GMAC_BURST_PREWR_LEN | - 0 << S6_GMAC_BURST_PREWR_CFE | - 1 << S6_GMAC_BURST_PREWR_PPE | - 1 << S6_GMAC_BURST_PREWR_FCS | - ((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD, - pd->reg + S6_GMAC_BURST_PREWR); - s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan, - (u32)skb->data, pd->io, skb->len); - if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) - netif_stop_queue(dev); - if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) { - printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n", - pd->tx_skb_o, pd->tx_skb_i); - BUG(); - } - pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb; - spin_unlock_irqrestore(&pd->lock, flags); - return 0; -} - -static void s6gmac_tx_timeout(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - spin_lock_irqsave(&pd->lock, flags); - s6gmac_tx_interrupt(dev); - spin_unlock_irqrestore(&pd->lock, flags); -} - -static int s6gmac_open(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - phy_read_status(pd->phydev); - spin_lock_irqsave(&pd->lock, flags); - pd->link.mbit = 0; - s6gmac_linkisup(dev, pd->phydev->link); - s6gmac_init_device(dev); - s6gmac_init_stats(dev); - s6gmac_init_dmac(dev); - s6gmac_rx_fillfifo(dev); - s6dmac_enable_chan(pd->rx_dma, pd->rx_chan, - 2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1); - s6dmac_enable_chan(pd->tx_dma, pd->tx_chan, - 2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1); - writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER | - 0 << S6_GMAC_HOST_INT_TXPREWOVER | - 0 << S6_GMAC_HOST_INT_RXBURSTUNDER | - 0 << S6_GMAC_HOST_INT_RXPOSTRFULL | - 0 << S6_GMAC_HOST_INT_RXPOSTRUNDER, - pd->reg + S6_GMAC_HOST_INTMASK); - spin_unlock_irqrestore(&pd->lock, flags); - phy_start(pd->phydev); - netif_start_queue(dev); - return 0; -} - -static int s6gmac_stop(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - unsigned long flags; - netif_stop_queue(dev); - phy_stop(pd->phydev); - spin_lock_irqsave(&pd->lock, flags); - s6gmac_init_dmac(dev); - s6gmac_stop_device(dev); - while (pd->tx_skb_i != pd->tx_skb_o) - dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); - while (pd->rx_skb_i != pd->rx_skb_o) - dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]); - spin_unlock_irqrestore(&pd->lock, flags); - return 0; -} - -static struct net_device_stats *s6gmac_stats(struct net_device *dev) -{ - struct s6gmac *pd = netdev_priv(dev); - struct net_device_stats *st = (struct net_device_stats *)&pd->stats; - int i; - do { - unsigned long flags; - spin_lock_irqsave(&pd->lock, flags); - for (i = 0; i < ARRAY_SIZE(pd->stats); i++) - pd->stats[i] = - pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); - s6gmac_stats_collect(pd, &statinf[0][0]); - s6gmac_stats_collect(pd, &statinf[1][0]); - i = s6gmac_stats_pending(pd, 0) | - s6gmac_stats_pending(pd, 1); - spin_unlock_irqrestore(&pd->lock, flags); - } while (i); - st->rx_errors = st->rx_crc_errors + - st->rx_frame_errors + - st->rx_length_errors + - st->rx_missed_errors; - st->tx_errors += st->tx_aborted_errors; - return st; -} - -static int s6gmac_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct s6gmac *pd; - int res; - unsigned long i; - struct mii_bus *mb; - - dev = alloc_etherdev(sizeof(*pd)); - if (!dev) - return -ENOMEM; - - dev->open = s6gmac_open; - dev->stop = s6gmac_stop; - dev->hard_start_xmit = s6gmac_tx; - dev->tx_timeout = s6gmac_tx_timeout; - dev->watchdog_timeo = HZ; - dev->get_stats = s6gmac_stats; - dev->irq = platform_get_irq(pdev, 0); - pd = netdev_priv(dev); - memset(pd, 0, sizeof(*pd)); - spin_lock_init(&pd->lock); - pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start; - i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start; - pd->tx_dma = DMA_MASK_DMAC(i); - pd->tx_chan = DMA_INDEX_CHNL(i); - i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start; - pd->rx_dma = DMA_MASK_DMAC(i); - pd->rx_chan = DMA_INDEX_CHNL(i); - pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; - res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev); - if (res) { - printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); - goto errirq; - } - res = register_netdev(dev); - if (res) { - printk(KERN_ERR DRV_PRMT "error registering device %s\n", - dev->name); - goto errdev; - } - mb = mdiobus_alloc(); - if (!mb) { - printk(KERN_ERR DRV_PRMT "error allocating mii bus\n"); - res = -ENOMEM; - goto errmii; - } - mb->name = "s6gmac_mii"; - mb->read = s6mii_read; - mb->write = s6mii_write; - mb->reset = s6mii_reset; - mb->priv = pd; - snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id); - mb->phy_mask = ~(1 << 0); - mb->irq = &pd->mii.irq[0]; - for (i = 0; i < PHY_MAX_ADDR; i++) { - int n = platform_get_irq(pdev, i + 1); - if (n < 0) - n = PHY_POLL; - pd->mii.irq[i] = n; - } - mdiobus_register(mb); - pd->mii.bus = mb; - res = s6gmac_phy_start(dev); - if (res) - return res; - platform_set_drvdata(pdev, dev); - return 0; -errmii: - unregister_netdev(dev); -errdev: - free_irq(dev->irq, dev); -errirq: - free_netdev(dev); - return res; -} - -static int s6gmac_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - if (dev) { - struct s6gmac *pd = netdev_priv(dev); - mdiobus_unregister(pd->mii.bus); - unregister_netdev(dev); - free_irq(dev->irq, dev); - free_netdev(dev); - } - return 0; -} - -static struct platform_driver s6gmac_driver = { - .probe = s6gmac_probe, - .remove = s6gmac_remove, - .driver = { - .name = "s6gmac", - }, -}; - -module_platform_driver(s6gmac_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); -MODULE_AUTHOR("Oskar Schirmer "); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 118a427..8c6b7c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1671,7 +1671,7 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv) * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ -static int stmmac_hw_setup(struct net_device *dev) +static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) { struct stmmac_priv *priv = netdev_priv(dev); int ret; @@ -1708,9 +1708,11 @@ static int stmmac_hw_setup(struct net_device *dev) stmmac_mmc_setup(priv); - ret = stmmac_init_ptp(priv); - if (ret && ret != -EOPNOTSUPP) - pr_warn("%s: failed PTP initialisation\n", __func__); + if (init_ptp) { + ret = stmmac_init_ptp(priv); + if (ret && ret != -EOPNOTSUPP) + pr_warn("%s: failed PTP initialisation\n", __func__); + } #ifdef CONFIG_DEBUG_FS ret = stmmac_init_fs(dev); @@ -1787,7 +1789,7 @@ static int stmmac_open(struct net_device *dev) goto init_error; } - ret = stmmac_hw_setup(dev); + ret = stmmac_hw_setup(dev, true); if (ret < 0) { pr_err("%s: Hw setup failed\n", __func__); goto init_error; @@ -3036,7 +3038,7 @@ int stmmac_resume(struct net_device *ndev) netif_device_attach(ndev); init_dma_desc_rings(ndev, GFP_ATOMIC); - stmmac_hw_setup(ndev); + stmmac_hw_setup(ndev, false); stmmac_init_tx_coalesce(priv); napi_enable(&priv->napi); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 4032b17..3039de2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -430,7 +430,6 @@ static struct platform_driver stmmac_pltfr_driver = { .remove = stmmac_pltfr_remove, .driver = { .name = STMMAC_RESOURCE_NAME, - .owner = THIS_MODULE, .pm = &stmmac_pltfr_pm_ops, .of_match_table = of_match_ptr(stmmac_dt_ids), }, diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 45c408e..d2835bf 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1201,6 +1201,7 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb) segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); if (IS_ERR(segs)) { dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 44b8d2b..4c9b4fa 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -388,7 +388,6 @@ struct axidma_bd { * @dma_err_tasklet: Tasklet structure to process Axi DMA errors * @tx_irq: Axidma TX IRQ number * @rx_irq: Axidma RX IRQ number - * @temac_type: axienet type to identify between soft and hard temac * @phy_type: Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X * @options: AxiEthernet option word * @last_link: Phy link state in which the PHY was negotiated earlier @@ -431,7 +430,6 @@ struct axienet_local { int tx_irq; int rx_irq; - u32 temac_type; u32 phy_type; u32 options; /* Current options word */ diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 4ea2d4e..c18a0c6 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1555,10 +1555,6 @@ static int axienet_of_probe(struct platform_device *op) if ((be32_to_cpup(p)) >= 0x4000) lp->jumbo_support = 1; } - p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type", - NULL); - if (p) - lp->temac_type = be32_to_cpup(p); p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL); if (p) lp->phy_type = be32_to_cpup(p); diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 2f48f79..384ca4f 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -590,6 +590,7 @@ struct nvsp_message { #define NETVSC_RECEIVE_BUFFER_ID 0xcafe +#define NETVSC_SEND_BUFFER_ID 0 #define NETVSC_PACKET_SIZE 4096 diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index dd867e6..9f49c01 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -161,8 +161,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) /* Deal with the send buffer we may have setup. * If we got a send section size, it means we received a - * SendsendBufferComplete msg (ie sent - * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need + * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent + * NVSP_MSG1_TYPE_SEND_SEND_BUF msg) therefore, we need * to send a revoke msg here */ if (net_device->send_section_size) { @@ -172,7 +172,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) revoke_packet->hdr.msg_type = NVSP_MSG1_TYPE_REVOKE_SEND_BUF; - revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0; + revoke_packet->msg.v1_msg.revoke_send_buf.id = + NETVSC_SEND_BUFFER_ID; ret = vmbus_sendpacket(net_device->dev->channel, revoke_packet, @@ -204,7 +205,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device) net_device->send_buf_gpadl_handle = 0; } if (net_device->send_buf) { - /* Free up the receive buffer */ + /* Free up the send buffer */ vfree(net_device->send_buf); net_device->send_buf = NULL; } @@ -339,9 +340,9 @@ static int netvsc_init_buf(struct hv_device *device) init_packet = &net_device->channel_init_pkt; memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF; - init_packet->msg.v1_msg.send_recv_buf.gpadl_handle = + init_packet->msg.v1_msg.send_send_buf.gpadl_handle = net_device->send_buf_gpadl_handle; - init_packet->msg.v1_msg.send_recv_buf.id = 0; + init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID; /* Send the gpadl notification request */ ret = vmbus_sendpacket(device->channel, init_packet, @@ -364,7 +365,7 @@ static int netvsc_init_buf(struct hv_device *device) netdev_err(ndev, "Unable to complete send buffer " "initialization with NetVsp - status %d\n", init_packet->msg.v1_msg. - send_recv_buf_complete.status); + send_send_buf_complete.status); ret = -EINVAL; goto cleanup; } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c530de1..3ad8ca7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -88,6 +88,7 @@ struct kszphy_priv { static const struct kszphy_type ksz8021_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, + .has_broadcast_disable = true, .has_rmii_ref_clk_sel = true, }; @@ -258,19 +259,6 @@ static int kszphy_config_init(struct phy_device *phydev) return 0; } -static int ksz8021_config_init(struct phy_device *phydev) -{ - int rc; - - rc = kszphy_config_init(phydev); - if (rc) - return rc; - - rc = kszphy_broadcast_disable(phydev); - - return rc < 0 ? rc : 0; -} - static int ksz9021_load_values_from_of(struct phy_device *phydev, struct device_node *of_node, u16 reg, char *field1, char *field2, @@ -584,7 +572,7 @@ static struct phy_driver ksphy_driver[] = { .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, - .config_init = ksz8021_config_init, + .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, @@ -601,7 +589,7 @@ static struct phy_driver ksphy_driver[] = { .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz8021_type, .probe = kszphy_probe, - .config_init = ksz8021_config_init, + .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b8bd719..5ca9771 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -760,7 +760,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget) container_of(napi, struct receive_queue, napi); unsigned int r, received = 0; -again: received += virtnet_receive(rq, budget - received); /* Out of packets? */ @@ -771,7 +770,6 @@ again: napi_schedule_prep(napi)) { virtqueue_disable_cb(rq->vq); __napi_schedule(napi); - goto again; } } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 49d9f22..7fbd89f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1579,8 +1579,10 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk); skb = udp_tunnel_handle_offloads(skb, udp_sum); - if (IS_ERR(skb)) - return -EINVAL; + if (IS_ERR(skb)) { + err = -EINVAL; + goto err; + } skb_scrub_packet(skb, xnet); @@ -1590,12 +1592,16 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) - return err; + if (unlikely(err)) { + kfree_skb(skb); + goto err; + } skb = vlan_hwaccel_push_inside(skb); - if (WARN_ON(!skb)) - return -ENOMEM; + if (WARN_ON(!skb)) { + err = -ENOMEM; + goto err; + } vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_FLAGS); @@ -1606,6 +1612,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port); return 0; +err: + dst_release(dst); + return err; } #endif @@ -1621,7 +1630,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, skb = udp_tunnel_handle_offloads(skb, udp_sum); if (IS_ERR(skb)) - return -EINVAL; + return PTR_ERR(skb); min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + VXLAN_HLEN + sizeof(struct iphdr) @@ -1629,8 +1638,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, /* Need space for new headers (invalidates iph ptr) */ err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) + if (unlikely(err)) { + kfree_skb(skb); return err; + } skb = vlan_hwaccel_push_inside(skb); if (WARN_ON(!skb)) @@ -1776,9 +1787,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos, ttl, df, src_port, dst_port, htonl(vni << 8), !net_eq(vxlan->net, dev_net(vxlan->dev))); - - if (err < 0) + if (err < 0) { + /* skb is already freed. */ + skb = NULL; goto rt_tx_error; + } + iptunnel_xmit_stats(err, &dev->stats, dev->tstats); #if IS_ENABLED(CONFIG_IPV6) } else { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 3c06e93..9880dae 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1070,7 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, */ if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) && ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) || - (sdiodev->pdata->oob_irq_supported))) + (sdiodev->pdata && sdiodev->pdata->oob_irq_supported))) bus_if->wowl_supported = true; #endif @@ -1167,7 +1167,7 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; brcmf_dbg(SDIO, "Enter\n"); - if (sdiodev->pdata->oob_irq_supported) + if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported) disable_irq_wake(sdiodev->pdata->oob_irq_nr); brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); atomic_set(&sdiodev->suspend, false); diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 91c0cb3..21de4fe 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -65,7 +65,8 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && CFG80211 && CFG80211_WEXT + depends on PCI && CFG80211 + select CFG80211_WEXT select WIRELESS_EXT select WEXT_SPY select WEXT_PRIV diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 38de151..850b85a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1323,10 +1323,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) try_again: /* try next, if any */ - kfree(pieces); release_firmware(ucode_raw); if (iwl_request_firmware(drv, false)) goto out_unbind; + kfree(pieces); return; out_free_fw: diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 9564ae1..1f7f15e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -310,6 +310,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +#define FH_MEM_TB_MAX_LENGTH (0x00020000) /* TFDB Area - TFDs buffer table */ #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 31a5b3f..e880f9d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1004,8 +1004,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) { lockdep_assert_held(&mvm->mutex); - /* disallow low power states when the FW is down */ - iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + /* + * Disallow low power states when the FW is down by taking + * the UCODE_DOWN ref. in case of ongoing hw restart the + * ref is already taken, so don't take it again. + */ + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); /* async_handlers_wk is now blocked */ @@ -1023,6 +1028,12 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) /* the fw is stopped, the aux sta is dead: clean up driver state */ iwl_mvm_del_aux_sta(mvm); + /* + * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete() + * won't be called in this case). + */ + clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); + mvm->ucode_loaded = false; } diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3ee8e38..2f0c4b1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -367,7 +367,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 3165 Series */ {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)}, /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 5d79a1f..523fe0c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -614,7 +614,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, { u8 *v_addr; dma_addr_t p_addr; - u32 offset, chunk_sz = section->len; + u32 offset, chunk_sz = min_t(u32, FH_MEM_TB_MAX_LENGTH, section->len); int ret = 0; IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", @@ -1012,16 +1012,21 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans); - /* Upon stop, the APM issues an interrupt if HW RF kill is set. - * Clean again the interrupt here + /* stop and reset the on-board processor */ + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + udelay(20); + + /* + * Upon stop, the APM issues an interrupt if HW RF kill is set. + * This is a bug in certain verions of the hardware. + * Certain devices also keep sending HW RF kill interrupt all + * the time, unless the interrupt is ACKed even if the interrupt + * should be masked. Re-ACK all the interrupts here. */ spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); spin_unlock(&trans_pcie->irq_lock); - /* stop and reset the on-board processor */ - iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - udelay(20); /* clear all status bits */ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 1bf891b..4f361b7 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -264,7 +264,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) && inode->i_sb->s_root != NULL && - is_root_inode(inode)) + !is_root_inode(inode)) ll_invalidate_aliases(inode); iput(inode); diff --git a/fs/aio.c b/fs/aio.c index 1b7893e..284c74e 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -136,7 +137,7 @@ struct kioctx { struct { struct mutex ring_lock; - wait_queue_head_t wait; + struct closure_waitlist wait; } ____cacheline_aligned_in_smp; struct { @@ -689,7 +690,6 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) /* Protect against page migration throughout kiotx setup by keeping * the ring_lock mutex held until setup is complete. */ mutex_lock(&ctx->ring_lock); - init_waitqueue_head(&ctx->wait); INIT_LIST_HEAD(&ctx->active_reqs); @@ -772,7 +772,7 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, spin_unlock(&mm->ioctx_lock); /* percpu_ref_kill() will do the necessary call_rcu() */ - wake_up_all(&ctx->wait); + closure_wake_up(&ctx->wait); /* * It'd be more correct to do this in free_ioctx(), after all @@ -1121,8 +1121,7 @@ void aio_complete(struct kiocb *iocb, long res, long res2) */ smp_mb(); - if (waitqueue_active(&ctx->wait)) - wake_up(&ctx->wait); + closure_wake_up(&ctx->wait); percpu_ref_put(&ctx->reqs); } @@ -1237,26 +1236,15 @@ static long read_events(struct kioctx *ctx, long min_nr, long nr, return -EFAULT; until = timespec_to_ktime(ts); + + if (until.tv64) + until = ktime_add(ktime_get(), until); } - /* - * Note that aio_read_events() is being called as the conditional - i.e. - * we're calling it after prepare_to_wait() has set task state to - * TASK_INTERRUPTIBLE. - * - * But aio_read_events() can block, and if it blocks it's going to flip - * the task state back to TASK_RUNNING. - * - * This should be ok, provided it doesn't flip the state back to - * TASK_RUNNING and return 0 too much - that causes us to spin. That - * will only happen if the mutex_lock() call blocks, and we then find - * the ringbuffer empty. So in practice we should be ok, but it's - * something to be aware of when touching this code. - */ if (until.tv64 == 0) aio_read_events(ctx, min_nr, nr, event, &ret); else - wait_event_interruptible_hrtimeout(ctx->wait, + closure_wait_event_hrtimeout(&ctx->wait, aio_read_events(ctx, min_nr, nr, event, &ret), until); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8ba35c6..e1b2e8b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -901,11 +901,15 @@ extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); +extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc); extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime); extern void drm_send_vblank_event(struct drm_device *dev, int crtc, struct drm_pending_vblank_event *e); +extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, int crtc); +extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); extern int drm_crtc_vblank_get(struct drm_crtc *crtc); diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 780511a..1e6ae14 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -119,13 +119,6 @@ struct drm_gem_object { * simply leave it as NULL. */ struct dma_buf_attachment *import_attach; - - /** - * dumb - created as dumb buffer - * Whether the gem object was created using the dumb buffer interface - * as such it may not be used for GPU rendering. - */ - bool dumb; }; void drm_gem_object_release(struct drm_gem_object *obj); diff --git a/include/linux/audit.h b/include/linux/audit.h index 0c04917..af84234 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -47,6 +47,7 @@ struct sk_buff; struct audit_krule { int vers_ops; + u32 pflags; u32 flags; u32 listnr; u32 action; @@ -64,6 +65,9 @@ struct audit_krule { u64 prio; }; +/* Flag to indicate legacy AUDIT_LOGINUID unset usage */ +#define AUDIT_LOGINUID_LEGACY 0x1 + struct audit_field { u32 type; union { diff --git a/include/linux/closure.h b/include/linux/closure.h new file mode 100644 index 0000000..1890319 --- /dev/null +++ b/include/linux/closure.h @@ -0,0 +1,458 @@ +#ifndef _LINUX_CLOSURE_H +#define _LINUX_CLOSURE_H + +#include +#include +#include + +/* + * Closure is perhaps the most overused and abused term in computer science, but + * since I've been unable to come up with anything better you're stuck with it + * again. + * + * What are closures? + * + * They embed a refcount. The basic idea is they count "things that are in + * progress" - in flight bios, some other thread that's doing something else - + * anything you might want to wait on. + * + * The refcount may be manipulated with closure_get() and closure_put(). + * closure_put() is where many of the interesting things happen, when it causes + * the refcount to go to 0. + * + * Closures can be used to wait on things both synchronously and asynchronously, + * and synchronous and asynchronous use can be mixed without restriction. To + * wait synchronously, use closure_sync() - you will sleep until your closure's + * refcount hits 1. + * + * To wait asynchronously, use + * continue_at(cl, next_function, workqueue); + * + * passing it, as you might expect, the function to run when nothing is pending + * and the workqueue to run that function out of. + * + * continue_at() also, critically, is a macro that returns the calling function. + * There's good reason for this. + * + * To use safely closures asynchronously, they must always have a refcount while + * they are running owned by the thread that is running them. Otherwise, suppose + * you submit some bios and wish to have a function run when they all complete: + * + * foo_endio(struct bio *bio, int error) + * { + * closure_put(cl); + * } + * + * closure_init(cl); + * + * do_stuff(); + * closure_get(cl); + * bio1->bi_endio = foo_endio; + * bio_submit(bio1); + * + * do_more_stuff(); + * closure_get(cl); + * bio2->bi_endio = foo_endio; + * bio_submit(bio2); + * + * continue_at(cl, complete_some_read, system_wq); + * + * If closure's refcount started at 0, complete_some_read() could run before the + * second bio was submitted - which is almost always not what you want! More + * importantly, it wouldn't be possible to say whether the original thread or + * complete_some_read()'s thread owned the closure - and whatever state it was + * associated with! + * + * So, closure_init() initializes a closure's refcount to 1 - and when a + * closure_fn is run, the refcount will be reset to 1 first. + * + * Then, the rule is - if you got the refcount with closure_get(), release it + * with closure_put() (i.e, in a bio->bi_endio function). If you have a refcount + * on a closure because you called closure_init() or you were run out of a + * closure - _always_ use continue_at(). Doing so consistently will help + * eliminate an entire class of particularly pernicious races. + * + * Lastly, you might have a wait list dedicated to a specific event, and have no + * need for specifying the condition - you just want to wait until someone runs + * closure_wake_up() on the appropriate wait list. In that case, just use + * closure_wait(). It will return either true or false, depending on whether the + * closure was already on a wait list or not - a closure can only be on one wait + * list at a time. + * + * Parents: + * + * closure_init() takes two arguments - it takes the closure to initialize, and + * a (possibly null) parent. + * + * If parent is non null, the new closure will have a refcount for its lifetime; + * a closure is considered to be "finished" when its refcount hits 0 and the + * function to run is null. Hence + * + * continue_at(cl, NULL, NULL); + * + * returns up the (spaghetti) stack of closures, precisely like normal return + * returns up the C stack. continue_at() with non null fn is better thought of + * as doing a tail call. + * + * All this implies that a closure should typically be embedded in a particular + * struct (which its refcount will normally control the lifetime of), and that + * struct can very much be thought of as a stack frame. + */ + +struct closure; +struct closure_sleeper; +typedef void (closure_fn) (struct closure *); + +struct closure_waitlist { + struct llist_head list; +}; + +enum closure_state { + /* + * CLOSURE_WAITING: Set iff the closure is on a waitlist. Must be set by + * the thread that owns the closure, and cleared by the thread that's + * waking up the closure. + * + * The rest are for debugging and don't affect behaviour: + * + * CLOSURE_RUNNING: Set when a closure is running (i.e. by + * closure_init() and when closure_put() runs then next function), and + * must be cleared before remaining hits 0. Primarily to help guard + * against incorrect usage and accidentally transferring references. + * continue_at() and closure_return() clear it for you, if you're doing + * something unusual you can use closure_set_dead() which also helps + * annotate where references are being transferred. + */ + + CLOSURE_BITS_START = (1U << 27), + CLOSURE_DESTRUCTOR = (1U << 27), + CLOSURE_WAITING = (1U << 29), + CLOSURE_RUNNING = (1U << 31), +}; + +#define CLOSURE_GUARD_MASK \ + ((CLOSURE_DESTRUCTOR|CLOSURE_WAITING|CLOSURE_RUNNING) << 1) + +#define CLOSURE_REMAINING_MASK (CLOSURE_BITS_START - 1) +#define CLOSURE_REMAINING_INITIALIZER (1|CLOSURE_RUNNING) + +struct closure { + union { + struct { + struct workqueue_struct *wq; + struct closure_sleeper *complete; + struct llist_node list; + closure_fn *fn; + }; + struct work_struct work; + }; + + struct closure *parent; + + atomic_t remaining; + +#ifdef CONFIG_CLOSURE_DEBUG +#define CLOSURE_MAGIC_DEAD 0xc054dead +#define CLOSURE_MAGIC_ALIVE 0xc054a11e + + unsigned magic; + struct list_head all; + unsigned long ip; + unsigned long waiting_on; +#endif +}; + +void closure_sub(struct closure *cl, int v); +void closure_put(struct closure *cl); +void __closure_wake_up(struct closure_waitlist *list); +bool closure_wait(struct closure_waitlist *list, struct closure *cl); + +void __closure_sync(struct closure *cl); + +/** + * closure_sync - sleep until a closure a closure has nothing left to wait on + * + * Sleeps until the refcount hits 1 - the thread that's running the closure owns + * the last refcount. + */ +static inline void closure_sync(struct closure *cl) +{ + if ((atomic_read(&cl->remaining) & CLOSURE_REMAINING_MASK) != 1) + __closure_sync(cl); +} + +int __closure_sync_interruptible_hrtimeout(struct closure *, + struct closure_waitlist *, + ktime_t); + +/** + * closure_sync_hrtimeout - like closure_sync() but with a timeout + * + * The closure must have been added to the given waitlist. If the timeout + * expires, we wake up every closure on the waitlist (possibly including this + * closure). This is an artifact of how closure_sync() sets the closure's fn + * to wake up an on-stack completion. Otherwise, if the closure waitlist is + * woken up after the timeout, the fn will reference a dead completion. + * + * Returns -ETIME if the timeout expired, -ERESTARTSYS if interrupted, else 0 + */ +static inline int closure_sync_interruptible_hrtimeout(struct closure *cl, + struct closure_waitlist *waitlist, + ktime_t until) +{ + return ((atomic_read(&cl->remaining) & CLOSURE_REMAINING_MASK) != 1) + ? __closure_sync_interruptible_hrtimeout(cl, waitlist, until) + : 0; +} + +#ifdef CONFIG_CLOSURE_DEBUG + +void closure_debug_create(struct closure *cl); +void closure_debug_destroy(struct closure *cl); + +#else + +static inline void closure_debug_create(struct closure *cl) {} +static inline void closure_debug_destroy(struct closure *cl) {} + +#endif + +static inline void closure_set_ip(struct closure *cl) +{ +#ifdef CONFIG_CLOSURE_DEBUG + cl->ip = _THIS_IP_; +#endif +} + +static inline void closure_set_ret_ip(struct closure *cl) +{ +#ifdef CONFIG_CLOSURE_DEBUG + cl->ip = _RET_IP_; +#endif +} + +static inline void closure_set_waiting(struct closure *cl, unsigned long f) +{ +#ifdef CONFIG_CLOSURE_DEBUG + cl->waiting_on = f; +#endif +} + +static inline void closure_set_stopped(struct closure *cl) +{ + atomic_sub(CLOSURE_RUNNING, &cl->remaining); +} + +static inline void set_closure_fn(struct closure *cl, closure_fn *fn, + struct workqueue_struct *wq) +{ + closure_set_ip(cl); + cl->fn = fn; + cl->wq = wq; + /* between atomic_dec() in closure_put() */ + smp_mb__before_atomic(); +} + +static inline void closure_queue(struct closure *cl) +{ + struct workqueue_struct *wq = cl->wq; + if (wq) { + INIT_WORK(&cl->work, cl->work.func); + BUG_ON(!queue_work(wq, &cl->work)); + } else + cl->fn(cl); +} + +/** + * closure_get - increment a closure's refcount + */ +static inline void closure_get(struct closure *cl) +{ +#ifdef CONFIG_CLOSURE_DEBUG + BUG_ON((atomic_inc_return(&cl->remaining) & + CLOSURE_REMAINING_MASK) <= 1); +#else + atomic_inc(&cl->remaining); +#endif +} + +/** + * closure_init - Initialize a closure, setting the refcount to 1 + * @cl: closure to initialize + * @parent: parent of the new closure. cl will take a refcount on it for its + * lifetime; may be NULL. + */ +static inline void closure_init(struct closure *cl, struct closure *parent) +{ + memset(cl, 0, sizeof(struct closure)); + cl->parent = parent; + if (parent) + closure_get(parent); + + atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER); + + closure_debug_create(cl); + closure_set_ip(cl); +} + +static inline void closure_init_stack(struct closure *cl) +{ + memset(cl, 0, sizeof(struct closure)); + atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER); +} + +/** + * closure_wake_up - wake up all closures on a wait list. + */ +static inline void closure_wake_up(struct closure_waitlist *list) +{ + smp_mb(); + __closure_wake_up(list); +} + +#define continue_at_noreturn(_cl, _fn, _wq) \ +do { \ + set_closure_fn(_cl, _fn, _wq); \ + closure_sub(_cl, CLOSURE_RUNNING + 1); \ +} while (0) + +/** + * continue_at - jump to another function with barrier + * + * After @cl is no longer waiting on anything (i.e. all outstanding refs have + * been dropped with closure_put()), it will resume execution at @fn running out + * of @wq (or, if @wq is NULL, @fn will be called by closure_put() directly). + * + * NOTE: This macro expands to a return in the calling function! + * + * This is because after calling continue_at() you no longer have a ref on @cl, + * and whatever @cl owns may be freed out from under you - a running closure fn + * has a ref on its own closure which continue_at() drops. + */ +#define continue_at(_cl, _fn, _wq) \ +do { \ + continue_at_noreturn(_cl, _fn, _wq); \ + return; \ +} while (0) + +/** + * closure_return - finish execution of a closure + * + * This is used to indicate that @cl is finished: when all outstanding refs on + * @cl have been dropped @cl's ref on its parent closure (as passed to + * closure_init()) will be dropped, if one was specified - thus this can be + * thought of as returning to the parent closure. + */ +#define closure_return(_cl) continue_at((_cl), NULL, NULL) + +/** + * continue_at_nobarrier - jump to another function without barrier + * + * Causes @fn to be executed out of @cl, in @wq context (or called directly if + * @wq is NULL). + * + * NOTE: like continue_at(), this macro expands to a return in the caller! + * + * The ref the caller of continue_at_nobarrier() had on @cl is now owned by @fn, + * thus it's not safe to touch anything protected by @cl after a + * continue_at_nobarrier(). + */ +#define continue_at_nobarrier(_cl, _fn, _wq) \ +do { \ + set_closure_fn(_cl, _fn, _wq); \ + closure_queue(_cl); \ + return; \ +} while (0) + +/** + * closure_return - finish execution of a closure, with destructor + * + * Works like closure_return(), except @destructor will be called when all + * outstanding refs on @cl have been dropped; @destructor may be used to safely + * free the memory occupied by @cl, and it is called with the ref on the parent + * closure still held - so @destructor could safely return an item to a + * freelist protected by @cl's parent. + */ +#define closure_return_with_destructor(_cl, _destructor) \ +do { \ + set_closure_fn(_cl, _destructor, NULL); \ + closure_sub(_cl, CLOSURE_RUNNING - CLOSURE_DESTRUCTOR + 1); \ + return; \ +} while (0) + +/** + * closure_call - execute @fn out of a new, uninitialized closure + * + * Typically used when running out of one closure, and we want to run @fn + * asynchronously out of a new closure - @parent will then wait for @cl to + * finish. + */ +static inline void closure_call(struct closure *cl, closure_fn fn, + struct workqueue_struct *wq, + struct closure *parent) +{ + closure_init(cl, parent); + continue_at_nobarrier(cl, fn, wq); +} + +/** + * closure_wait_event - wait for a condition to become true + * + * We wait for @condition to become true, waiting on @waitlist to be woken up + * until it does. + */ +#define closure_wait_event(waitlist, condition) \ + do { \ + struct closure __cl; \ + closure_init_stack(&__cl); \ + while (1) { \ + if (condition) \ + break; \ + closure_wait(waitlist, &__cl); \ + if (condition) { \ + closure_wake_up(waitlist); \ + closure_sync(&__cl); \ + break; \ + } \ + closure_sync(&__cl); \ + } \ + } while (0) + +#define __closure_wait_event_hrtimeout(waitlist, condition, until) \ +({ \ + struct closure _cl; \ + int _ret; \ + \ + closure_init_stack(&_cl); \ + \ + do { \ + closure_wait(waitlist, &_cl); \ + \ + if (condition) { \ + closure_wake_up(waitlist); \ + closure_sync(&_cl); \ + _ret = 0; \ + break; \ + } \ + } while (!(_ret = closure_sync_interruptible_hrtimeout(&_cl, \ + waitlist, \ + until))); \ + \ + _ret; \ +}) + +/** + * closure_wait_event_timeout - wait for a condition to become true + * + * We wait for @condition to become true, waiting for @waitlist to be woken up + * until it does. + * + * Returns -ETIME if @condition did not become true before @until, + * -ERESTARTSYS if interrupted, else 0 + */ +#define closure_wait_event_hrtimeout(waitlist, condition, until) \ + (condition) \ + ? 0 \ + : __closure_wait_event_hrtimeout(waitlist, condition, until) + +#endif /* _LINUX_CLOSURE_H */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c31f74d..679e6e9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1012,12 +1012,15 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * Callback to use for xmit over the accelerated station. This * is used in place of ndo_start_xmit on accelerated net * devices. - * bool (*ndo_gso_check) (struct sk_buff *skb, - * struct net_device *dev); + * netdev_features_t (*ndo_features_check) (struct sk_buff *skb, + * struct net_device *dev + * netdev_features_t features); * Called by core transmit path to determine if device is capable of - * performing GSO on a packet. The device returns true if it is - * able to GSO the packet, false otherwise. If the return value is - * false the stack will do software GSO. + * performing offload operations on a given packet. This is to give + * the device an opportunity to implement any restrictions that cannot + * be otherwise expressed by feature flags. The check is called with + * the set of features that the stack has calculated and it returns + * those the driver believes to be appropriate. * * int (*ndo_switch_parent_id_get)(struct net_device *dev, * struct netdev_phys_item_id *psid); @@ -1178,8 +1181,9 @@ struct net_device_ops { struct net_device *dev, void *priv); int (*ndo_get_lock_subclass)(struct net_device *dev); - bool (*ndo_gso_check) (struct sk_buff *skb, - struct net_device *dev); + netdev_features_t (*ndo_features_check) (struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features); #ifdef CONFIG_NET_SWITCHDEV int (*ndo_switch_parent_id_get)(struct net_device *dev, struct netdev_phys_item_id *psid); @@ -3611,8 +3615,6 @@ static inline bool netif_needs_gso(struct net_device *dev, struct sk_buff *skb, netdev_features_t features) { return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || - (dev->netdev_ops->ndo_gso_check && - !dev->netdev_ops->ndo_gso_check(skb, dev)) || unlikely((skb->ip_summed != CHECKSUM_PARTIAL) && (skb->ip_summed != CHECKSUM_UNNECESSARY))); } diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 9e572da..02fc86d 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -46,8 +46,8 @@ struct netlink_kernel_cfg { unsigned int flags; void (*input)(struct sk_buff *skb); struct mutex *cb_mutex; - int (*bind)(int group); - void (*unbind)(int group); + int (*bind)(struct net *net, int group); + void (*unbind)(struct net *net, int group); bool (*compare)(struct net *net, struct sock *sk); }; diff --git a/include/net/genetlink.h b/include/net/genetlink.h index af10c2c..8412508 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -31,6 +31,9 @@ struct genl_info; * do additional, common, filtering and return an error * @post_doit: called after an operation's doit callback, it may * undo operations done by pre_doit, for example release locks + * @mcast_bind: a socket bound to the given multicast group (which + * is given as the offset into the groups array) + * @mcast_unbind: a socket was unbound from the given multicast group * @attrbuf: buffer to store parsed attributes * @family_list: family list * @mcgrps: multicast groups used by this family (private) @@ -53,6 +56,8 @@ struct genl_family { void (*post_doit)(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); + int (*mcast_bind)(struct net *net, int group); + void (*mcast_unbind)(struct net *net, int group); struct nlattr ** attrbuf; /* private */ const struct genl_ops * ops; /* private */ const struct genl_multicast_group *mcgrps; /* private */ @@ -395,11 +400,11 @@ static inline int genl_set_err(struct genl_family *family, struct net *net, } static inline int genl_has_listeners(struct genl_family *family, - struct sock *sk, unsigned int group) + struct net *net, unsigned int group) { if (WARN_ON_ONCE(group >= family->n_mcgrps)) return -EINVAL; group = family->mcgrp_offset + group; - return netlink_has_listeners(sk, group); + return netlink_has_listeners(net->genl_sock, group); } #endif /* __NET_GENERIC_NETLINK_H */ diff --git a/include/net/neighbour.h b/include/net/neighbour.h index eb070b3..76f7084 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -190,7 +190,6 @@ struct neigh_hash_table { struct neigh_table { - struct neigh_table *next; int family; int entry_size; int key_len; diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 57cccd0..903461a 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -1,6 +1,9 @@ #ifndef __NET_VXLAN_H #define __NET_VXLAN_H 1 +#include +#include +#include #include #include #include @@ -51,16 +54,33 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be32 vni, bool xnet); -static inline bool vxlan_gso_check(struct sk_buff *skb) +static inline netdev_features_t vxlan_features_check(struct sk_buff *skb, + netdev_features_t features) { - if ((skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) && + u8 l4_hdr = 0; + + if (!skb->encapsulation) + return features; + + switch (vlan_get_protocol(skb)) { + case htons(ETH_P_IP): + l4_hdr = ip_hdr(skb)->protocol; + break; + case htons(ETH_P_IPV6): + l4_hdr = ipv6_hdr(skb)->nexthdr; + break; + default: + return features;; + } + + if ((l4_hdr == IPPROTO_UDP) && (skb->inner_protocol_type != ENCAP_TYPE_ETHER || skb->inner_protocol != htons(ETH_P_TEB) || (skb_inner_mac_header(skb) - skb_transport_header(skb) != sizeof(struct udphdr) + sizeof(struct vxlanhdr)))) - return false; + return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); - return true; + return features; } /* IP header + UDP + VXLAN + Ethernet header */ diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h index 74a2a17..79b12b0 100644 --- a/include/uapi/linux/in6.h +++ b/include/uapi/linux/in6.h @@ -149,7 +149,7 @@ struct in6_flowlabel_req { /* * IPV6 socket options */ - +#if __UAPI_DEF_IPV6_OPTIONS #define IPV6_ADDRFORM 1 #define IPV6_2292PKTINFO 2 #define IPV6_2292HOPOPTS 3 @@ -196,6 +196,7 @@ struct in6_flowlabel_req { #define IPV6_IPSEC_POLICY 34 #define IPV6_XFRM_POLICY 35 +#endif /* * Multicast: diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h index c140620..e28807a 100644 --- a/include/uapi/linux/libc-compat.h +++ b/include/uapi/linux/libc-compat.h @@ -69,6 +69,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 0 #define __UAPI_DEF_IPV6_MREQ 0 #define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 #else @@ -82,6 +83,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 1 #define __UAPI_DEF_IPV6_MREQ 1 #define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 #endif /* _NETINET_IN_H */ @@ -103,6 +105,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 1 #define __UAPI_DEF_IPV6_MREQ 1 #define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 /* Definitions for xattr.h */ #define __UAPI_DEF_XATTR 1 diff --git a/kernel/audit.c b/kernel/audit.c index f8f203e..72ab759 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -429,7 +429,7 @@ static void kauditd_send_skb(struct sk_buff *skb) * This function doesn't consume an skb as might be expected since it has to * copy it anyways. */ -static void kauditd_send_multicast_skb(struct sk_buff *skb) +static void kauditd_send_multicast_skb(struct sk_buff *skb, gfp_t gfp_mask) { struct sk_buff *copy; struct audit_net *aunet = net_generic(&init_net, audit_net_id); @@ -448,11 +448,11 @@ static void kauditd_send_multicast_skb(struct sk_buff *skb) * no reason for new multicast clients to continue with this * non-compliance. */ - copy = skb_copy(skb, GFP_KERNEL); + copy = skb_copy(skb, gfp_mask); if (!copy) return; - nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL); + nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, gfp_mask); } /* @@ -1100,7 +1100,7 @@ static void audit_receive(struct sk_buff *skb) } /* Run custom bind function on netlink socket group connect or bind requests. */ -static int audit_bind(int group) +static int audit_bind(struct net *net, int group) { if (!capable(CAP_AUDIT_READ)) return -EPERM; @@ -1940,7 +1940,7 @@ void audit_log_end(struct audit_buffer *ab) struct nlmsghdr *nlh = nlmsg_hdr(ab->skb); nlh->nlmsg_len = ab->skb->len; - kauditd_send_multicast_skb(ab->skb); + kauditd_send_multicast_skb(ab->skb, ab->gfp_mask); /* * The original kaudit unicast socket sends up messages with diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 3598e13..4f68a32 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -442,19 +442,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) { f->type = AUDIT_LOGINUID_SET; f->val = 0; - } - - if ((f->type == AUDIT_PID) || (f->type == AUDIT_PPID)) { - struct pid *pid; - rcu_read_lock(); - pid = find_vpid(f->val); - if (!pid) { - rcu_read_unlock(); - err = -ESRCH; - goto exit_free; - } - f->val = pid_nr(pid); - rcu_read_unlock(); + entry->rule.pflags |= AUDIT_LOGINUID_LEGACY; } err = audit_field_valid(entry, f); @@ -630,6 +618,13 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule) data->buflen += data->values[i] = audit_pack_string(&bufp, krule->filterkey); break; + case AUDIT_LOGINUID_SET: + if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) { + data->fields[i] = AUDIT_LOGINUID; + data->values[i] = AUDIT_UID_UNSET; + break; + } + /* fallthrough if set */ default: data->values[i] = f->val; } @@ -646,6 +641,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b) int i; if (a->flags != b->flags || + a->pflags != b->pflags || a->listnr != b->listnr || a->action != b->action || a->field_count != b->field_count) @@ -764,6 +760,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old) new = &entry->rule; new->vers_ops = old->vers_ops; new->flags = old->flags; + new->pflags = old->pflags; new->listnr = old->listnr; new->action = old->action; for (i = 0; i < AUDIT_BITMASK_SIZE; i++) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index c75522a..37c69ab 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1877,12 +1877,18 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, } out_alloc: - /* unable to find the name from a previous getname(). Allocate a new - * anonymous entry. - */ - n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); + /* unable to find an entry with both a matching name and type */ + n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); if (!n) return; + if (name) + /* since name is not NULL we know there is already a matching + * name record, see audit_getname(), so there must be a type + * mismatch; reuse the string path since the original name + * record will keep the string valid until we free it in + * audit_free_names() */ + n->name = name; + out: if (parent) { n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5f2ce61..453dc68 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1308,6 +1308,14 @@ config DEBUG_BLOCK_EXT_DEVT Say N if you are unsure. +config CLOSURE_DEBUG + bool "Debug closures" + select DEBUG_FS + ---help--- + Keeps all active closures in a linked list and provides a debugfs + interface to list them, which makes it possible to see asynchronous + operations that get stuck. + config NOTIFIER_ERROR_INJECTION tristate "Notifier error injection" depends on DEBUG_KERNEL diff --git a/lib/Makefile b/lib/Makefile index 3c3b30b..d27b7cf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,7 +26,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ - percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o + percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o closure.o obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += kstrtox.o diff --git a/lib/closure.c b/lib/closure.c new file mode 100644 index 0000000..00283af --- /dev/null +++ b/lib/closure.c @@ -0,0 +1,285 @@ +/* + * Asynchronous refcounty things + * + * Copyright 2010, 2011 Kent Overstreet + * Copyright 2012 Google, Inc. + */ + +#include +#include +#include + +static inline void closure_put_after_sub(struct closure *cl, int flags) +{ + int r = flags & CLOSURE_REMAINING_MASK; + + BUG_ON(flags & CLOSURE_GUARD_MASK); + BUG_ON(!r && (flags & ~CLOSURE_DESTRUCTOR)); + + if (!r) { + if (cl->fn && !(flags & CLOSURE_DESTRUCTOR)) { + atomic_set(&cl->remaining, + CLOSURE_REMAINING_INITIALIZER); + closure_queue(cl); + } else { + struct closure *parent = cl->parent; + closure_fn *destructor = cl->fn; + + closure_debug_destroy(cl); + + if (destructor) + destructor(cl); + + if (parent) + closure_put(parent); + } + } +} + +/* For clearing flags with the same atomic op as a put */ +void closure_sub(struct closure *cl, int v) +{ + closure_put_after_sub(cl, atomic_sub_return(v, &cl->remaining)); +} +EXPORT_SYMBOL(closure_sub); + +/** + * closure_put - decrement a closure's refcount + */ +void closure_put(struct closure *cl) +{ + closure_put_after_sub(cl, atomic_dec_return(&cl->remaining)); +} +EXPORT_SYMBOL(closure_put); + +/** + * closure_wake_up - wake up all closures on a wait list, without memory barrier + */ +void __closure_wake_up(struct closure_waitlist *wait_list) +{ + struct llist_node *list; + struct closure *cl; + struct llist_node *reverse = NULL; + + list = llist_del_all(&wait_list->list); + + /* We first reverse the list to preserve FIFO ordering and fairness */ + + while (list) { + struct llist_node *t = list; + list = llist_next(list); + + t->next = reverse; + reverse = t; + } + + /* Then do the wakeups */ + + while (reverse) { + cl = container_of(reverse, struct closure, list); + reverse = llist_next(reverse); + + closure_set_waiting(cl, 0); + closure_sub(cl, CLOSURE_WAITING + 1); + } +} +EXPORT_SYMBOL(__closure_wake_up); + +/** + * closure_wait - add a closure to a waitlist + * + * @waitlist will own a ref on @cl, which will be released when + * closure_wake_up() is called on @waitlist. + * + */ +bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl) +{ + if (atomic_read(&cl->remaining) & CLOSURE_WAITING) + return false; + + closure_set_waiting(cl, _RET_IP_); + atomic_add(CLOSURE_WAITING + 1, &cl->remaining); + llist_add(&cl->list, &waitlist->list); + + return true; +} +EXPORT_SYMBOL(closure_wait); + +struct closure_sleeper { + struct hrtimer timer; + struct task_struct *task; + struct closure_waitlist *waitlist; + + int ret; + int done; +}; + +static void closure_sync_fn(struct closure *cl) +{ + struct closure_sleeper *s = cl->complete; + + s->done = 1; + wake_up_process(s->task); +} + +static void do_closure_sync(struct closure *cl, + struct closure_sleeper *s, + long state) +{ + cl->complete = s; + continue_at_noreturn(cl, closure_sync_fn, NULL); + + while (1) { + set_current_state(state); + if (signal_pending_state(state, current)) { + s->ret = -ERESTARTSYS; + closure_wake_up(s->waitlist); + } + + if (s->done) + break; + schedule(); + + } + __set_current_state(TASK_RUNNING); +} + +static enum hrtimer_restart closure_sync_timeout_fn(struct hrtimer *timer) +{ + struct closure_sleeper *s = + container_of(timer, struct closure_sleeper, timer); + + s->ret = -ETIME; + closure_wake_up(s->waitlist); + + return HRTIMER_NORESTART; +} + +int __closure_sync_interruptible_hrtimeout(struct closure *cl, + struct closure_waitlist *waitlist, + ktime_t until) +{ + struct closure_sleeper s; + + s.task = current; + s.waitlist = waitlist; + s.ret = 0; + s.done = 0; + + if (until.tv64 != KTIME_MAX) { + hrtimer_init_on_stack(&s.timer, + CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + s.timer.function = closure_sync_timeout_fn; + + hrtimer_start_range_ns(&s.timer, until, + current->timer_slack_ns, + HRTIMER_MODE_ABS); + } + + do_closure_sync(cl, &s, TASK_INTERRUPTIBLE); + + if (until.tv64 != KTIME_MAX) { + hrtimer_cancel(&s.timer); + destroy_hrtimer_on_stack(&s.timer); + } + + return s.ret; +} +EXPORT_SYMBOL(__closure_sync_interruptible_hrtimeout); + +void __closure_sync(struct closure *cl) +{ + struct closure_sleeper s; + + s.task = current; + s.waitlist = NULL; + s.ret = 0; + s.done = 0; + + do_closure_sync(cl, &s, TASK_UNINTERRUPTIBLE); +} +EXPORT_SYMBOL(__closure_sync); + +#ifdef CONFIG_CLOSURE_DEBUG + +static LIST_HEAD(closure_list); +static DEFINE_SPINLOCK(closure_list_lock); + +void closure_debug_create(struct closure *cl) +{ + unsigned long flags; + + BUG_ON(cl->magic == CLOSURE_MAGIC_ALIVE); + cl->magic = CLOSURE_MAGIC_ALIVE; + + spin_lock_irqsave(&closure_list_lock, flags); + list_add(&cl->all, &closure_list); + spin_unlock_irqrestore(&closure_list_lock, flags); +} +EXPORT_SYMBOL(closure_debug_create); + +void closure_debug_destroy(struct closure *cl) +{ + unsigned long flags; + + BUG_ON(cl->magic != CLOSURE_MAGIC_ALIVE); + cl->magic = CLOSURE_MAGIC_DEAD; + + spin_lock_irqsave(&closure_list_lock, flags); + list_del(&cl->all); + spin_unlock_irqrestore(&closure_list_lock, flags); +} +EXPORT_SYMBOL(closure_debug_destroy); + +static struct dentry *debug; + +#define work_data_bits(work) ((unsigned long *)(&(work)->data)) + +static int debug_seq_show(struct seq_file *f, void *data) +{ + struct closure *cl; + spin_lock_irq(&closure_list_lock); + + list_for_each_entry(cl, &closure_list, all) { + int r = atomic_read(&cl->remaining); + + seq_printf(f, "%p: %pF -> %pf p %p r %i ", + cl, (void *) cl->ip, cl->fn, cl->parent, + r & CLOSURE_REMAINING_MASK); + + seq_printf(f, "%s%s\n", + test_bit(WORK_STRUCT_PENDING, + work_data_bits(&cl->work)) ? "Q" : "", + r & CLOSURE_RUNNING ? "R" : ""); + + if (r & CLOSURE_WAITING) + seq_printf(f, " W %pF\n", + (void *) cl->waiting_on); + + seq_printf(f, "\n"); + } + + spin_unlock_irq(&closure_list_lock); + return 0; +} + +static int debug_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, debug_seq_show, NULL); +} + +static const struct file_operations debug_ops = { + .open = debug_seq_open, + .read = seq_read, + .release = single_release +}; + +static int __init closure_debug_init(void) +{ + debug = debugfs_create_file("closures", 0400, NULL, NULL, &debug_ops); + return 0; +} +late_initcall(closure_debug_init); + +#endif diff --git a/mm/memory.c b/mm/memory.c index 649e7d4..ca920d1 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2378,12 +2378,12 @@ void unmap_mapping_range(struct address_space *mapping, details.last_index = ULONG_MAX; - i_mmap_lock_read(mapping); + i_mmap_lock_write(mapping); if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) unmap_mapping_range_tree(&mapping->i_mmap, &details); if (unlikely(!list_empty(&mapping->i_mmap_nonlinear))) unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details); - i_mmap_unlock_read(mapping); + i_mmap_unlock_write(mapping); } EXPORT_SYMBOL(unmap_mapping_range); diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index fc1835c..00f9e14 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -251,7 +251,7 @@ batadv_frag_merge_packets(struct hlist_head *chain, struct sk_buff *skb) kfree(entry); /* Make room for the rest of the fragments. */ - if (pskb_expand_head(skb_out, 0, size - skb->len, GFP_ATOMIC) < 0) { + if (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) { kfree_skb(skb_out); skb_out = NULL; goto free; @@ -434,7 +434,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb, * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE */ mtu = min_t(unsigned, mtu, BATADV_FRAG_MAX_FRAG_SIZE); - max_fragment_size = (mtu - header_size - ETH_HLEN); + max_fragment_size = mtu - header_size; max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS; /* Don't even try to fragment, if we need more than 16 fragments */ diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 90cff58..e0bcf9e 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -810,7 +810,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, goto out; gw_node = batadv_gw_node_get(bat_priv, orig_dst_node); - if (!gw_node->bandwidth_down == 0) + if (!gw_node) goto out; switch (atomic_read(&bat_priv->gw_mode)) { diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 76617be..c989253 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -390,7 +390,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, drop: dev->stats.rx_dropped++; - kfree_skb(skb); return NET_RX_DROP; } diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 85bcc21..ce82722d 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -533,6 +533,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) BT_DBG(""); + if (!l2cap_is_socket(sock)) + return -EBADFD; + baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst); baswap((void *) src, &l2cap_pi(sock->sk)->chan->src); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 67fe5e8..278a194 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -334,6 +334,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) BT_DBG(""); + if (!l2cap_is_socket(sock)) + return -EBADFD; + session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL); if (!session) return -ENOMEM; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 39a5c8a..3f2e8b8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -242,7 +242,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - if (test_bit(HCI_SETUP, &hdev->dev_flags)) + if (test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags)) memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } @@ -509,7 +510,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - if (test_bit(HCI_SETUP, &hdev->dev_flags)) { + if (test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags)) { hdev->hci_ver = rp->hci_ver; hdev->hci_rev = __le16_to_cpu(rp->hci_rev); hdev->lmp_ver = rp->lmp_ver; @@ -528,7 +530,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, if (rp->status) return; - if (test_bit(HCI_SETUP, &hdev->dev_flags)) + if (test_bit(HCI_SETUP, &hdev->dev_flags) || + test_bit(HCI_CONFIG, &hdev->dev_flags)) memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); } @@ -2194,7 +2197,12 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) return; } - if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && + /* Require HCI_CONNECTABLE or a whitelist entry to accept the + * connection. These features are only touched through mgmt so + * only do the checks if HCI_MGMT is set. + */ + if (test_bit(HCI_MGMT, &hdev->dev_flags) && + !test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && !hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, BDADDR_BREDR)) { hci_reject_conn(hdev, &ev->bdaddr); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index cc25d0b..07348e1 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -1314,13 +1314,14 @@ int hidp_connection_add(struct hidp_connadd_req *req, { struct hidp_session *session; struct l2cap_conn *conn; - struct l2cap_chan *chan = l2cap_pi(ctrl_sock->sk)->chan; + struct l2cap_chan *chan; int ret; ret = hidp_verify_sockets(ctrl_sock, intr_sock); if (ret) return ret; + chan = l2cap_pi(ctrl_sock->sk)->chan; conn = NULL; l2cap_chan_lock(chan); if (chan->conn) diff --git a/net/core/dev.c b/net/core/dev.c index f411c28..683d493 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1694,6 +1694,7 @@ int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb) skb_scrub_packet(skb, true); skb->protocol = eth_type_trans(skb, dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); return 0; } @@ -2522,7 +2523,7 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) /* If MPLS offload request, verify we are testing hardware MPLS features * instead of standard features for the netdev. */ -#ifdef CONFIG_NET_MPLS_GSO +#if IS_ENABLED(CONFIG_NET_MPLS_GSO) static netdev_features_t net_mpls_features(struct sk_buff *skb, netdev_features_t features, __be16 type) @@ -2562,7 +2563,7 @@ static netdev_features_t harmonize_features(struct sk_buff *skb, netdev_features_t netif_skb_features(struct sk_buff *skb) { - const struct net_device *dev = skb->dev; + struct net_device *dev = skb->dev; netdev_features_t features = dev->features; u16 gso_segs = skb_shinfo(skb)->gso_segs; __be16 protocol = skb->protocol; @@ -2570,11 +2571,21 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs) features &= ~NETIF_F_GSO_MASK; - if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) { - struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; - protocol = veh->h_vlan_encapsulated_proto; - } else if (!vlan_tx_tag_present(skb)) { - return harmonize_features(skb, features); + /* If encapsulation offload request, verify we are testing + * hardware encapsulation features instead of standard + * features for the netdev + */ + if (skb->encapsulation) + features &= dev->hw_enc_features; + + if (!vlan_tx_tag_present(skb)) { + if (unlikely(protocol == htons(ETH_P_8021Q) || + protocol == htons(ETH_P_8021AD))) { + struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; + protocol = veh->h_vlan_encapsulated_proto; + } else { + goto finalize; + } } features = netdev_intersect_features(features, @@ -2591,6 +2602,11 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); +finalize: + if (dev->netdev_ops->ndo_features_check) + features &= dev->netdev_ops->ndo_features_check(skb, dev, + features); + return harmonize_features(skb, features); } EXPORT_SYMBOL(netif_skb_features); @@ -2661,19 +2677,12 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device if (unlikely(!skb)) goto out_null; - /* If encapsulation offload request, verify we are testing - * hardware encapsulation features instead of standard - * features for the netdev - */ - if (skb->encapsulation) - features &= dev->hw_enc_features; - if (netif_needs_gso(dev, skb, features)) { struct sk_buff *segs; segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { - segs = NULL; + goto out_kfree_skb; } else if (segs) { consume_skb(skb); skb = segs; @@ -4557,6 +4566,68 @@ void netif_napi_del(struct napi_struct *napi) } EXPORT_SYMBOL(netif_napi_del); +static int napi_poll(struct napi_struct *n, struct list_head *repoll) +{ + void *have; + int work, weight; + + list_del_init(&n->poll_list); + + have = netpoll_poll_lock(n); + + weight = n->weight; + + /* This NAPI_STATE_SCHED test is for avoiding a race + * with netpoll's poll_napi(). Only the entity which + * obtains the lock and sees NAPI_STATE_SCHED set will + * actually make the ->poll() call. Therefore we avoid + * accidentally calling ->poll() when NAPI is not scheduled. + */ + work = 0; + if (test_bit(NAPI_STATE_SCHED, &n->state)) { + work = n->poll(n, weight); + trace_napi_poll(n); + } + + WARN_ON_ONCE(work > weight); + + if (likely(work < weight)) + goto out_unlock; + + /* Drivers must not modify the NAPI state if they + * consume the entire weight. In such cases this code + * still "owns" the NAPI instance and therefore can + * move the instance around on the list at-will. + */ + if (unlikely(napi_disable_pending(n))) { + napi_complete(n); + goto out_unlock; + } + + if (n->gro_list) { + /* flush too old packets + * If HZ < 1000, flush all packets. + */ + napi_gro_flush(n, HZ >= 1000); + } + + /* Some drivers may have called napi_schedule + * prior to exhausting their budget. + */ + if (unlikely(!list_empty(&n->poll_list))) { + pr_warn_once("%s: Budget exhausted after napi rescheduled\n", + n->dev ? n->dev->name : "backlog"); + goto out_unlock; + } + + list_add_tail(&n->poll_list, repoll); + +out_unlock: + netpoll_poll_unlock(have); + + return work; +} + static void net_rx_action(struct softirq_action *h) { struct softnet_data *sd = this_cpu_ptr(&softnet_data); @@ -4564,74 +4635,34 @@ static void net_rx_action(struct softirq_action *h) int budget = netdev_budget; LIST_HEAD(list); LIST_HEAD(repoll); - void *have; local_irq_disable(); list_splice_init(&sd->poll_list, &list); local_irq_enable(); - while (!list_empty(&list)) { + for (;;) { struct napi_struct *n; - int work, weight; - - /* If softirq window is exhausted then punt. - * Allow this to run for 2 jiffies since which will allow - * an average latency of 1.5/HZ. - */ - if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit))) - goto softnet_break; - - - n = list_first_entry(&list, struct napi_struct, poll_list); - list_del_init(&n->poll_list); - have = netpoll_poll_lock(n); - - weight = n->weight; - - /* This NAPI_STATE_SCHED test is for avoiding a race - * with netpoll's poll_napi(). Only the entity which - * obtains the lock and sees NAPI_STATE_SCHED set will - * actually make the ->poll() call. Therefore we avoid - * accidentally calling ->poll() when NAPI is not scheduled. - */ - work = 0; - if (test_bit(NAPI_STATE_SCHED, &n->state)) { - work = n->poll(n, weight); - trace_napi_poll(n); + if (list_empty(&list)) { + if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll)) + return; + break; } - WARN_ON_ONCE(work > weight); - - budget -= work; + n = list_first_entry(&list, struct napi_struct, poll_list); + budget -= napi_poll(n, &repoll); - /* Drivers must not modify the NAPI state if they - * consume the entire weight. In such cases this code - * still "owns" the NAPI instance and therefore can - * move the instance around on the list at-will. + /* If softirq window is exhausted then punt. + * Allow this to run for 2 jiffies since which will allow + * an average latency of 1.5/HZ. */ - if (unlikely(work == weight)) { - if (unlikely(napi_disable_pending(n))) { - napi_complete(n); - } else { - if (n->gro_list) { - /* flush too old packets - * If HZ < 1000, flush all packets. - */ - napi_gro_flush(n, HZ >= 1000); - } - list_add_tail(&n->poll_list, &repoll); - } + if (unlikely(budget <= 0 || + time_after_eq(jiffies, time_limit))) { + sd->time_squeeze++; + break; } - - netpoll_poll_unlock(have); } - if (!sd_has_rps_ipi_waiting(sd) && - list_empty(&list) && - list_empty(&repoll)) - return; -out: local_irq_disable(); list_splice_tail_init(&sd->poll_list, &list); @@ -4641,12 +4672,6 @@ out: __raise_softirq_irqoff(NET_RX_SOFTIRQ); net_rps_action_and_irq_enable(sd); - - return; - -softnet_break: - sd->time_squeeze++; - goto out; } struct netdev_adjacent { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ae13ef6..395c15b 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4148,6 +4148,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet) skb->ignore_df = 0; skb_dst_drop(skb); skb->mark = 0; + skb_init_secmark(skb); secpath_reset(skb); nf_reset(skb); nf_reset_trace(skb); diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 95e47c9..394a200 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -122,14 +122,18 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, int err; skb = udp_tunnel_handle_offloads(skb, !gs->sock->sk->sk_no_check_tx); + if (IS_ERR(skb)) + return PTR_ERR(skb); min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr) + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) + if (unlikely(err)) { + kfree_skb(skb); return err; + } skb = vlan_hwaccel_push_inside(skb); if (unlikely(!skb)) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5ff8780..9c0b54e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1387,6 +1387,28 @@ ipv6_pktoptions: return 0; } +static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, + const struct tcphdr *th) +{ + /* This is tricky: we move IP6CB at its correct location into + * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because + * _decode_session6() uses IP6CB(). + * barrier() makes sure compiler won't play aliasing games. + */ + memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), + sizeof(struct inet6_skb_parm)); + barrier(); + + TCP_SKB_CB(skb)->seq = ntohl(th->seq); + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + + skb->len - th->doff*4); + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); + TCP_SKB_CB(skb)->tcp_tw_isn = 0; + TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); + TCP_SKB_CB(skb)->sacked = 0; +} + static int tcp_v6_rcv(struct sk_buff *skb) { const struct tcphdr *th; @@ -1418,24 +1440,9 @@ static int tcp_v6_rcv(struct sk_buff *skb) th = tcp_hdr(skb); hdr = ipv6_hdr(skb); - /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() - * barrier() makes sure compiler wont play fool^Waliasing games. - */ - memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), - sizeof(struct inet6_skb_parm)); - barrier(); - - TCP_SKB_CB(skb)->seq = ntohl(th->seq); - TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - skb->len - th->doff*4); - TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); - TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; - TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); - TCP_SKB_CB(skb)->sacked = 0; sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest, - tcp_v6_iif(skb)); + inet6_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1451,6 +1458,8 @@ process: if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto discard_and_relse; + tcp_v6_fill_cb(skb, hdr, th); + #ifdef CONFIG_TCP_MD5SIG if (tcp_v6_inbound_md5_hash(sk, skb)) goto discard_and_relse; @@ -1482,6 +1491,8 @@ no_tcp_socket: if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; + tcp_v6_fill_cb(skb, hdr, th); + if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { csum_error: TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS); @@ -1505,6 +1516,8 @@ do_time_wait: goto discard_it; } + tcp_v6_fill_cb(skb, hdr, th); + if (skb->len < (th->doff<<2)) { inet_twsk_put(inet_twsk(sk)); goto bad_packet; diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index ca27837..349295d 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c @@ -31,10 +31,7 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, SKB_GSO_TCPV6 | SKB_GSO_UDP | SKB_GSO_DODGY | - SKB_GSO_TCP_ECN | - SKB_GSO_GRE | - SKB_GSO_GRE_CSUM | - SKB_GSO_IPIP))) + SKB_GSO_TCP_ECN))) goto out; /* Setup inner SKB. */ diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 13c2e17..cde4a67 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -463,7 +463,7 @@ static void nfnetlink_rcv(struct sk_buff *skb) } #ifdef CONFIG_MODULES -static int nfnetlink_bind(int group) +static int nfnetlink_bind(struct net *net, int group) { const struct nfnetlink_subsystem *ss; int type; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 074cf3e..562d386 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1091,8 +1091,10 @@ static void netlink_remove(struct sock *sk) mutex_unlock(&nl_sk_hash_lock); netlink_table_grab(); - if (nlk_sk(sk)->subscriptions) + if (nlk_sk(sk)->subscriptions) { __sk_del_bind_node(sk); + netlink_update_listeners(sk); + } netlink_table_ungrab(); } @@ -1139,8 +1141,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol, struct module *module = NULL; struct mutex *cb_mutex; struct netlink_sock *nlk; - int (*bind)(int group); - void (*unbind)(int group); + int (*bind)(struct net *net, int group); + void (*unbind)(struct net *net, int group); int err = 0; sock->state = SS_UNCONNECTED; @@ -1226,8 +1228,8 @@ static int netlink_release(struct socket *sock) module_put(nlk->module); - netlink_table_grab(); if (netlink_is_kernel(sk)) { + netlink_table_grab(); BUG_ON(nl_table[sk->sk_protocol].registered == 0); if (--nl_table[sk->sk_protocol].registered == 0) { struct listeners *old; @@ -1241,11 +1243,16 @@ static int netlink_release(struct socket *sock) nl_table[sk->sk_protocol].flags = 0; nl_table[sk->sk_protocol].registered = 0; } - } else if (nlk->subscriptions) { - netlink_update_listeners(sk); + netlink_table_ungrab(); } - netlink_table_ungrab(); + if (nlk->netlink_unbind) { + int i; + + for (i = 0; i < nlk->ngroups; i++) + if (test_bit(i, nlk->groups)) + nlk->netlink_unbind(sock_net(sk), i + 1); + } kfree(nlk->groups); nlk->groups = NULL; @@ -1410,9 +1417,10 @@ static int netlink_realloc_groups(struct sock *sk) return err; } -static void netlink_unbind(int group, long unsigned int groups, - struct netlink_sock *nlk) +static void netlink_undo_bind(int group, long unsigned int groups, + struct sock *sk) { + struct netlink_sock *nlk = nlk_sk(sk); int undo; if (!nlk->netlink_unbind) @@ -1420,7 +1428,7 @@ static void netlink_unbind(int group, long unsigned int groups, for (undo = 0; undo < group; undo++) if (test_bit(undo, &groups)) - nlk->netlink_unbind(undo); + nlk->netlink_unbind(sock_net(sk), undo); } static int netlink_bind(struct socket *sock, struct sockaddr *addr, @@ -1458,10 +1466,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, for (group = 0; group < nlk->ngroups; group++) { if (!test_bit(group, &groups)) continue; - err = nlk->netlink_bind(group); + err = nlk->netlink_bind(net, group); if (!err) continue; - netlink_unbind(group, groups, nlk); + netlink_undo_bind(group, groups, sk); return err; } } @@ -1471,7 +1479,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, netlink_insert(sk, net, nladdr->nl_pid) : netlink_autobind(sock); if (err) { - netlink_unbind(nlk->ngroups, groups, nlk); + netlink_undo_bind(nlk->ngroups, groups, sk); return err; } } @@ -1976,8 +1984,10 @@ int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid netlink_lock_table(); - sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) + sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) { do_one_broadcast(sk, &info); + cond_resched(); + } consume_skb(skb); @@ -2122,7 +2132,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, if (!val || val - 1 >= nlk->ngroups) return -EINVAL; if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { - err = nlk->netlink_bind(val); + err = nlk->netlink_bind(sock_net(sk), val); if (err) return err; } @@ -2131,7 +2141,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, optname == NETLINK_ADD_MEMBERSHIP); netlink_table_ungrab(); if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) - nlk->netlink_unbind(val); + nlk->netlink_unbind(sock_net(sk), val); err = 0; break; diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index b20a173..f123a88 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -39,8 +39,8 @@ struct netlink_sock { struct mutex *cb_mutex; struct mutex cb_def_mutex; void (*netlink_rcv)(struct sk_buff *skb); - int (*netlink_bind)(int group); - void (*netlink_unbind)(int group); + int (*netlink_bind)(struct net *net, int group); + void (*netlink_unbind)(struct net *net, int group); struct module *module; #ifdef CONFIG_NETLINK_MMAP struct mutex pg_vec_lock; @@ -65,8 +65,8 @@ struct netlink_table { unsigned int groups; struct mutex *cb_mutex; struct module *module; - int (*bind)(int group); - void (*unbind)(int group); + int (*bind)(struct net *net, int group); + void (*unbind)(struct net *net, int group); bool (*compare)(struct net *net, struct sock *sock); int registered; }; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 76393f2..5cfbcea 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -983,11 +983,74 @@ static struct genl_multicast_group genl_ctrl_groups[] = { { .name = "notify", }, }; +static int genl_bind(struct net *net, int group) +{ + int i, err; + bool found = false; + + down_read(&cb_lock); + for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { + struct genl_family *f; + + list_for_each_entry(f, genl_family_chain(i), family_list) { + if (group >= f->mcgrp_offset && + group < f->mcgrp_offset + f->n_mcgrps) { + int fam_grp = group - f->mcgrp_offset; + + if (!f->netnsok && net != &init_net) + err = -ENOENT; + else if (f->mcast_bind) + err = f->mcast_bind(net, fam_grp); + else + err = 0; + found = true; + break; + } + } + } + up_read(&cb_lock); + +#if 0 + if (WARN_ON(!found)) + err = 0; +#endif + + return err; +} + +static void genl_unbind(struct net *net, int group) +{ + int i; + bool found = false; + + down_read(&cb_lock); + for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { + struct genl_family *f; + + list_for_each_entry(f, genl_family_chain(i), family_list) { + if (group >= f->mcgrp_offset && + group < f->mcgrp_offset + f->n_mcgrps) { + int fam_grp = group - f->mcgrp_offset; + + if (f->mcast_unbind) + f->mcast_unbind(net, fam_grp); + found = true; + break; + } + } + } + up_read(&cb_lock); + + WARN_ON(!found); +} + static int __net_init genl_pernet_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = genl_rcv, .flags = NL_CFG_F_NONROOT_RECV, + .bind = genl_bind, + .unbind = genl_unbind, }; /* we'll bump the group number right afterwards */ diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 764fdc3..770064c 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -147,7 +147,8 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, hdr = eth_hdr(skb); hdr->h_proto = mpls->mpls_ethertype; - skb_set_inner_protocol(skb, skb->protocol); + if (!skb->inner_protocol) + skb_set_inner_protocol(skb, skb->protocol); skb->protocol = mpls->mpls_ethertype; invalidate_flow_key(key); diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 332b5a0..4e9a5f0 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -83,8 +83,7 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info, unsigned int group) { return info->nlhdr->nlmsg_flags & NLM_F_ECHO || - genl_has_listeners(family, genl_info_net(info)->genl_sock, - group); + genl_has_listeners(family, genl_info_net(info), group); } static void ovs_notify(struct genl_family *family, diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 9645a21..d1eecf7 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1753,7 +1753,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, __be16 eth_type, __be16 vlan_tci, bool log) { const struct nlattr *a; - bool out_tnl_port = false; int rem, err; if (depth >= SAMPLE_ACTION_DEPTH) @@ -1796,8 +1795,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_OUTPUT: if (nla_get_u32(a) >= DP_MAX_PORTS) return -EINVAL; - out_tnl_port = false; - break; case OVS_ACTION_ATTR_HASH: { @@ -1832,12 +1829,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nla_data(a); - /* Networking stack do not allow simultaneous Tunnel - * and MPLS GSO. - */ - if (out_tnl_port) - return -EINVAL; - if (!eth_p_mpls(mpls->mpls_ethertype)) return -EINVAL; /* Prohibit push MPLS other than to a white list @@ -1873,11 +1864,9 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_SET: err = validate_set(a, key, sfa, - &out_tnl_port, eth_type, log); + &skip_copy, eth_type, log); if (err) return err; - - skip_copy = out_tnl_port; break; case OVS_ACTION_ATTR_SAMPLE: diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 347fa23..484864d 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -219,7 +219,10 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) false); if (err < 0) ip_rt_put(rt); + return err; + error: + kfree_skb(skb); return err; } diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 6b69df5..d4168c4 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -73,7 +73,7 @@ static struct sk_buff *__build_header(struct sk_buff *skb, skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); if (IS_ERR(skb)) - return NULL; + return skb; tpi.flags = filter_tnl_flags(tun_key->tun_flags); tpi.proto = htons(ETH_P_TEB); @@ -144,7 +144,7 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) if (unlikely(!OVS_CB(skb)->egress_tun_info)) { err = -EINVAL; - goto error; + goto err_free_skb; } tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; @@ -157,8 +157,10 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) fl.flowi4_proto = IPPROTO_GRE; rt = ip_route_output_key(net, &fl); - if (IS_ERR(rt)) - return PTR_ERR(rt); + if (IS_ERR(rt)) { + err = PTR_ERR(rt); + goto err_free_skb; + } tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags); @@ -183,8 +185,9 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) /* Push Tunnel header. */ skb = __build_header(skb, tunnel_hlen); - if (unlikely(!skb)) { - err = 0; + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + skb = NULL; goto err_free_rt; } @@ -198,7 +201,8 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) tun_key->ipv4_tos, tun_key->ipv4_ttl, df, false); err_free_rt: ip_rt_put(rt); -error: +err_free_skb: + kfree_skb(skb); return err; } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 38f95a5..d7c46b3 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -187,7 +187,9 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) false); if (err < 0) ip_rt_put(rt); + return err; error: + kfree_skb(skb); return err; } diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 9584526..53f3ebb 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -519,10 +519,9 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb) u64_stats_update_end(&stats->syncp); } else if (sent < 0) { ovs_vport_record_error(vport, VPORT_E_TX_ERROR); - kfree_skb(skb); - } else + } else { ovs_vport_record_error(vport, VPORT_E_TX_DROPPED); - + } return sent; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e52a447..6880f34 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -785,6 +785,7 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1, struct tpacket3_hdr *last_pkt; struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1; + struct sock *sk = &po->sk; if (po->stats.stats3.tp_drops) status |= TP_STATUS_LOSING; @@ -809,6 +810,8 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1, /* Flush the block */ prb_flush_block(pkc1, pbd1, status); + sk->sk_data_ready(sk); + pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1); } @@ -2052,12 +2055,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, smp_wmb(); #endif - if (po->tp_version <= TPACKET_V2) + if (po->tp_version <= TPACKET_V2) { __packet_set_status(po, h.raw, status); - else + sk->sk_data_ready(sk); + } else { prb_clear_blk_fill_status(&po->rx_ring); - - sk->sk_data_ready(sk); + } drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 5972624..7a60d1a 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -217,9 +217,22 @@ else fi maintainer="$name <$email>" +# Try to determine distribution +if [ -e $(which lsb_release) ]; then + codename=$(lsb_release --codename --short) + if [ "$codename" != "" ]; then + distribution=$codename + else + distribution="UNRELEASED" + echo "WARNING: The distribution could NOT be determined!" + fi +else + echo "HINT: Install lsb_release binary, this helps to identify your distribution!" +fi + # Generate a simple changelog template cat < debian/changelog -linux-upstream ($packageversion) unstable; urgency=low +linux-upstream ($packageversion) $distribution; urgency=low * Custom built Linux kernel. @@ -233,10 +246,10 @@ This is a packacked upstream version of the Linux kernel. The sources may be found at most Linux ftp sites, including: ftp://ftp.kernel.org/pub/linux/kernel -Copyright: 1991 - 2009 Linus Torvalds and others. +Copyright: 1991 - 2014 Linus Torvalds and others. The git repository for mainline kernel development is at: -git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git +git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 8276a74..0cfc9c8 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -1922,10 +1922,18 @@ int azx_mixer_create(struct azx *chip) EXPORT_SYMBOL_GPL(azx_mixer_create); +static bool is_input_stream(struct azx *chip, unsigned char index) +{ + return (index >= chip->capture_index_offset && + index < chip->capture_index_offset + chip->capture_streams); +} + /* initialize SD streams */ int azx_init_stream(struct azx *chip) { int i; + int in_stream_tag = 0; + int out_stream_tag = 0; /* initialize each stream (aka device) * assign the starting bdl address to each stream (device) @@ -1938,9 +1946,21 @@ int azx_init_stream(struct azx *chip) azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ azx_dev->sd_int_sta_mask = 1 << i; - /* stream tag: must be non-zero and unique */ azx_dev->index = i; - azx_dev->stream_tag = i + 1; + + /* stream tag must be unique throughout + * the stream direction group, + * valid values 1...15 + * use separate stream tag if the flag + * AZX_DCAPS_SEPARATE_STREAM_TAG is used + */ + if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) + azx_dev->stream_tag = + is_input_stream(chip, i) ? + ++in_stream_tag : + ++out_stream_tag; + else + azx_dev->stream_tag = i + 1; } return 0; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2bf0b56..d426a0b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -299,6 +299,9 @@ enum { AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ AZX_DCAPS_SNOOP_TYPE(SCH)) +#define AZX_DCAPS_INTEL_SKYLAKE \ + (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG) + /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\ @@ -2027,7 +2030,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index aa484fd..166e3e8 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ +#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ enum { AZX_SNOOP_TYPE_NONE ,