Merge 5.10.81 into android12-5.10-lts
Changes in 5.10.81 fortify: Explicitly disable Clang support block: Add a helper to validate the block size loop: Use blk_validate_block_size() to validate block size bootconfig: init: Fix memblock leak in xbc_make_cmdline() net: stmmac: add clocks management for gmac driver net: stmmac: platform: fix build error with !CONFIG_PM_SLEEP net: stmmac: fix missing unlock on error in stmmac_suspend() net: stmmac: fix system hang if change mac address after interface ifdown net: stmmac: fix issue where clk is being unprepared twice net: stmmac: dwmac-rk: fix unbalanced pm_runtime_enable warnings x86/iopl: Fake iopl(3) CLI/STI usage parisc/entry: fix trace test in syscall exit path PCI/MSI: Destroy sysfs before freeing entries PCI/MSI: Deal with devices lying about their MSI mask capability PCI: Add MSI masking quirk for Nvidia ION AHCI erofs: remove the occupied parameter from z_erofs_pagevec_enqueue() erofs: fix unsafe pagevec reuse of hooked pclusters scripts/lld-version.sh: Rewrite based on upstream ld-version.sh perf/core: Avoid put_page() when GUP fails thermal: Fix NULL pointer dereferences in of_thermal_ functions selftests/x86/iopl: Adjust to the faked iopl CLI/STI usage Linux 5.10.81 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ic5ba37cba892391e62596f4c342d36a8f66e4647
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
VERSION = 5
|
VERSION = 5
|
||||||
PATCHLEVEL = 10
|
PATCHLEVEL = 10
|
||||||
SUBLEVEL = 80
|
SUBLEVEL = 81
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =
|
||||||
NAME = Dare mighty things
|
NAME = Dare mighty things
|
||||||
|
|
||||||
|
@@ -1849,7 +1849,7 @@ syscall_restore:
|
|||||||
|
|
||||||
/* Are we being ptraced? */
|
/* Are we being ptraced? */
|
||||||
LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
|
LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
|
||||||
ldi _TIF_SYSCALL_TRACE_MASK,%r2
|
ldi _TIF_SINGLESTEP|_TIF_BLOCKSTEP,%r2
|
||||||
and,COND(=) %r19,%r2,%r0
|
and,COND(=) %r19,%r2,%r0
|
||||||
b,n syscall_restore_rfi
|
b,n syscall_restore_rfi
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs);
|
|||||||
int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs);
|
int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs);
|
||||||
unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
|
unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx);
|
||||||
int insn_get_code_seg_params(struct pt_regs *regs);
|
int insn_get_code_seg_params(struct pt_regs *regs);
|
||||||
|
unsigned long insn_get_effective_ip(struct pt_regs *regs);
|
||||||
int insn_fetch_from_user(struct pt_regs *regs,
|
int insn_fetch_from_user(struct pt_regs *regs,
|
||||||
unsigned char buf[MAX_INSN_SIZE]);
|
unsigned char buf[MAX_INSN_SIZE]);
|
||||||
int insn_fetch_from_user_inatomic(struct pt_regs *regs,
|
int insn_fetch_from_user_inatomic(struct pt_regs *regs,
|
||||||
|
@@ -534,6 +534,7 @@ struct thread_struct {
|
|||||||
*/
|
*/
|
||||||
unsigned long iopl_emul;
|
unsigned long iopl_emul;
|
||||||
|
|
||||||
|
unsigned int iopl_warn:1;
|
||||||
unsigned int sig_on_uaccess_err:1;
|
unsigned int sig_on_uaccess_err:1;
|
||||||
|
|
||||||
/* Floating point and extended processor state */
|
/* Floating point and extended processor state */
|
||||||
|
@@ -138,6 +138,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
|
|||||||
frame->ret_addr = (unsigned long) ret_from_fork;
|
frame->ret_addr = (unsigned long) ret_from_fork;
|
||||||
p->thread.sp = (unsigned long) fork_frame;
|
p->thread.sp = (unsigned long) fork_frame;
|
||||||
p->thread.io_bitmap = NULL;
|
p->thread.io_bitmap = NULL;
|
||||||
|
p->thread.iopl_warn = 0;
|
||||||
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
|
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
@@ -523,6 +523,37 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
|
|||||||
|
|
||||||
#define GPFSTR "general protection fault"
|
#define GPFSTR "general protection fault"
|
||||||
|
|
||||||
|
static bool fixup_iopl_exception(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct thread_struct *t = ¤t->thread;
|
||||||
|
unsigned char byte;
|
||||||
|
unsigned long ip;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_X86_IOPL_IOPERM) || t->iopl_emul != 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ip = insn_get_effective_ip(regs);
|
||||||
|
if (!ip)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (get_user(byte, (const char __user *)ip))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (byte != 0xfa && byte != 0xfb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!t->iopl_warn && printk_ratelimit()) {
|
||||||
|
pr_err("%s[%d] attempts to use CLI/STI, pretending it's a NOP, ip:%lx",
|
||||||
|
current->comm, task_pid_nr(current), ip);
|
||||||
|
print_vma_addr(KERN_CONT " in ", ip);
|
||||||
|
pr_cont("\n");
|
||||||
|
t->iopl_warn = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs->ip += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
|
DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
|
||||||
{
|
{
|
||||||
char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
|
char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
|
||||||
@@ -548,6 +579,9 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
|
|||||||
tsk = current;
|
tsk = current;
|
||||||
|
|
||||||
if (user_mode(regs)) {
|
if (user_mode(regs)) {
|
||||||
|
if (fixup_iopl_exception(regs))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
tsk->thread.error_code = error_code;
|
tsk->thread.error_code = error_code;
|
||||||
tsk->thread.trap_nr = X86_TRAP_GP;
|
tsk->thread.trap_nr = X86_TRAP_GP;
|
||||||
|
|
||||||
|
@@ -1415,7 +1415,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long insn_get_effective_ip(struct pt_regs *regs)
|
unsigned long insn_get_effective_ip(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long seg_base = 0;
|
unsigned long seg_base = 0;
|
||||||
|
|
||||||
|
@@ -228,19 +228,6 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
|
|||||||
blk_mq_unfreeze_queue(lo->lo_queue);
|
blk_mq_unfreeze_queue(lo->lo_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* loop_validate_block_size() - validates the passed in block size
|
|
||||||
* @bsize: size to validate
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
loop_validate_block_size(unsigned short bsize)
|
|
||||||
{
|
|
||||||
if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loop_set_size() - sets device size and notifies userspace
|
* loop_set_size() - sets device size and notifies userspace
|
||||||
* @lo: struct loop_device to set the size for
|
* @lo: struct loop_device to set the size for
|
||||||
@@ -1121,7 +1108,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config->block_size) {
|
if (config->block_size) {
|
||||||
error = loop_validate_block_size(config->block_size);
|
error = blk_validate_block_size(config->block_size);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
@@ -1617,7 +1604,7 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
|
|||||||
if (lo->lo_state != Lo_bound)
|
if (lo->lo_state != Lo_bound)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
err = loop_validate_block_size(arg);
|
err = blk_validate_block_size(arg);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@@ -21,7 +21,6 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/pm_runtime.h>
|
|
||||||
|
|
||||||
#include "stmmac_platform.h"
|
#include "stmmac_platform.h"
|
||||||
|
|
||||||
@@ -1336,9 +1335,6 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_enable(dev);
|
|
||||||
pm_runtime_get_sync(dev);
|
|
||||||
|
|
||||||
if (bsp_priv->integrated_phy)
|
if (bsp_priv->integrated_phy)
|
||||||
rk_gmac_integrated_phy_powerup(bsp_priv);
|
rk_gmac_integrated_phy_powerup(bsp_priv);
|
||||||
|
|
||||||
@@ -1347,14 +1343,9 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
|
|||||||
|
|
||||||
static void rk_gmac_powerdown(struct rk_priv_data *gmac)
|
static void rk_gmac_powerdown(struct rk_priv_data *gmac)
|
||||||
{
|
{
|
||||||
struct device *dev = &gmac->pdev->dev;
|
|
||||||
|
|
||||||
if (gmac->integrated_phy)
|
if (gmac->integrated_phy)
|
||||||
rk_gmac_integrated_phy_powerdown(gmac);
|
rk_gmac_integrated_phy_powerdown(gmac);
|
||||||
|
|
||||||
pm_runtime_put_sync(dev);
|
|
||||||
pm_runtime_disable(dev);
|
|
||||||
|
|
||||||
phy_power_on(gmac, false);
|
phy_power_on(gmac, false);
|
||||||
gmac_clk_enable(gmac, false);
|
gmac_clk_enable(gmac, false);
|
||||||
}
|
}
|
||||||
|
@@ -270,6 +270,7 @@ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
|
|||||||
bool stmmac_eee_init(struct stmmac_priv *priv);
|
bool stmmac_eee_init(struct stmmac_priv *priv);
|
||||||
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
|
int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt);
|
||||||
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
|
int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size);
|
||||||
|
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
|
#if IS_ENABLED(CONFIG_STMMAC_SELFTESTS)
|
||||||
void stmmac_selftest_run(struct net_device *dev,
|
void stmmac_selftest_run(struct net_device *dev,
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include <linux/if_vlan.h>
|
#include <linux/if_vlan.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
@@ -113,6 +114,28 @@ static void stmmac_exit_fs(struct net_device *dev);
|
|||||||
|
|
||||||
#define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
|
#define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
|
||||||
|
|
||||||
|
int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
ret = clk_prepare_enable(priv->plat->stmmac_clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = clk_prepare_enable(priv->plat->pclk);
|
||||||
|
if (ret) {
|
||||||
|
clk_disable_unprepare(priv->plat->stmmac_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clk_disable_unprepare(priv->plat->stmmac_clk);
|
||||||
|
clk_disable_unprepare(priv->plat->pclk);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(stmmac_bus_clks_config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* stmmac_verify_args - verify the driver parameters.
|
* stmmac_verify_args - verify the driver parameters.
|
||||||
* Description: it checks the driver parameters and set a default in case of
|
* Description: it checks the driver parameters and set a default in case of
|
||||||
@@ -2792,6 +2815,12 @@ static int stmmac_open(struct net_device *dev)
|
|||||||
u32 chan;
|
u32 chan;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||||
priv->hw->pcs != STMMAC_PCS_RTBI &&
|
priv->hw->pcs != STMMAC_PCS_RTBI &&
|
||||||
priv->hw->xpcs == NULL) {
|
priv->hw->xpcs == NULL) {
|
||||||
@@ -2800,7 +2829,7 @@ static int stmmac_open(struct net_device *dev)
|
|||||||
netdev_err(priv->dev,
|
netdev_err(priv->dev,
|
||||||
"%s: Cannot attach to PHY (error: %d)\n",
|
"%s: Cannot attach to PHY (error: %d)\n",
|
||||||
__func__, ret);
|
__func__, ret);
|
||||||
return ret;
|
goto init_phy_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2915,6 +2944,8 @@ init_error:
|
|||||||
free_dma_desc_resources(priv);
|
free_dma_desc_resources(priv);
|
||||||
dma_desc_error:
|
dma_desc_error:
|
||||||
phylink_disconnect_phy(priv->phylink);
|
phylink_disconnect_phy(priv->phylink);
|
||||||
|
init_phy_error:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2965,6 +2996,8 @@ static int stmmac_release(struct net_device *dev)
|
|||||||
|
|
||||||
stmmac_release_ptp(priv);
|
stmmac_release_ptp(priv);
|
||||||
|
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4291,12 +4324,21 @@ static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
|
|||||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = eth_mac_addr(ndev, addr);
|
ret = eth_mac_addr(ndev, addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto set_mac_error;
|
||||||
|
|
||||||
stmmac_set_umac_addr(priv, priv->hw, ndev->dev_addr, 0);
|
stmmac_set_umac_addr(priv, priv->hw, ndev->dev_addr, 0);
|
||||||
|
|
||||||
|
set_mac_error:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4616,6 +4658,12 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
|
|||||||
bool is_double = false;
|
bool is_double = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (be16_to_cpu(proto) == ETH_P_8021AD)
|
if (be16_to_cpu(proto) == ETH_P_8021AD)
|
||||||
is_double = true;
|
is_double = true;
|
||||||
|
|
||||||
@@ -4624,10 +4672,15 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
|
|||||||
if (priv->hw->num_vlan) {
|
if (priv->hw->num_vlan) {
|
||||||
ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
|
ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto del_vlan_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stmmac_vlan_update(priv, is_double);
|
ret = stmmac_vlan_update(priv, is_double);
|
||||||
|
|
||||||
|
del_vlan_error:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops stmmac_netdev_ops = {
|
static const struct net_device_ops stmmac_netdev_ops = {
|
||||||
@@ -5066,6 +5119,10 @@ int stmmac_dvr_probe(struct device *device,
|
|||||||
|
|
||||||
stmmac_check_pcs_mode(priv);
|
stmmac_check_pcs_mode(priv);
|
||||||
|
|
||||||
|
pm_runtime_get_noresume(device);
|
||||||
|
pm_runtime_set_active(device);
|
||||||
|
pm_runtime_enable(device);
|
||||||
|
|
||||||
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||||
priv->hw->pcs != STMMAC_PCS_RTBI) {
|
priv->hw->pcs != STMMAC_PCS_RTBI) {
|
||||||
/* MDIO bus Registration */
|
/* MDIO bus Registration */
|
||||||
@@ -5103,6 +5160,11 @@ int stmmac_dvr_probe(struct device *device,
|
|||||||
stmmac_init_fs(ndev);
|
stmmac_init_fs(ndev);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Let pm_runtime_put() disable the clocks.
|
||||||
|
* If CONFIG_PM is not enabled, the clocks will stay powered.
|
||||||
|
*/
|
||||||
|
pm_runtime_put(device);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error_serdes_powerup:
|
error_serdes_powerup:
|
||||||
@@ -5152,8 +5214,8 @@ int stmmac_dvr_remove(struct device *dev)
|
|||||||
phylink_destroy(priv->phylink);
|
phylink_destroy(priv->phylink);
|
||||||
if (priv->plat->stmmac_rst)
|
if (priv->plat->stmmac_rst)
|
||||||
reset_control_assert(priv->plat->stmmac_rst);
|
reset_control_assert(priv->plat->stmmac_rst);
|
||||||
clk_disable_unprepare(priv->plat->pclk);
|
pm_runtime_put(dev);
|
||||||
clk_disable_unprepare(priv->plat->stmmac_clk);
|
pm_runtime_disable(dev);
|
||||||
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||||
priv->hw->pcs != STMMAC_PCS_RTBI)
|
priv->hw->pcs != STMMAC_PCS_RTBI)
|
||||||
stmmac_mdio_unregister(ndev);
|
stmmac_mdio_unregister(ndev);
|
||||||
@@ -5176,6 +5238,7 @@ int stmmac_suspend(struct device *dev)
|
|||||||
struct net_device *ndev = dev_get_drvdata(dev);
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
u32 chan;
|
u32 chan;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!ndev || !netif_running(ndev))
|
if (!ndev || !netif_running(ndev))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5219,8 +5282,11 @@ int stmmac_suspend(struct device *dev)
|
|||||||
pinctrl_pm_select_sleep_state(priv->device);
|
pinctrl_pm_select_sleep_state(priv->device);
|
||||||
/* Disable clock in case of PWM is off */
|
/* Disable clock in case of PWM is off */
|
||||||
clk_disable_unprepare(priv->plat->clk_ptp_ref);
|
clk_disable_unprepare(priv->plat->clk_ptp_ref);
|
||||||
clk_disable_unprepare(priv->plat->pclk);
|
ret = pm_runtime_force_suspend(dev);
|
||||||
clk_disable_unprepare(priv->plat->stmmac_clk);
|
if (ret) {
|
||||||
|
mutex_unlock(&priv->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&priv->lock);
|
mutex_unlock(&priv->lock);
|
||||||
|
|
||||||
@@ -5286,8 +5352,9 @@ int stmmac_resume(struct device *dev)
|
|||||||
} else {
|
} else {
|
||||||
pinctrl_pm_select_default_state(priv->device);
|
pinctrl_pm_select_default_state(priv->device);
|
||||||
/* enable the clk previously disabled */
|
/* enable the clk previously disabled */
|
||||||
clk_prepare_enable(priv->plat->stmmac_clk);
|
ret = pm_runtime_force_resume(dev);
|
||||||
clk_prepare_enable(priv->plat->pclk);
|
if (ret)
|
||||||
|
return ret;
|
||||||
if (priv->plat->clk_ptp_ref)
|
if (priv->plat->clk_ptp_ref)
|
||||||
clk_prepare_enable(priv->plat->clk_ptp_ref);
|
clk_prepare_enable(priv->plat->clk_ptp_ref);
|
||||||
/* reset the phy so that it's ready */
|
/* reset the phy so that it's ready */
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
#include <linux/mii.h>
|
#include <linux/mii.h>
|
||||||
#include <linux/of_mdio.h>
|
#include <linux/of_mdio.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -87,21 +88,29 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
|||||||
u32 tmp, addr, value = MII_XGMAC_BUSY;
|
u32 tmp, addr, value = MII_XGMAC_BUSY;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000))
|
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
if (phyreg & MII_ADDR_C45) {
|
if (phyreg & MII_ADDR_C45) {
|
||||||
phyreg &= ~MII_ADDR_C45;
|
phyreg &= ~MII_ADDR_C45;
|
||||||
|
|
||||||
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
|
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
} else {
|
} else {
|
||||||
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
|
|
||||||
value |= MII_XGMAC_SADDR;
|
value |= MII_XGMAC_SADDR;
|
||||||
}
|
}
|
||||||
@@ -112,8 +121,10 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
|||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000))
|
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the MII address register to read */
|
/* Set the MII address register to read */
|
||||||
writel(addr, priv->ioaddr + mii_address);
|
writel(addr, priv->ioaddr + mii_address);
|
||||||
@@ -121,11 +132,18 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
|||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000))
|
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the data from the MII data register */
|
/* Read the data from the MII data register */
|
||||||
return readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
|
ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0);
|
||||||
|
|
||||||
|
err_disable_clks:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
|
static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
|
||||||
@@ -138,21 +156,29 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
|
|||||||
u32 addr, tmp, value = MII_XGMAC_BUSY;
|
u32 addr, tmp, value = MII_XGMAC_BUSY;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000))
|
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
if (phyreg & MII_ADDR_C45) {
|
if (phyreg & MII_ADDR_C45) {
|
||||||
phyreg &= ~MII_ADDR_C45;
|
phyreg &= ~MII_ADDR_C45;
|
||||||
|
|
||||||
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
|
ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
} else {
|
} else {
|
||||||
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
|
|
||||||
value |= MII_XGMAC_SADDR;
|
value |= MII_XGMAC_SADDR;
|
||||||
}
|
}
|
||||||
@@ -164,16 +190,23 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr,
|
|||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
if (readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000))
|
!(tmp & MII_XGMAC_BUSY), 100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the MII address register to write */
|
/* Set the MII address register to write */
|
||||||
writel(addr, priv->ioaddr + mii_address);
|
writel(addr, priv->ioaddr + mii_address);
|
||||||
writel(value, priv->ioaddr + mii_data);
|
writel(value, priv->ioaddr + mii_data);
|
||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
return readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp,
|
||||||
!(tmp & MII_XGMAC_BUSY), 100, 10000);
|
!(tmp & MII_XGMAC_BUSY), 100, 10000);
|
||||||
|
|
||||||
|
err_disable_clks:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,6 +229,12 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
|||||||
int data = 0;
|
int data = 0;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
|
||||||
|
data = pm_runtime_get_sync(priv->device);
|
||||||
|
if (data < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||||
& priv->hw->mii.addr_mask;
|
& priv->hw->mii.addr_mask;
|
||||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||||
@@ -216,19 +255,26 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||||
100, 10000))
|
100, 10000)) {
|
||||||
return -EBUSY;
|
data = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
writel(data, priv->ioaddr + mii_data);
|
writel(data, priv->ioaddr + mii_data);
|
||||||
writel(value, priv->ioaddr + mii_address);
|
writel(value, priv->ioaddr + mii_address);
|
||||||
|
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||||
100, 10000))
|
100, 10000)) {
|
||||||
return -EBUSY;
|
data = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the data from the MII data register */
|
/* Read the data from the MII data register */
|
||||||
data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
|
data = (int)readl(priv->ioaddr + mii_data) & MII_DATA_MASK;
|
||||||
|
|
||||||
|
err_disable_clks:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,10 +293,16 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
|
|||||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
unsigned int mii_address = priv->hw->mii.addr;
|
unsigned int mii_address = priv->hw->mii.addr;
|
||||||
unsigned int mii_data = priv->hw->mii.data;
|
unsigned int mii_data = priv->hw->mii.data;
|
||||||
|
int ret, data = phydata;
|
||||||
u32 value = MII_BUSY;
|
u32 value = MII_BUSY;
|
||||||
int data = phydata;
|
|
||||||
u32 v;
|
u32 v;
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(priv->device);
|
||||||
|
if (ret < 0) {
|
||||||
|
pm_runtime_put_noidle(priv->device);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
value |= (phyaddr << priv->hw->mii.addr_shift)
|
value |= (phyaddr << priv->hw->mii.addr_shift)
|
||||||
& priv->hw->mii.addr_mask;
|
& priv->hw->mii.addr_mask;
|
||||||
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask;
|
||||||
@@ -275,16 +327,23 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
|
|||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||||
100, 10000))
|
100, 10000)) {
|
||||||
return -EBUSY;
|
ret = -EBUSY;
|
||||||
|
goto err_disable_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the MII address register to write */
|
/* Set the MII address register to write */
|
||||||
writel(data, priv->ioaddr + mii_data);
|
writel(data, priv->ioaddr + mii_data);
|
||||||
writel(value, priv->ioaddr + mii_address);
|
writel(value, priv->ioaddr + mii_address);
|
||||||
|
|
||||||
/* Wait until any existing MII operation is complete */
|
/* Wait until any existing MII operation is complete */
|
||||||
return readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
ret = readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY),
|
||||||
100, 10000);
|
100, 10000);
|
||||||
|
|
||||||
|
err_disable_clks:
|
||||||
|
pm_runtime_put(priv->device);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -720,7 +720,6 @@ int stmmac_pltfr_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
/**
|
/**
|
||||||
* stmmac_pltfr_suspend
|
* stmmac_pltfr_suspend
|
||||||
* @dev: device pointer
|
* @dev: device pointer
|
||||||
@@ -728,7 +727,7 @@ EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
|
|||||||
* call the main suspend function and then, if required, on some platform, it
|
* call the main suspend function and then, if required, on some platform, it
|
||||||
* can call an exit helper.
|
* can call an exit helper.
|
||||||
*/
|
*/
|
||||||
static int stmmac_pltfr_suspend(struct device *dev)
|
static int __maybe_unused stmmac_pltfr_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct net_device *ndev = dev_get_drvdata(dev);
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
@@ -749,7 +748,7 @@ static int stmmac_pltfr_suspend(struct device *dev)
|
|||||||
* the main resume function, on some platforms, it can call own init helper
|
* the main resume function, on some platforms, it can call own init helper
|
||||||
* if required.
|
* if required.
|
||||||
*/
|
*/
|
||||||
static int stmmac_pltfr_resume(struct device *dev)
|
static int __maybe_unused stmmac_pltfr_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct net_device *ndev = dev_get_drvdata(dev);
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
@@ -760,10 +759,29 @@ static int stmmac_pltfr_resume(struct device *dev)
|
|||||||
|
|
||||||
return stmmac_resume(dev);
|
return stmmac_resume(dev);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
|
static int __maybe_unused stmmac_runtime_suspend(struct device *dev)
|
||||||
stmmac_pltfr_resume);
|
{
|
||||||
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
|
|
||||||
|
stmmac_bus_clks_config(priv, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused stmmac_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = dev_get_drvdata(dev);
|
||||||
|
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||||
|
|
||||||
|
return stmmac_bus_clks_config(priv, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dev_pm_ops stmmac_pltfr_pm_ops = {
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume)
|
||||||
|
SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL)
|
||||||
|
};
|
||||||
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
|
EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
|
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
|
||||||
|
@@ -395,18 +395,6 @@ static void free_msi_irqs(struct pci_dev *dev)
|
|||||||
for (i = 0; i < entry->nvec_used; i++)
|
for (i = 0; i < entry->nvec_used; i++)
|
||||||
BUG_ON(irq_has_action(entry->irq + i));
|
BUG_ON(irq_has_action(entry->irq + i));
|
||||||
|
|
||||||
pci_msi_teardown_msi_irqs(dev);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(entry, tmp, msi_list, list) {
|
|
||||||
if (entry->msi_attrib.is_msix) {
|
|
||||||
if (list_is_last(&entry->list, msi_list))
|
|
||||||
iounmap(entry->mask_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del(&entry->list);
|
|
||||||
free_msi_entry(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->msi_irq_groups) {
|
if (dev->msi_irq_groups) {
|
||||||
sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups);
|
sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups);
|
||||||
msi_attrs = dev->msi_irq_groups[0]->attrs;
|
msi_attrs = dev->msi_irq_groups[0]->attrs;
|
||||||
@@ -422,6 +410,18 @@ static void free_msi_irqs(struct pci_dev *dev)
|
|||||||
kfree(dev->msi_irq_groups);
|
kfree(dev->msi_irq_groups);
|
||||||
dev->msi_irq_groups = NULL;
|
dev->msi_irq_groups = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pci_msi_teardown_msi_irqs(dev);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(entry, tmp, msi_list, list) {
|
||||||
|
if (entry->msi_attrib.is_msix) {
|
||||||
|
if (list_is_last(&entry->list, msi_list))
|
||||||
|
iounmap(entry->mask_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&entry->list);
|
||||||
|
free_msi_entry(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
|
static void pci_intx_for_msi(struct pci_dev *dev, int enable)
|
||||||
@@ -591,6 +591,9 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
||||||
|
/* Lies, damned lies, and MSIs */
|
||||||
|
if (dev->dev_flags & PCI_DEV_FLAGS_HAS_MSI_MASKING)
|
||||||
|
control |= PCI_MSI_FLAGS_MASKBIT;
|
||||||
|
|
||||||
entry->msi_attrib.is_msix = 0;
|
entry->msi_attrib.is_msix = 0;
|
||||||
entry->msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
|
entry->msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
|
||||||
|
@@ -5756,3 +5756,9 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
|
|||||||
}
|
}
|
||||||
DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
|
DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
|
||||||
PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
|
PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);
|
||||||
|
|
||||||
|
static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
pdev->dev_flags |= PCI_DEV_FLAGS_HAS_MSI_MASKING;
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0ab8, nvidia_ion_ahci_fixup);
|
||||||
|
@@ -376,11 +376,10 @@ static bool z_erofs_try_inplace_io(struct z_erofs_collector *clt,
|
|||||||
|
|
||||||
/* callers must be with collection lock held */
|
/* callers must be with collection lock held */
|
||||||
static int z_erofs_attach_page(struct z_erofs_collector *clt,
|
static int z_erofs_attach_page(struct z_erofs_collector *clt,
|
||||||
struct page *page,
|
struct page *page, enum z_erofs_page_type type,
|
||||||
enum z_erofs_page_type type)
|
bool pvec_safereuse)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
bool occupied;
|
|
||||||
|
|
||||||
/* give priority for inplaceio */
|
/* give priority for inplaceio */
|
||||||
if (clt->mode >= COLLECT_PRIMARY &&
|
if (clt->mode >= COLLECT_PRIMARY &&
|
||||||
@@ -388,10 +387,9 @@ static int z_erofs_attach_page(struct z_erofs_collector *clt,
|
|||||||
z_erofs_try_inplace_io(clt, page))
|
z_erofs_try_inplace_io(clt, page))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = z_erofs_pagevec_enqueue(&clt->vector,
|
ret = z_erofs_pagevec_enqueue(&clt->vector, page, type,
|
||||||
page, type, &occupied);
|
pvec_safereuse);
|
||||||
clt->cl->vcnt += (unsigned int)ret;
|
clt->cl->vcnt += (unsigned int)ret;
|
||||||
|
|
||||||
return ret ? 0 : -EAGAIN;
|
return ret ? 0 : -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,15 +735,16 @@ hitted:
|
|||||||
tight &= (clt->mode >= COLLECT_PRIMARY_FOLLOWED);
|
tight &= (clt->mode >= COLLECT_PRIMARY_FOLLOWED);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
err = z_erofs_attach_page(clt, page, page_type);
|
err = z_erofs_attach_page(clt, page, page_type,
|
||||||
/* should allocate an additional short-lived page for pagevec */
|
clt->mode >= COLLECT_PRIMARY_FOLLOWED);
|
||||||
|
/* should allocate an additional staging page for pagevec */
|
||||||
if (err == -EAGAIN) {
|
if (err == -EAGAIN) {
|
||||||
struct page *const newpage =
|
struct page *const newpage =
|
||||||
alloc_page(GFP_NOFS | __GFP_NOFAIL);
|
alloc_page(GFP_NOFS | __GFP_NOFAIL);
|
||||||
|
|
||||||
set_page_private(newpage, Z_EROFS_SHORTLIVED_PAGE);
|
set_page_private(newpage, Z_EROFS_SHORTLIVED_PAGE);
|
||||||
err = z_erofs_attach_page(clt, newpage,
|
err = z_erofs_attach_page(clt, newpage,
|
||||||
Z_EROFS_PAGE_TYPE_EXCLUSIVE);
|
Z_EROFS_PAGE_TYPE_EXCLUSIVE, true);
|
||||||
if (!err)
|
if (!err)
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
@@ -108,12 +108,17 @@ static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
|
|||||||
static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
|
static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
|
||||||
struct page *page,
|
struct page *page,
|
||||||
enum z_erofs_page_type type,
|
enum z_erofs_page_type type,
|
||||||
bool *occupied)
|
bool pvec_safereuse)
|
||||||
{
|
{
|
||||||
*occupied = false;
|
if (!ctor->next) {
|
||||||
if (!ctor->next && type)
|
/* some pages cannot be reused as pvec safely without I/O */
|
||||||
if (ctor->index + 1 == ctor->nr)
|
if (type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && !pvec_safereuse)
|
||||||
|
type = Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED;
|
||||||
|
|
||||||
|
if (type != Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
|
||||||
|
ctor->index + 1 == ctor->nr)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctor->index >= ctor->nr)
|
if (ctor->index >= ctor->nr)
|
||||||
z_erofs_pagevec_ctor_pagedown(ctor, false);
|
z_erofs_pagevec_ctor_pagedown(ctor, false);
|
||||||
@@ -125,7 +130,6 @@ static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
|
|||||||
/* should remind that collector->next never equal to 1, 2 */
|
/* should remind that collector->next never equal to 1, 2 */
|
||||||
if (type == (uintptr_t)ctor->next) {
|
if (type == (uintptr_t)ctor->next) {
|
||||||
ctor->next = page;
|
ctor->next = page;
|
||||||
*occupied = true;
|
|
||||||
}
|
}
|
||||||
ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
|
ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
|
||||||
return true;
|
return true;
|
||||||
|
@@ -61,6 +61,14 @@ struct blk_keyslot_manager;
|
|||||||
*/
|
*/
|
||||||
#define BLKCG_MAX_POLS 5
|
#define BLKCG_MAX_POLS 5
|
||||||
|
|
||||||
|
static inline int blk_validate_block_size(unsigned int bsize)
|
||||||
|
{
|
||||||
|
if (bsize < 512 || bsize > PAGE_SIZE || !is_power_of_2(bsize))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
typedef void (rq_end_io_fn)(struct request *, blk_status_t);
|
typedef void (rq_end_io_fn)(struct request *, blk_status_t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -228,6 +228,8 @@ enum pci_dev_flags {
|
|||||||
PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
|
PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
|
||||||
/* Don't use Relaxed Ordering for TLPs directed at this device */
|
/* Don't use Relaxed Ordering for TLPs directed at this device */
|
||||||
PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
|
PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
|
||||||
|
/* Device does honor MSI masking despite saying otherwise */
|
||||||
|
PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pci_irq_reroute_variant {
|
enum pci_irq_reroute_variant {
|
||||||
|
@@ -382,6 +382,7 @@ static char * __init xbc_make_cmdline(const char *key)
|
|||||||
ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
|
ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
|
||||||
if (ret < 0 || ret > len) {
|
if (ret < 0 || ret > len) {
|
||||||
pr_err("Failed to print extra kernel cmdline.\n");
|
pr_err("Failed to print extra kernel cmdline.\n");
|
||||||
|
memblock_free(__pa(new_cmdline), len + 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7037,7 +7037,6 @@ void perf_output_sample(struct perf_output_handle *handle,
|
|||||||
static u64 perf_virt_to_phys(u64 virt)
|
static u64 perf_virt_to_phys(u64 virt)
|
||||||
{
|
{
|
||||||
u64 phys_addr = 0;
|
u64 phys_addr = 0;
|
||||||
struct page *p = NULL;
|
|
||||||
|
|
||||||
if (!virt)
|
if (!virt)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -7056,14 +7055,15 @@ static u64 perf_virt_to_phys(u64 virt)
|
|||||||
* If failed, leave phys_addr as 0.
|
* If failed, leave phys_addr as 0.
|
||||||
*/
|
*/
|
||||||
if (current->mm != NULL) {
|
if (current->mm != NULL) {
|
||||||
|
struct page *p;
|
||||||
|
|
||||||
pagefault_disable();
|
pagefault_disable();
|
||||||
if (get_user_page_fast_only(virt, 0, &p))
|
if (get_user_page_fast_only(virt, 0, &p)) {
|
||||||
phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
|
phys_addr = page_to_phys(p) + virt % PAGE_SIZE;
|
||||||
|
put_page(p);
|
||||||
|
}
|
||||||
pagefault_enable();
|
pagefault_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p)
|
|
||||||
put_page(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return phys_addr;
|
return phys_addr;
|
||||||
|
@@ -6,15 +6,32 @@
|
|||||||
# Print the linker version of `ld.lld' in a 5 or 6-digit form
|
# Print the linker version of `ld.lld' in a 5 or 6-digit form
|
||||||
# such as `100001' for ld.lld 10.0.1 etc.
|
# such as `100001' for ld.lld 10.0.1 etc.
|
||||||
|
|
||||||
linker_string="$($* --version)"
|
set -e
|
||||||
|
|
||||||
if ! ( echo $linker_string | grep -q LLD ); then
|
# Convert the version string x.y.z to a canonical 5 or 6-digit form.
|
||||||
|
get_canonical_version()
|
||||||
|
{
|
||||||
|
IFS=.
|
||||||
|
set -- $1
|
||||||
|
|
||||||
|
# If the 2nd or 3rd field is missing, fill it with a zero.
|
||||||
|
echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0}))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the first line of the --version output.
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
set -- $(LC_ALL=C "$@" --version)
|
||||||
|
|
||||||
|
# Split the line on spaces.
|
||||||
|
IFS=' '
|
||||||
|
set -- $1
|
||||||
|
|
||||||
|
while [ $# -gt 1 -a "$1" != "LLD" ]; do
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
if [ "$1" = LLD ]; then
|
||||||
|
echo $(get_canonical_version ${2%-*})
|
||||||
|
else
|
||||||
echo 0
|
echo 0
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
VERSION=$(echo $linker_string | cut -d ' ' -f 2)
|
|
||||||
MAJOR=$(echo $VERSION | cut -d . -f 1)
|
|
||||||
MINOR=$(echo $VERSION | cut -d . -f 2)
|
|
||||||
PATCHLEVEL=$(echo $VERSION | cut -d . -f 3)
|
|
||||||
printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
|
|
||||||
|
@@ -191,6 +191,9 @@ config HARDENED_USERCOPY_PAGESPAN
|
|||||||
config FORTIFY_SOURCE
|
config FORTIFY_SOURCE
|
||||||
bool "Harden common str/mem functions against buffer overflows"
|
bool "Harden common str/mem functions against buffer overflows"
|
||||||
depends on ARCH_HAS_FORTIFY_SOURCE
|
depends on ARCH_HAS_FORTIFY_SOURCE
|
||||||
|
# https://bugs.llvm.org/show_bug.cgi?id=50322
|
||||||
|
# https://bugs.llvm.org/show_bug.cgi?id=41459
|
||||||
|
depends on !CC_IS_CLANG
|
||||||
help
|
help
|
||||||
Detect overflows of buffers in common string and memory functions
|
Detect overflows of buffers in common string and memory functions
|
||||||
where the compiler can determine and validate the buffer sizes.
|
where the compiler can determine and validate the buffer sizes.
|
||||||
|
@@ -85,48 +85,88 @@ static void expect_gp_outb(unsigned short port)
|
|||||||
printf("[OK]\toutb to 0x%02hx failed\n", port);
|
printf("[OK]\toutb to 0x%02hx failed\n", port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool try_cli(void)
|
#define RET_FAULTED 0
|
||||||
|
#define RET_FAIL 1
|
||||||
|
#define RET_EMUL 2
|
||||||
|
|
||||||
|
static int try_cli(void)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
||||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||||
return false;
|
return RET_FAULTED;
|
||||||
} else {
|
} else {
|
||||||
asm volatile ("cli");
|
asm volatile("cli; pushf; pop %[flags]"
|
||||||
return true;
|
: [flags] "=rm" (flags));
|
||||||
|
|
||||||
|
/* X86_FLAGS_IF */
|
||||||
|
if (!(flags & (1 << 9)))
|
||||||
|
return RET_FAIL;
|
||||||
|
else
|
||||||
|
return RET_EMUL;
|
||||||
}
|
}
|
||||||
clearhandler(SIGSEGV);
|
clearhandler(SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool try_sti(void)
|
static int try_sti(bool irqs_off)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
|
||||||
if (sigsetjmp(jmpbuf, 1) != 0) {
|
if (sigsetjmp(jmpbuf, 1) != 0) {
|
||||||
return false;
|
return RET_FAULTED;
|
||||||
} else {
|
} else {
|
||||||
asm volatile ("sti");
|
asm volatile("sti; pushf; pop %[flags]"
|
||||||
return true;
|
: [flags] "=rm" (flags));
|
||||||
|
|
||||||
|
/* X86_FLAGS_IF */
|
||||||
|
if (irqs_off && (flags & (1 << 9)))
|
||||||
|
return RET_FAIL;
|
||||||
|
else
|
||||||
|
return RET_EMUL;
|
||||||
}
|
}
|
||||||
clearhandler(SIGSEGV);
|
clearhandler(SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expect_gp_sti(void)
|
static void expect_gp_sti(bool irqs_off)
|
||||||
{
|
{
|
||||||
if (try_sti()) {
|
int ret = try_sti(irqs_off);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case RET_FAULTED:
|
||||||
|
printf("[OK]\tSTI faulted\n");
|
||||||
|
break;
|
||||||
|
case RET_EMUL:
|
||||||
|
printf("[OK]\tSTI NOPped\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
printf("[FAIL]\tSTI worked\n");
|
printf("[FAIL]\tSTI worked\n");
|
||||||
nerrs++;
|
nerrs++;
|
||||||
} else {
|
|
||||||
printf("[OK]\tSTI faulted\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expect_gp_cli(void)
|
/*
|
||||||
|
* Returns whether it managed to disable interrupts.
|
||||||
|
*/
|
||||||
|
static bool test_cli(void)
|
||||||
{
|
{
|
||||||
if (try_cli()) {
|
int ret = try_cli();
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case RET_FAULTED:
|
||||||
|
printf("[OK]\tCLI faulted\n");
|
||||||
|
break;
|
||||||
|
case RET_EMUL:
|
||||||
|
printf("[OK]\tCLI NOPped\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
printf("[FAIL]\tCLI worked\n");
|
printf("[FAIL]\tCLI worked\n");
|
||||||
nerrs++;
|
nerrs++;
|
||||||
} else {
|
return true;
|
||||||
printf("[OK]\tCLI faulted\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
@@ -152,8 +192,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that CLI/STI are blocked even with IOPL level 3 */
|
/* Make sure that CLI/STI are blocked even with IOPL level 3 */
|
||||||
expect_gp_cli();
|
expect_gp_sti(test_cli());
|
||||||
expect_gp_sti();
|
|
||||||
expect_ok_outb(0x80);
|
expect_ok_outb(0x80);
|
||||||
|
|
||||||
/* Establish an I/O bitmap to test the restore */
|
/* Establish an I/O bitmap to test the restore */
|
||||||
@@ -204,8 +243,7 @@ int main(void)
|
|||||||
printf("[RUN]\tparent: write to 0x80 (should fail)\n");
|
printf("[RUN]\tparent: write to 0x80 (should fail)\n");
|
||||||
|
|
||||||
expect_gp_outb(0x80);
|
expect_gp_outb(0x80);
|
||||||
expect_gp_cli();
|
expect_gp_sti(test_cli());
|
||||||
expect_gp_sti();
|
|
||||||
|
|
||||||
/* Test the capability checks. */
|
/* Test the capability checks. */
|
||||||
printf("\tiopl(3)\n");
|
printf("\tiopl(3)\n");
|
||||||
|
Reference in New Issue
Block a user