diff options
author | Mike Pagano <mpagano@gentoo.org> | 2023-06-05 07:49:57 -0400 |
---|---|---|
committer | Mike Pagano <mpagano@gentoo.org> | 2023-06-05 07:49:57 -0400 |
commit | 26f8bf35b6fb51a168b7ee50e07ac0f8b7f60a0d (patch) | |
tree | 3cd433e1ba001c880e40b74c4b3d67a370163a43 | |
parent | Linux patch 5.10.181 (diff) | |
download | linux-patches-26f8bf35b6fb51a168b7ee50e07ac0f8b7f60a0d.tar.gz linux-patches-26f8bf35b6fb51a168b7ee50e07ac0f8b7f60a0d.tar.bz2 linux-patches-26f8bf35b6fb51a168b7ee50e07ac0f8b7f60a0d.zip |
Linux patch 5.10.1825.10-192
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r-- | 0000_README | 4 | ||||
-rw-r--r-- | 1181_linux-5.10.182.patch | 1150 |
2 files changed, 1154 insertions, 0 deletions
diff --git a/0000_README b/0000_README index 366c0d03..0400be74 100644 --- a/0000_README +++ b/0000_README @@ -767,6 +767,10 @@ Patch: 1180_linux-5.10.181.patch From: https://www.kernel.org Desc: Linux 5.10.181 +Patch: 1181_linux-5.10.182.patch +From: https://www.kernel.org +Desc: Linux 5.10.182 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1181_linux-5.10.182.patch b/1181_linux-5.10.182.patch new file mode 100644 index 00000000..75cca61c --- /dev/null +++ b/1181_linux-5.10.182.patch @@ -0,0 +1,1150 @@ +diff --git a/Makefile b/Makefile +index 4e8289113a81f..2f0efde219023 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 5 + PATCHLEVEL = 10 +-SUBLEVEL = 181 ++SUBLEVEL = 182 + EXTRAVERSION = + NAME = Dare mighty things + +diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h +index 14b52718917f6..0de49e33d422e 100644 +--- a/arch/x86/include/asm/intel-family.h ++++ b/arch/x86/include/asm/intel-family.h +@@ -104,6 +104,8 @@ + #define INTEL_FAM6_RAPTORLAKE_P 0xBA + #define INTEL_FAM6_RAPTORLAKE_S 0xBF + ++#define INTEL_FAM6_RAPTORLAKE 0xB7 ++ + /* "Small Core" Processors (Atom) */ + + #define INTEL_FAM6_ATOM_BONNELL 0x1C /* Diamondville, Pineview */ +diff --git a/drivers/android/binder.c b/drivers/android/binder.c +index b403c7f063b00..dbae98f096580 100644 +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -2267,24 +2267,23 @@ static void binder_deferred_fd_close(int fd) + static void binder_transaction_buffer_release(struct binder_proc *proc, + struct binder_thread *thread, + struct binder_buffer *buffer, +- binder_size_t failed_at, ++ binder_size_t off_end_offset, + bool is_failure) + { + int debug_id = buffer->debug_id; +- binder_size_t off_start_offset, buffer_offset, off_end_offset; ++ binder_size_t off_start_offset, buffer_offset; + + binder_debug(BINDER_DEBUG_TRANSACTION, + "%d buffer release %d, size %zd-%zd, failed at %llx\n", + proc->pid, buffer->debug_id, + buffer->data_size, buffer->offsets_size, +- (unsigned long long)failed_at); ++ (unsigned long long)off_end_offset); + + if (buffer->target_node) + binder_dec_node(buffer->target_node, 1, 0); + + off_start_offset = ALIGN(buffer->data_size, sizeof(void *)); +- off_end_offset = is_failure && failed_at ? failed_at : +- off_start_offset + buffer->offsets_size; ++ + for (buffer_offset = off_start_offset; buffer_offset < off_end_offset; + buffer_offset += sizeof(binder_size_t)) { + struct binder_object_header *hdr; +@@ -2444,6 +2443,21 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, + } + } + ++/* Clean up all the objects in the buffer */ ++static inline void binder_release_entire_buffer(struct binder_proc *proc, ++ struct binder_thread *thread, ++ struct binder_buffer *buffer, ++ bool is_failure) ++{ ++ binder_size_t off_end_offset; ++ ++ off_end_offset = ALIGN(buffer->data_size, sizeof(void *)); ++ off_end_offset += buffer->offsets_size; ++ ++ binder_transaction_buffer_release(proc, thread, buffer, ++ off_end_offset, is_failure); ++} ++ + static int binder_translate_binder(struct flat_binder_object *fp, + struct binder_transaction *t, + struct binder_thread *thread) +@@ -3926,7 +3940,7 @@ binder_free_buf(struct binder_proc *proc, + binder_node_inner_unlock(buf_node); + } + trace_binder_transaction_buffer_release(buffer); +- binder_transaction_buffer_release(proc, thread, buffer, 0, is_failure); ++ binder_release_entire_buffer(proc, thread, buffer, is_failure); + binder_alloc_free_buf(&proc->alloc, buffer); + } + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +index abd066e952286..438be215bbd45 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +@@ -3,6 +3,7 @@ + + #include <linux/mlx5/vport.h> + #include "lib/devcom.h" ++#include "mlx5_core.h" + + static LIST_HEAD(devcom_list); + +@@ -14,7 +15,7 @@ static LIST_HEAD(devcom_list); + struct mlx5_devcom_component { + struct { + void *data; +- } device[MLX5_MAX_PORTS]; ++ } device[MLX5_DEVCOM_PORTS_SUPPORTED]; + + mlx5_devcom_event_handler_t handler; + struct rw_semaphore sem; +@@ -25,7 +26,7 @@ struct mlx5_devcom_list { + struct list_head list; + + struct mlx5_devcom_component components[MLX5_DEVCOM_NUM_COMPONENTS]; +- struct mlx5_core_dev *devs[MLX5_MAX_PORTS]; ++ struct mlx5_core_dev *devs[MLX5_DEVCOM_PORTS_SUPPORTED]; + }; + + struct mlx5_devcom { +@@ -74,13 +75,16 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) + + if (!mlx5_core_is_pf(dev)) + return NULL; ++ if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED) ++ return NULL; + ++ mlx5_dev_list_lock(); + sguid0 = mlx5_query_nic_system_image_guid(dev); + list_for_each_entry(iter, &devcom_list, list) { + struct mlx5_core_dev *tmp_dev = NULL; + + idx = -1; +- for (i = 0; i < MLX5_MAX_PORTS; i++) { ++ for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) { + if (iter->devs[i]) + tmp_dev = iter->devs[i]; + else +@@ -100,8 +104,10 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) + + if (!priv) { + priv = mlx5_devcom_list_alloc(); +- if (!priv) +- return ERR_PTR(-ENOMEM); ++ if (!priv) { ++ devcom = ERR_PTR(-ENOMEM); ++ goto out; ++ } + + idx = 0; + new_priv = true; +@@ -112,12 +118,14 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) + if (!devcom) { + if (new_priv) + kfree(priv); +- return ERR_PTR(-ENOMEM); ++ devcom = ERR_PTR(-ENOMEM); ++ goto out; + } + + if (new_priv) + list_add(&priv->list, &devcom_list); +- ++out: ++ mlx5_dev_list_unlock(); + return devcom; + } + +@@ -130,20 +138,23 @@ void mlx5_devcom_unregister_device(struct mlx5_devcom *devcom) + if (IS_ERR_OR_NULL(devcom)) + return; + ++ mlx5_dev_list_lock(); + priv = devcom->priv; + priv->devs[devcom->idx] = NULL; + + kfree(devcom); + +- for (i = 0; i < MLX5_MAX_PORTS; i++) ++ for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) + if (priv->devs[i]) + break; + +- if (i != MLX5_MAX_PORTS) +- return; ++ if (i != MLX5_DEVCOM_PORTS_SUPPORTED) ++ goto out; + + list_del(&priv->list); + kfree(priv); ++out: ++ mlx5_dev_list_unlock(); + } + + void mlx5_devcom_register_component(struct mlx5_devcom *devcom, +@@ -192,7 +203,7 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom, + + comp = &devcom->priv->components[id]; + down_write(&comp->sem); +- for (i = 0; i < MLX5_MAX_PORTS; i++) ++ for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) + if (i != devcom->idx && comp->device[i].data) { + err = comp->handler(event, comp->device[i].data, + event_data); +@@ -240,7 +251,7 @@ void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, + return NULL; + } + +- for (i = 0; i < MLX5_MAX_PORTS; i++) ++ for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) + if (i != devcom->idx) + break; + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +index 939d5bf1581b5..94313c18bb647 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +@@ -6,6 +6,8 @@ + + #include <linux/mlx5/driver.h> + ++#define MLX5_DEVCOM_PORTS_SUPPORTED 2 ++ + enum mlx5_devcom_components { + MLX5_DEVCOM_ESW_OFFLOADS, + +diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h +index c2023f93c0b24..79117d281c1ec 100644 +--- a/drivers/net/phy/mscc/mscc.h ++++ b/drivers/net/phy/mscc/mscc.h +@@ -175,6 +175,7 @@ enum rgmii_clock_delay { + #define VSC8502_RGMII_CNTL 20 + #define VSC8502_RGMII_RX_DELAY_MASK 0x0070 + #define VSC8502_RGMII_TX_DELAY_MASK 0x0007 ++#define VSC8502_RGMII_RX_CLK_DISABLE 0x0800 + + #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21 + #define MSCC_PHY_WOL_MID_MAC_ADDR 22 +diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c +index ffac713afa551..c64ac142509a5 100644 +--- a/drivers/net/phy/mscc/mscc_main.c ++++ b/drivers/net/phy/mscc/mscc_main.c +@@ -527,14 +527,27 @@ out_unlock: + * * 2.0 ns (which causes the data to be sampled at exactly half way between + * clock transitions at 1000 Mbps) if delays should be enabled + */ +-static int vsc85xx_rgmii_set_skews(struct phy_device *phydev, u32 rgmii_cntl, +- u16 rgmii_rx_delay_mask, +- u16 rgmii_tx_delay_mask) ++static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl, ++ u16 rgmii_rx_delay_mask, ++ u16 rgmii_tx_delay_mask) + { + u16 rgmii_rx_delay_pos = ffs(rgmii_rx_delay_mask) - 1; + u16 rgmii_tx_delay_pos = ffs(rgmii_tx_delay_mask) - 1; + u16 reg_val = 0; +- int rc; ++ u16 mask = 0; ++ int rc = 0; ++ ++ /* For traffic to pass, the VSC8502 family needs the RX_CLK disable bit ++ * to be unset for all PHY modes, so do that as part of the paged ++ * register modification. ++ * For some family members (like VSC8530/31/40/41) this bit is reserved ++ * and read-only, and the RX clock is enabled by default. ++ */ ++ if (rgmii_cntl == VSC8502_RGMII_CNTL) ++ mask |= VSC8502_RGMII_RX_CLK_DISABLE; ++ ++ if (phy_interface_is_rgmii(phydev)) ++ mask |= rgmii_rx_delay_mask | rgmii_tx_delay_mask; + + mutex_lock(&phydev->lock); + +@@ -545,10 +558,9 @@ static int vsc85xx_rgmii_set_skews(struct phy_device *phydev, u32 rgmii_cntl, + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_tx_delay_pos; + +- rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, +- rgmii_cntl, +- rgmii_rx_delay_mask | rgmii_tx_delay_mask, +- reg_val); ++ if (mask) ++ rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, ++ rgmii_cntl, mask, reg_val); + + mutex_unlock(&phydev->lock); + +@@ -557,19 +569,11 @@ static int vsc85xx_rgmii_set_skews(struct phy_device *phydev, u32 rgmii_cntl, + + static int vsc85xx_default_config(struct phy_device *phydev) + { +- int rc; +- + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + +- if (phy_interface_mode_is_rgmii(phydev->interface)) { +- rc = vsc85xx_rgmii_set_skews(phydev, VSC8502_RGMII_CNTL, +- VSC8502_RGMII_RX_DELAY_MASK, +- VSC8502_RGMII_TX_DELAY_MASK); +- if (rc) +- return rc; +- } +- +- return 0; ++ return vsc85xx_update_rgmii_cntl(phydev, VSC8502_RGMII_CNTL, ++ VSC8502_RGMII_RX_DELAY_MASK, ++ VSC8502_RGMII_TX_DELAY_MASK); + } + + static int vsc85xx_get_tunable(struct phy_device *phydev, +@@ -1646,13 +1650,11 @@ static int vsc8584_config_init(struct phy_device *phydev) + if (ret) + return ret; + +- if (phy_interface_is_rgmii(phydev)) { +- ret = vsc85xx_rgmii_set_skews(phydev, VSC8572_RGMII_CNTL, +- VSC8572_RGMII_RX_DELAY_MASK, +- VSC8572_RGMII_TX_DELAY_MASK); +- if (ret) +- return ret; +- } ++ ret = vsc85xx_update_rgmii_cntl(phydev, VSC8572_RGMII_CNTL, ++ VSC8572_RGMII_RX_DELAY_MASK, ++ VSC8572_RGMII_TX_DELAY_MASK); ++ if (ret) ++ return ret; + + ret = genphy_soft_reset(phydev); + if (ret) +diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c +index 338dd82007e4e..5769b36851c34 100644 +--- a/drivers/power/supply/bq24190_charger.c ++++ b/drivers/power/supply/bq24190_charger.c +@@ -1203,8 +1203,19 @@ static void bq24190_input_current_limit_work(struct work_struct *work) + struct bq24190_dev_info *bdi = + container_of(work, struct bq24190_dev_info, + input_current_limit_work.work); ++ union power_supply_propval val; ++ int ret; + +- power_supply_set_input_current_limit_from_supplier(bdi->charger); ++ ret = power_supply_get_property_from_supplier(bdi->charger, ++ POWER_SUPPLY_PROP_CURRENT_MAX, ++ &val); ++ if (ret) ++ return; ++ ++ bq24190_charger_set_property(bdi->charger, ++ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, ++ &val); ++ power_supply_changed(bdi->charger); + } + + /* Sync the input-current-limit with our parent supply (if we have one) */ +diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c +index c08dd4e6d35ad..235647b21af71 100644 +--- a/drivers/power/supply/bq27xxx_battery.c ++++ b/drivers/power/supply/bq27xxx_battery.c +@@ -1507,14 +1507,6 @@ static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg) + */ + static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di) + { +- int flags; +- +- if (di->opts & BQ27XXX_O_ZERO) { +- flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); +- if (flags >= 0 && (flags & BQ27000_FLAG_CI)) +- return -ENODATA; +- } +- + return bq27xxx_battery_read_charge(di, BQ27XXX_REG_NAC); + } + +@@ -1668,6 +1660,18 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) + return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); + } + ++/* ++ * Returns true if reported battery capacity is inaccurate ++ */ ++static bool bq27xxx_battery_capacity_inaccurate(struct bq27xxx_device_info *di, ++ u16 flags) ++{ ++ if (di->opts & BQ27XXX_O_HAS_CI) ++ return (flags & BQ27000_FLAG_CI); ++ else ++ return false; ++} ++ + static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) + { + /* Unlikely but important to return first */ +@@ -1677,14 +1681,89 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) + return POWER_SUPPLY_HEALTH_COLD; + if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) + return POWER_SUPPLY_HEALTH_DEAD; ++ if (unlikely(bq27xxx_battery_capacity_inaccurate(di, di->cache.flags))) ++ return POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED; + + return POWER_SUPPLY_HEALTH_GOOD; + } + ++static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags) ++{ ++ if (di->opts & BQ27XXX_O_ZERO) ++ return (flags & BQ27000_FLAG_FC); ++ else if (di->opts & BQ27Z561_O_BITS) ++ return (flags & BQ27Z561_FLAG_FC); ++ else ++ return (flags & BQ27XXX_FLAG_FC); ++} ++ ++/* ++ * Return the battery average current in µA and the status ++ * Note that current can be negative signed as well ++ * Or 0 if something fails. ++ */ ++static int bq27xxx_battery_current_and_status( ++ struct bq27xxx_device_info *di, ++ union power_supply_propval *val_curr, ++ union power_supply_propval *val_status, ++ struct bq27xxx_reg_cache *cache) ++{ ++ bool single_flags = (di->opts & BQ27XXX_O_ZERO); ++ int curr; ++ int flags; ++ ++ curr = bq27xxx_read(di, BQ27XXX_REG_AI, false); ++ if (curr < 0) { ++ dev_err(di->dev, "error reading current\n"); ++ return curr; ++ } ++ ++ if (cache) { ++ flags = cache->flags; ++ } else { ++ flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags); ++ if (flags < 0) { ++ dev_err(di->dev, "error reading flags\n"); ++ return flags; ++ } ++ } ++ ++ if (di->opts & BQ27XXX_O_ZERO) { ++ if (!(flags & BQ27000_FLAG_CHGS)) { ++ dev_dbg(di->dev, "negative current!\n"); ++ curr = -curr; ++ } ++ ++ curr = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; ++ } else { ++ /* Other gauges return signed value */ ++ curr = (int)((s16)curr) * 1000; ++ } ++ ++ if (val_curr) ++ val_curr->intval = curr; ++ ++ if (val_status) { ++ if (curr > 0) { ++ val_status->intval = POWER_SUPPLY_STATUS_CHARGING; ++ } else if (curr < 0) { ++ val_status->intval = POWER_SUPPLY_STATUS_DISCHARGING; ++ } else { ++ if (bq27xxx_battery_is_full(di, flags)) ++ val_status->intval = POWER_SUPPLY_STATUS_FULL; ++ else ++ val_status->intval = ++ POWER_SUPPLY_STATUS_NOT_CHARGING; ++ } ++ } ++ ++ return 0; ++} ++ + static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) + { ++ union power_supply_propval status = di->last_status; + struct bq27xxx_reg_cache cache = {0, }; +- bool has_ci_flag = di->opts & BQ27XXX_O_HAS_CI; + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; + + cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); +@@ -1692,41 +1771,40 @@ static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) + cache.flags = -1; /* read error */ + if (cache.flags >= 0) { + cache.temperature = bq27xxx_battery_read_temperature(di); +- if (has_ci_flag && (cache.flags & BQ27000_FLAG_CI)) { +- dev_info_once(di->dev, "battery is not calibrated! ignoring capacity values\n"); +- cache.capacity = -ENODATA; +- cache.energy = -ENODATA; +- cache.time_to_empty = -ENODATA; +- cache.time_to_empty_avg = -ENODATA; +- cache.time_to_full = -ENODATA; +- cache.charge_full = -ENODATA; +- cache.health = -ENODATA; +- } else { +- if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) +- cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); +- if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) +- cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); +- if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) +- cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); +- +- cache.charge_full = bq27xxx_battery_read_fcc(di); +- cache.capacity = bq27xxx_battery_read_soc(di); +- if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) +- cache.energy = bq27xxx_battery_read_energy(di); +- di->cache.flags = cache.flags; +- cache.health = bq27xxx_battery_read_health(di); +- } ++ if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) ++ cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); ++ if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) ++ cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); ++ if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) ++ cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); ++ ++ cache.charge_full = bq27xxx_battery_read_fcc(di); ++ cache.capacity = bq27xxx_battery_read_soc(di); ++ if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) ++ cache.energy = bq27xxx_battery_read_energy(di); ++ di->cache.flags = cache.flags; ++ cache.health = bq27xxx_battery_read_health(di); + if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) + cache.cycle_count = bq27xxx_battery_read_cyct(di); + ++ /* ++ * On gauges with signed current reporting the current must be ++ * checked to detect charging <-> discharging status changes. ++ */ ++ if (!(di->opts & BQ27XXX_O_ZERO)) ++ bq27xxx_battery_current_and_status(di, NULL, &status, &cache); ++ + /* We only have to read charge design full once */ + if (di->charge_design_full <= 0) + di->charge_design_full = bq27xxx_battery_read_dcap(di); + } + + if ((di->cache.capacity != cache.capacity) || +- (di->cache.flags != cache.flags)) ++ (di->cache.flags != cache.flags) || ++ (di->last_status.intval != status.intval)) { ++ di->last_status.intval = status.intval; + power_supply_changed(di->bat); ++ } + + if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) + di->cache = cache; +@@ -1754,39 +1832,6 @@ static void bq27xxx_battery_poll(struct work_struct *work) + bq27xxx_battery_update(di); + } + +-/* +- * Return the battery average current in µA +- * Note that current can be negative signed as well +- * Or 0 if something fails. +- */ +-static int bq27xxx_battery_current(struct bq27xxx_device_info *di, +- union power_supply_propval *val) +-{ +- int curr; +- int flags; +- +- curr = bq27xxx_read(di, BQ27XXX_REG_AI, false); +- if (curr < 0) { +- dev_err(di->dev, "error reading current\n"); +- return curr; +- } +- +- if (di->opts & BQ27XXX_O_ZERO) { +- flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); +- if (flags & BQ27000_FLAG_CHGS) { +- dev_dbg(di->dev, "negative current!\n"); +- curr = -curr; +- } +- +- val->intval = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; +- } else { +- /* Other gauges return signed value */ +- val->intval = (int)((s16)curr) * 1000; +- } +- +- return 0; +-} +- + /* + * Get the average power in µW + * Return < 0 if something fails. +@@ -1813,43 +1858,6 @@ static int bq27xxx_battery_pwr_avg(struct bq27xxx_device_info *di, + return 0; + } + +-static int bq27xxx_battery_status(struct bq27xxx_device_info *di, +- union power_supply_propval *val) +-{ +- int status; +- +- if (di->opts & BQ27XXX_O_ZERO) { +- if (di->cache.flags & BQ27000_FLAG_FC) +- status = POWER_SUPPLY_STATUS_FULL; +- else if (di->cache.flags & BQ27000_FLAG_CHGS) +- status = POWER_SUPPLY_STATUS_CHARGING; +- else +- status = POWER_SUPPLY_STATUS_DISCHARGING; +- } else if (di->opts & BQ27Z561_O_BITS) { +- if (di->cache.flags & BQ27Z561_FLAG_FC) +- status = POWER_SUPPLY_STATUS_FULL; +- else if (di->cache.flags & BQ27Z561_FLAG_DIS_CH) +- status = POWER_SUPPLY_STATUS_DISCHARGING; +- else +- status = POWER_SUPPLY_STATUS_CHARGING; +- } else { +- if (di->cache.flags & BQ27XXX_FLAG_FC) +- status = POWER_SUPPLY_STATUS_FULL; +- else if (di->cache.flags & BQ27XXX_FLAG_DSC) +- status = POWER_SUPPLY_STATUS_DISCHARGING; +- else +- status = POWER_SUPPLY_STATUS_CHARGING; +- } +- +- if ((status == POWER_SUPPLY_STATUS_DISCHARGING) && +- (power_supply_am_i_supplied(di->bat) > 0)) +- status = POWER_SUPPLY_STATUS_NOT_CHARGING; +- +- val->intval = status; +- +- return 0; +-} +- + static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, + union power_supply_propval *val) + { +@@ -1935,7 +1943,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: +- ret = bq27xxx_battery_status(di, val); ++ ret = bq27xxx_battery_current_and_status(di, NULL, val, NULL); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = bq27xxx_battery_voltage(di, val); +@@ -1944,7 +1952,7 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, + val->intval = di->cache.flags < 0 ? 0 : 1; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: +- ret = bq27xxx_battery_current(di, val); ++ ret = bq27xxx_battery_current_and_status(di, val, NULL, NULL); + break; + case POWER_SUPPLY_PROP_CAPACITY: + ret = bq27xxx_simple_value(di->cache.capacity, val); +@@ -2014,8 +2022,8 @@ static void bq27xxx_external_power_changed(struct power_supply *psy) + { + struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); + +- cancel_delayed_work_sync(&di->work); +- schedule_delayed_work(&di->work, 0); ++ /* After charger plug in/out wait 0.5s for things to stabilize */ ++ mod_delayed_work(system_wq, &di->work, HZ / 2); + } + + int bq27xxx_battery_setup(struct bq27xxx_device_info *di) +diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c +index 2b644590fa8e0..53e5b3e04be13 100644 +--- a/drivers/power/supply/power_supply_core.c ++++ b/drivers/power/supply/power_supply_core.c +@@ -375,46 +375,49 @@ int power_supply_is_system_supplied(void) + } + EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); + +-static int __power_supply_get_supplier_max_current(struct device *dev, +- void *data) ++struct psy_get_supplier_prop_data { ++ struct power_supply *psy; ++ enum power_supply_property psp; ++ union power_supply_propval *val; ++}; ++ ++static int __power_supply_get_supplier_property(struct device *dev, void *_data) + { +- union power_supply_propval ret = {0,}; + struct power_supply *epsy = dev_get_drvdata(dev); +- struct power_supply *psy = data; ++ struct psy_get_supplier_prop_data *data = _data; + +- if (__power_supply_is_supplied_by(epsy, psy)) +- if (!epsy->desc->get_property(epsy, +- POWER_SUPPLY_PROP_CURRENT_MAX, +- &ret)) +- return ret.intval; ++ if (__power_supply_is_supplied_by(epsy, data->psy)) ++ if (!epsy->desc->get_property(epsy, data->psp, data->val)) ++ return 1; /* Success */ + +- return 0; ++ return 0; /* Continue iterating */ + } + +-int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy) ++int power_supply_get_property_from_supplier(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) + { +- union power_supply_propval val = {0,}; +- int curr; +- +- if (!psy->desc->set_property) +- return -EINVAL; ++ struct psy_get_supplier_prop_data data = { ++ .psy = psy, ++ .psp = psp, ++ .val = val, ++ }; ++ int ret; + + /* + * This function is not intended for use with a supply with multiple +- * suppliers, we simply pick the first supply to report a non 0 +- * max-current. ++ * suppliers, we simply pick the first supply to report the psp. + */ +- curr = class_for_each_device(power_supply_class, NULL, psy, +- __power_supply_get_supplier_max_current); +- if (curr <= 0) +- return (curr == 0) ? -ENODEV : curr; +- +- val.intval = curr; ++ ret = class_for_each_device(power_supply_class, NULL, &data, ++ __power_supply_get_supplier_property); ++ if (ret < 0) ++ return ret; ++ if (ret == 0) ++ return -ENODEV; + +- return psy->desc->set_property(psy, +- POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); ++ return 0; + } +-EXPORT_SYMBOL_GPL(power_supply_set_input_current_limit_from_supplier); ++EXPORT_SYMBOL_GPL(power_supply_get_property_from_supplier); + + int power_supply_set_battery_charged(struct power_supply *psy) + { +diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c +index e4bb09bbd3fa6..a356f84b1285b 100644 +--- a/drivers/regulator/helpers.c ++++ b/drivers/regulator/helpers.c +@@ -879,3 +879,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2) + return reg1->rdev == reg2->rdev; + } + EXPORT_SYMBOL_GPL(regulator_is_equal); ++ ++static int find_closest_bigger(unsigned int target, const unsigned int *table, ++ unsigned int num_sel, unsigned int *sel) ++{ ++ unsigned int s, tmp, max, maxsel = 0; ++ bool found = false; ++ ++ max = table[0]; ++ ++ for (s = 0; s < num_sel; s++) { ++ if (table[s] > max) { ++ max = table[s]; ++ maxsel = s; ++ } ++ if (table[s] >= target) { ++ if (!found || table[s] - target < tmp - target) { ++ tmp = table[s]; ++ *sel = s; ++ found = true; ++ if (tmp == target) ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ *sel = maxsel; ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * regulator_set_ramp_delay_regmap - set_ramp_delay() helper ++ * ++ * @rdev: regulator to operate on ++ * ++ * Regulators that use regmap for their register I/O can set the ramp_reg ++ * and ramp_mask fields in their descriptor and then use this as their ++ * set_ramp_delay operation, saving some code. ++ */ ++int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay) ++{ ++ int ret; ++ unsigned int sel; ++ ++ if (!rdev->desc->n_ramp_values) ++ return -EINVAL; ++ ++ ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table, ++ rdev->desc->n_ramp_values, &sel); ++ ++ if (ret) { ++ dev_warn(rdev_get_dev(rdev), ++ "Can't set ramp-delay %u, setting %u\n", ramp_delay, ++ rdev->desc->ramp_delay_table[sel]); ++ } ++ ++ sel <<= ffs(rdev->desc->ramp_mask) - 1; ++ ++ return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg, ++ rdev->desc->ramp_mask, sel); ++} ++EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap); +diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c +index d38109cc3a011..b3d206ebb2894 100644 +--- a/drivers/regulator/pca9450-regulator.c ++++ b/drivers/regulator/pca9450-regulator.c +@@ -65,32 +65,9 @@ static const struct regmap_config pca9450_regmap_config = { + * 10: 25mV/4usec + * 11: 25mV/8usec + */ +-static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev, +- int ramp_delay) +-{ +- int id = rdev_get_id(rdev); +- unsigned int ramp_value; +- +- switch (ramp_delay) { +- case 1 ... 3125: +- ramp_value = BUCK1_RAMP_3P125MV; +- break; +- case 3126 ... 6250: +- ramp_value = BUCK1_RAMP_6P25MV; +- break; +- case 6251 ... 12500: +- ramp_value = BUCK1_RAMP_12P5MV; +- break; +- case 12501 ... 25000: +- ramp_value = BUCK1_RAMP_25MV; +- break; +- default: +- ramp_value = BUCK1_RAMP_25MV; +- } +- +- return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3, +- BUCK1_RAMP_MASK, ramp_value << 6); +-} ++static const unsigned int pca9450_dvs_buck_ramp_table[] = { ++ 25000, 12500, 6250, 3125 ++}; + + static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { + .enable = regulator_enable_regmap, +@@ -100,7 +77,7 @@ static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, +- .set_ramp_delay = pca9450_dvs_set_ramp_delay, ++ .set_ramp_delay = regulator_set_ramp_delay_regmap, + }; + + static const struct regulator_ops pca9450_buck_regulator_ops = { +@@ -251,6 +228,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { + .vsel_mask = BUCK1OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK1CTRL, + .enable_mask = BUCK1_ENMODE_MASK, ++ .ramp_reg = PCA9450_REG_BUCK1CTRL, ++ .ramp_mask = BUCK1_RAMP_MASK, ++ .ramp_delay_table = pca9450_dvs_buck_ramp_table, ++ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, +@@ -275,7 +256,11 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { + .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0, + .vsel_mask = BUCK2OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK2CTRL, +- .enable_mask = BUCK1_ENMODE_MASK, ++ .enable_mask = BUCK2_ENMODE_MASK, ++ .ramp_reg = PCA9450_REG_BUCK2CTRL, ++ .ramp_mask = BUCK2_RAMP_MASK, ++ .ramp_delay_table = pca9450_dvs_buck_ramp_table, ++ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, +@@ -301,6 +286,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { + .vsel_mask = BUCK3OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK3CTRL, + .enable_mask = BUCK3_ENMODE_MASK, ++ .ramp_reg = PCA9450_REG_BUCK3CTRL, ++ .ramp_mask = BUCK3_RAMP_MASK, ++ .ramp_delay_table = pca9450_dvs_buck_ramp_table, ++ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, +@@ -477,6 +466,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { + .vsel_mask = BUCK1OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK1CTRL, + .enable_mask = BUCK1_ENMODE_MASK, ++ .ramp_reg = PCA9450_REG_BUCK1CTRL, ++ .ramp_mask = BUCK1_RAMP_MASK, ++ .ramp_delay_table = pca9450_dvs_buck_ramp_table, ++ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, +@@ -501,7 +494,11 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { + .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0, + .vsel_mask = BUCK2OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK2CTRL, +- .enable_mask = BUCK1_ENMODE_MASK, ++ .enable_mask = BUCK2_ENMODE_MASK, ++ .ramp_reg = PCA9450_REG_BUCK2CTRL, ++ .ramp_mask = BUCK2_RAMP_MASK, ++ .ramp_delay_table = pca9450_dvs_buck_ramp_table, ++ .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, +diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h +index 705b94bd091e3..63964196a436e 100644 +--- a/include/linux/power/bq27xxx_battery.h ++++ b/include/linux/power/bq27xxx_battery.h +@@ -2,6 +2,8 @@ + #ifndef __LINUX_BQ27X00_BATTERY_H__ + #define __LINUX_BQ27X00_BATTERY_H__ + ++#include <linux/power_supply.h> ++ + enum bq27xxx_chip { + BQ27000 = 1, /* bq27000, bq27200 */ + BQ27010, /* bq27010, bq27210 */ +@@ -69,6 +71,7 @@ struct bq27xxx_device_info { + int charge_design_full; + bool removed; + unsigned long last_update; ++ union power_supply_propval last_status; + struct delayed_work work; + struct power_supply *bat; + struct list_head list; +diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h +index 81a55e974feb1..e6fe2f581bdaf 100644 +--- a/include/linux/power_supply.h ++++ b/include/linux/power_supply.h +@@ -413,8 +413,9 @@ power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table + int table_len, int temp); + extern void power_supply_changed(struct power_supply *psy); + extern int power_supply_am_i_supplied(struct power_supply *psy); +-extern int power_supply_set_input_current_limit_from_supplier( +- struct power_supply *psy); ++int power_supply_get_property_from_supplier(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val); + extern int power_supply_set_battery_charged(struct power_supply *psy); + + #ifdef CONFIG_POWER_SUPPLY +diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h +index 11cade73726ce..633e7a2ab01d0 100644 +--- a/include/linux/regulator/driver.h ++++ b/include/linux/regulator/driver.h +@@ -370,6 +370,10 @@ struct regulator_desc { + unsigned int pull_down_reg; + unsigned int pull_down_mask; + unsigned int pull_down_val_on; ++ unsigned int ramp_reg; ++ unsigned int ramp_mask; ++ const unsigned int *ramp_delay_table; ++ unsigned int n_ramp_values; + + unsigned int enable_time; + +@@ -532,6 +536,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev, + int min_uA, int max_uA); + int regulator_get_current_limit_regmap(struct regulator_dev *rdev); + void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); ++int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay); + + /* + * Helper functions intended to be used by regulator drivers prior registering +diff --git a/include/net/ip.h b/include/net/ip.h +index 4b775af572688..8d1173577fb5c 100644 +--- a/include/net/ip.h ++++ b/include/net/ip.h +@@ -75,6 +75,7 @@ struct ipcm_cookie { + __be32 addr; + int oif; + struct ip_options_rcu *opt; ++ __u8 protocol; + __u8 ttl; + __s16 tos; + char priority; +@@ -95,6 +96,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm, + ipcm->sockc.tsflags = inet->sk.sk_tsflags; + ipcm->oif = inet->sk.sk_bound_dev_if; + ipcm->addr = inet->inet_saddr; ++ ipcm->protocol = inet->inet_num; + } + + #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) +diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h +index d1b327036ae43..3960bc3da6b30 100644 +--- a/include/uapi/linux/in.h ++++ b/include/uapi/linux/in.h +@@ -159,6 +159,8 @@ struct in_addr { + #define MCAST_MSFILTER 48 + #define IP_MULTICAST_ALL 49 + #define IP_UNICAST_IF 50 ++#define IP_LOCAL_PORT_RANGE 51 ++#define IP_PROTOCOL 52 + + #define MCAST_EXCLUDE 0 + #define MCAST_INCLUDE 1 +diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c +index 4dcc1a8a8954f..eafb2bebc12cb 100644 +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -980,6 +980,34 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, + + BT_DBG("cmd %x arg %lx", cmd, arg); + ++ /* Make sure the cmd is valid before doing anything */ ++ switch (cmd) { ++ case HCIGETDEVLIST: ++ case HCIGETDEVINFO: ++ case HCIGETCONNLIST: ++ case HCIDEVUP: ++ case HCIDEVDOWN: ++ case HCIDEVRESET: ++ case HCIDEVRESTAT: ++ case HCISETSCAN: ++ case HCISETAUTH: ++ case HCISETENCRYPT: ++ case HCISETPTYPE: ++ case HCISETLINKPOL: ++ case HCISETLINKMODE: ++ case HCISETACLMTU: ++ case HCISETSCOMTU: ++ case HCIINQUIRY: ++ case HCISETRAW: ++ case HCIGETCONNINFO: ++ case HCIGETAUTHINFO: ++ case HCIBLOCKADDR: ++ case HCIUNBLOCKADDR: ++ break; ++ default: ++ return -ENOIOCTLCMD; ++ } ++ + lock_sock(sk); + + if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) { +diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c +index 4cc39c62af55d..1b35afd326b8d 100644 +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -317,7 +317,14 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc, + ipc->tos = val; + ipc->priority = rt_tos2priority(ipc->tos); + break; +- ++ case IP_PROTOCOL: ++ if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) ++ return -EINVAL; ++ val = *(int *)CMSG_DATA(cmsg); ++ if (val < 1 || val > 255) ++ return -EINVAL; ++ ipc->protocol = val; ++ break; + default: + return -EINVAL; + } +@@ -1724,6 +1731,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, + case IP_MINTTL: + val = inet->min_ttl; + break; ++ case IP_PROTOCOL: ++ val = inet_sk(sk)->inet_num; ++ break; + default: + release_sock(sk); + return -ENOPROTOOPT; +diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c +index 4899ebe569eb6..650da4d8f7ad1 100644 +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -559,6 +559,9 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + } + + ipcm_init_sk(&ipc, inet); ++ /* Keep backward compat */ ++ if (hdrincl) ++ ipc.protocol = IPPROTO_RAW; + + if (msg->msg_controllen) { + err = ip_cmsg_send(sk, msg, &ipc, false); +@@ -626,7 +629,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, + RT_SCOPE_UNIVERSE, +- hdrincl ? IPPROTO_RAW : sk->sk_protocol, ++ hdrincl ? ipc.protocol : sk->sk_protocol, + inet_sk_flowi_flags(sk) | + (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), + daddr, saddr, 0, 0, sk->sk_uid); +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index 69f0f9c05d028..7ff06fa7ed19a 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -828,7 +828,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + + if (!proto) + proto = inet->inet_num; +- else if (proto != inet->inet_num) ++ else if (proto != inet->inet_num && ++ inet->inet_num != IPPROTO_RAW) + return -EINVAL; + + if (proto > 255) +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index c9ca857f1068d..6a055a2216831 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -1493,9 +1493,6 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { + + static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data) + { +- if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) +- return 0; +- + return ctnetlink_filter_match(ct, data); + } + +@@ -1561,11 +1558,6 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl, + + ct = nf_ct_tuplehash_to_ctrack(h); + +- if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) { +- nf_ct_put(ct); +- return -EBUSY; +- } +- + if (cda[CTA_ID]) { + __be32 id = nla_get_be32(cda[CTA_ID]); + |