[rdkb][common][bsp][Refactor and sync kernel from openwrt]
[Description]
f937161 [MAC80211][hnat][Add Netfilter Netlink Ftnl package]
7926340 [kernel][common][i2c][add dps368 sensor support]
3b54134 [MAC80211][hnat][Add DSCP offload support]
0adc1d4 [MAC80211][hnat][Fix PPE entry clear issue]
[Release-log]
Change-Id: I509e8f209979486c288df2365eb7ca2a3a5b601f
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
index d35be90..fc9d17c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
@@ -171,6 +171,11 @@
compatible = "wlf,wm8960";
reg = <0x1a>;
};
+
+ dps368: dps368@77 {
+ compatible = "infineon,dps310";
+ reg = <0x77>;
+ };
};
&spi0 {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
index fee356d..74fa426 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
@@ -134,6 +134,11 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
status = "okay";
+
+ dps368: dps368@77 {
+ compatible = "infineon,dps310";
+ reg = <0x77>;
+ };
};
&pwm {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/iio/pressure/dps310.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/iio/pressure/dps310.c
new file mode 100644
index 0000000..72640cb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/iio/pressure/dps310.c
@@ -0,0 +1,848 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright IBM Corp 2019
+/*
+ * The DPS310 is a barometric pressure and temperature sensor.
+ * Currently only reading a single temperature is supported by
+ * this driver.
+ *
+ * https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242
+ *
+ * Temperature calculation:
+ * c0 * 0.5 + c1 * T_raw / kT °C
+ *
+ * TODO:
+ * - Optionally support the FIFO
+ */
+
+#include <linux/i2c.h>
+#include <linux/limits.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DPS310_DEV_NAME "dps310"
+
+#define DPS310_PRS_B0 0x00
+#define DPS310_PRS_B1 0x01
+#define DPS310_PRS_B2 0x02
+#define DPS310_TMP_B0 0x03
+#define DPS310_TMP_B1 0x04
+#define DPS310_TMP_B2 0x05
+#define DPS310_PRS_CFG 0x06
+#define DPS310_PRS_RATE_BITS GENMASK(6, 4)
+#define DPS310_PRS_PRC_BITS GENMASK(3, 0)
+#define DPS310_TMP_CFG 0x07
+#define DPS310_TMP_RATE_BITS GENMASK(6, 4)
+#define DPS310_TMP_PRC_BITS GENMASK(3, 0)
+#define DPS310_TMP_EXT BIT(7)
+#define DPS310_MEAS_CFG 0x08
+#define DPS310_MEAS_CTRL_BITS GENMASK(2, 0)
+#define DPS310_PRS_EN BIT(0)
+#define DPS310_TEMP_EN BIT(1)
+#define DPS310_BACKGROUND BIT(2)
+#define DPS310_PRS_RDY BIT(4)
+#define DPS310_TMP_RDY BIT(5)
+#define DPS310_SENSOR_RDY BIT(6)
+#define DPS310_COEF_RDY BIT(7)
+#define DPS310_CFG_REG 0x09
+#define DPS310_INT_HL BIT(7)
+#define DPS310_TMP_SHIFT_EN BIT(3)
+#define DPS310_PRS_SHIFT_EN BIT(4)
+#define DPS310_FIFO_EN BIT(5)
+#define DPS310_SPI_EN BIT(6)
+#define DPS310_RESET 0x0c
+#define DPS310_RESET_MAGIC 0x09
+#define DPS310_COEF_BASE 0x10
+
+/* Make sure sleep time is <= 20ms for usleep_range */
+#define DPS310_POLL_SLEEP_US(t) min(20000, (t) / 8)
+/* Silently handle error in rate value here */
+#define DPS310_POLL_TIMEOUT_US(rc) ((rc) <= 0 ? 1000000 : 1000000 / (rc))
+
+#define DPS310_PRS_BASE DPS310_PRS_B0
+#define DPS310_TMP_BASE DPS310_TMP_B0
+
+/*
+ * These values (defined in the spec) indicate how to scale the raw register
+ * values for each level of precision available.
+ */
+static const int scale_factors[] = {
+ 524288,
+ 1572864,
+ 3670016,
+ 7864320,
+ 253952,
+ 516096,
+ 1040384,
+ 2088960,
+};
+
+struct dps310_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct mutex lock; /* Lock for sequential HW access functions */
+
+ s32 c0, c1;
+ s32 c00, c10, c20, c30, c01, c11, c21;
+ s32 pressure_raw;
+ s32 temp_raw;
+};
+
+static const struct iio_chan_spec dps310_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+};
+
+/* To be called after checking the COEF_RDY bit in MEAS_CFG */
+static int dps310_get_coefs(struct dps310_data *data)
+{
+ int rc;
+ u8 coef[18];
+ u32 c0, c1;
+ u32 c00, c10, c20, c30, c01, c11, c21;
+
+ /* Read all sensor calibration coefficients from the COEF registers. */
+ rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef,
+ sizeof(coef));
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Calculate temperature calibration coefficients c0 and c1. The
+ * numbers are 12-bit 2's complement numbers.
+ */
+ c0 = (coef[0] << 4) | (coef[1] >> 4);
+ data->c0 = sign_extend32(c0, 11);
+
+ c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2];
+ data->c1 = sign_extend32(c1, 11);
+
+ /*
+ * Calculate pressure calibration coefficients. c00 and c10 are 20 bit
+ * 2's complement numbers, while the rest are 16 bit 2's complement
+ * numbers.
+ */
+ c00 = (coef[3] << 12) | (coef[4] << 4) | (coef[5] >> 4);
+ data->c00 = sign_extend32(c00, 19);
+
+ c10 = ((coef[5] & GENMASK(3, 0)) << 16) | (coef[6] << 8) | coef[7];
+ data->c10 = sign_extend32(c10, 19);
+
+ c01 = (coef[8] << 8) | coef[9];
+ data->c01 = sign_extend32(c01, 15);
+
+ c11 = (coef[10] << 8) | coef[11];
+ data->c11 = sign_extend32(c11, 15);
+
+ c20 = (coef[12] << 8) | coef[13];
+ data->c20 = sign_extend32(c20, 15);
+
+ c21 = (coef[14] << 8) | coef[15];
+ data->c21 = sign_extend32(c21, 15);
+
+ c30 = (coef[16] << 8) | coef[17];
+ data->c30 = sign_extend32(c30, 15);
+
+ return 0;
+}
+
+static int dps310_get_pres_precision(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT(val & GENMASK(2, 0));
+}
+
+static int dps310_get_temp_precision(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Scale factor is bottom 4 bits of the register, but 1111 is
+ * reserved so just grab bottom three
+ */
+ return BIT(val & GENMASK(2, 0));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_precision(struct dps310_data *data, int val)
+{
+ int rc;
+ u8 shift_en;
+
+ if (val < 0 || val > 128)
+ return -EINVAL;
+
+ shift_en = val >= 16 ? DPS310_PRS_SHIFT_EN : 0;
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_PRS_SHIFT_EN, shift_en);
+ if (rc)
+ return rc;
+
+ return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+ DPS310_PRS_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_temp_precision(struct dps310_data *data, int val)
+{
+ int rc;
+ u8 shift_en;
+
+ if (val < 0 || val > 128)
+ return -EINVAL;
+
+ shift_en = val >= 16 ? DPS310_TMP_SHIFT_EN : 0;
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_TMP_SHIFT_EN, shift_en);
+ if (rc)
+ return rc;
+
+ return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+ DPS310_TMP_PRC_BITS, ilog2(val));
+}
+
+/* Called with lock held */
+static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq)
+{
+ u8 val;
+
+ if (freq < 0 || freq > 128)
+ return -EINVAL;
+
+ val = ilog2(freq) << 4;
+
+ return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+ DPS310_PRS_RATE_BITS, val);
+}
+
+/* Called with lock held */
+static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq)
+{
+ u8 val;
+
+ if (freq < 0 || freq > 128)
+ return -EINVAL;
+
+ val = ilog2(freq) << 4;
+
+ return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+ DPS310_TMP_RATE_BITS, val);
+}
+
+static int dps310_get_pres_samp_freq(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT((val & DPS310_PRS_RATE_BITS) >> 4);
+}
+
+static int dps310_get_temp_samp_freq(struct dps310_data *data)
+{
+ int rc;
+ int val;
+
+ rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val);
+ if (rc < 0)
+ return rc;
+
+ return BIT((val & DPS310_TMP_RATE_BITS) >> 4);
+}
+
+static int dps310_get_pres_k(struct dps310_data *data)
+{
+ int rc = dps310_get_pres_precision(data);
+
+ if (rc < 0)
+ return rc;
+
+ return scale_factors[ilog2(rc)];
+}
+
+static int dps310_get_temp_k(struct dps310_data *data)
+{
+ int rc = dps310_get_temp_precision(data);
+
+ if (rc < 0)
+ return rc;
+
+ return scale_factors[ilog2(rc)];
+}
+
+static int dps310_read_pres_raw(struct dps310_data *data)
+{
+ int rc;
+ int rate;
+ int ready;
+ int timeout;
+ s32 raw;
+ u8 val[3];
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ rate = dps310_get_pres_samp_freq(data);
+ timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+ /* Poll for sensor readiness; base the timeout upon the sample rate. */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_PRS_RDY,
+ DPS310_POLL_SLEEP_US(timeout), timeout);
+ if (rc)
+ goto done;
+
+ rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val));
+ if (rc < 0)
+ goto done;
+
+ raw = (val[0] << 16) | (val[1] << 8) | val[2];
+ data->pressure_raw = sign_extend32(raw, 23);
+
+done:
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+/* Called with lock held */
+static int dps310_read_temp_ready(struct dps310_data *data)
+{
+ int rc;
+ u8 val[3];
+ s32 raw;
+
+ rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val));
+ if (rc < 0)
+ return rc;
+
+ raw = (val[0] << 16) | (val[1] << 8) | val[2];
+ data->temp_raw = sign_extend32(raw, 23);
+
+ return 0;
+}
+
+static int dps310_read_temp_raw(struct dps310_data *data)
+{
+ int rc;
+ int rate;
+ int ready;
+ int timeout;
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ rate = dps310_get_temp_samp_freq(data);
+ timeout = DPS310_POLL_TIMEOUT_US(rate);
+
+ /* Poll for sensor readiness; base the timeout upon the sample rate. */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_TMP_RDY,
+ DPS310_POLL_SLEEP_US(timeout), timeout);
+ if (rc < 0)
+ goto done;
+
+ rc = dps310_read_temp_ready(data);
+
+done:
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DPS310_PRS_CFG:
+ case DPS310_TMP_CFG:
+ case DPS310_MEAS_CFG:
+ case DPS310_CFG_REG:
+ case DPS310_RESET:
+ /* No documentation available on the registers below */
+ case 0x0e:
+ case 0x0f:
+ case 0x62:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool dps310_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DPS310_PRS_B0:
+ case DPS310_PRS_B1:
+ case DPS310_PRS_B2:
+ case DPS310_TMP_B0:
+ case DPS310_TMP_B1:
+ case DPS310_TMP_B2:
+ case DPS310_MEAS_CFG:
+ case 0x32: /* No documentation available on this register */
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int dps310_write_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int rc;
+ struct dps310_data *data = iio_priv(iio);
+
+ if (mutex_lock_interruptible(&data->lock))
+ return -EINTR;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ rc = dps310_set_pres_samp_freq(data, val);
+ break;
+
+ case IIO_TEMP:
+ rc = dps310_set_temp_samp_freq(data, val);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ rc = dps310_set_pres_precision(data, val);
+ break;
+
+ case IIO_TEMP:
+ rc = dps310_set_temp_precision(data, val);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&data->lock);
+ return rc;
+}
+
+static int dps310_calculate_pressure(struct dps310_data *data)
+{
+ int i;
+ int rc;
+ int t_ready;
+ int kpi = dps310_get_pres_k(data);
+ int kti = dps310_get_temp_k(data);
+ s64 rem = 0ULL;
+ s64 pressure = 0ULL;
+ s64 p;
+ s64 t;
+ s64 denoms[7];
+ s64 nums[7];
+ s64 rems[7];
+ s64 kp;
+ s64 kt;
+
+ if (kpi < 0)
+ return kpi;
+
+ if (kti < 0)
+ return kti;
+
+ kp = (s64)kpi;
+ kt = (s64)kti;
+
+ /* Refresh temp if it's ready, otherwise just use the latest value */
+ if (mutex_trylock(&data->lock)) {
+ rc = regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready);
+ if (rc >= 0 && t_ready & DPS310_TMP_RDY)
+ dps310_read_temp_ready(data);
+
+ mutex_unlock(&data->lock);
+ }
+
+ p = (s64)data->pressure_raw;
+ t = (s64)data->temp_raw;
+
+ /* Section 4.9.1 of the DPS310 spec; algebra'd to avoid underflow */
+ nums[0] = (s64)data->c00;
+ denoms[0] = 1LL;
+ nums[1] = p * (s64)data->c10;
+ denoms[1] = kp;
+ nums[2] = p * p * (s64)data->c20;
+ denoms[2] = kp * kp;
+ nums[3] = p * p * p * (s64)data->c30;
+ denoms[3] = kp * kp * kp;
+ nums[4] = t * (s64)data->c01;
+ denoms[4] = kt;
+ nums[5] = t * p * (s64)data->c11;
+ denoms[5] = kp * kt;
+ nums[6] = t * p * p * (s64)data->c21;
+ denoms[6] = kp * kp * kt;
+
+ /* Kernel lacks a div64_s64_rem function; denoms are all positive */
+ for (i = 0; i < 7; ++i) {
+ u64 irem;
+
+ if (nums[i] < 0LL) {
+ pressure -= div64_u64_rem(-nums[i], denoms[i], &irem);
+ rems[i] = -irem;
+ } else {
+ pressure += div64_u64_rem(nums[i], denoms[i], &irem);
+ rems[i] = (s64)irem;
+ }
+ }
+
+ /* Increase precision and calculate the remainder sum */
+ for (i = 0; i < 7; ++i)
+ rem += div64_s64((s64)rems[i] * 1000000000LL, denoms[i]);
+
+ pressure += div_s64(rem, 1000000000LL);
+ if (pressure < 0LL)
+ return -ERANGE;
+
+ return (int)min_t(s64, pressure, INT_MAX);
+}
+
+static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2,
+ long mask)
+{
+ int rc;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = dps310_get_pres_samp_freq(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_PROCESSED:
+ rc = dps310_read_pres_raw(data);
+ if (rc)
+ return rc;
+
+ rc = dps310_calculate_pressure(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ *val2 = 1000; /* Convert Pa to KPa per IIO ABI */
+ return IIO_VAL_FRACTIONAL;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ rc = dps310_get_pres_precision(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dps310_calculate_temp(struct dps310_data *data)
+{
+ s64 c0;
+ s64 t;
+ int kt = dps310_get_temp_k(data);
+
+ if (kt < 0)
+ return kt;
+
+ /* Obtain inverse-scaled offset */
+ c0 = div_s64((s64)kt * (s64)data->c0, 2);
+
+ /* Add the offset to the unscaled temperature */
+ t = c0 + ((s64)data->temp_raw * (s64)data->c1);
+
+ /* Convert to milliCelsius and scale the temperature */
+ return (int)div_s64(t * 1000LL, kt);
+}
+
+static int dps310_read_temp(struct dps310_data *data, int *val, int *val2,
+ long mask)
+{
+ int rc;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ rc = dps310_get_temp_samp_freq(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_PROCESSED:
+ rc = dps310_read_temp_raw(data);
+ if (rc)
+ return rc;
+
+ rc = dps310_calculate_temp(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ rc = dps310_get_temp_precision(data);
+ if (rc < 0)
+ return rc;
+
+ *val = rc;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dps310_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct dps310_data *data = iio_priv(iio);
+
+ switch (chan->type) {
+ case IIO_PRESSURE:
+ return dps310_read_pressure(data, val, val2, mask);
+
+ case IIO_TEMP:
+ return dps310_read_temp(data, val, val2, mask);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void dps310_reset(void *action_data)
+{
+ struct dps310_data *data = action_data;
+
+ regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC);
+}
+
+static const struct regmap_config dps310_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = dps310_is_writeable_reg,
+ .volatile_reg = dps310_is_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = 0x62, /* No documentation available on this register */
+};
+
+static const struct iio_info dps310_info = {
+ .read_raw = dps310_read_raw,
+ .write_raw = dps310_write_raw,
+};
+
+/*
+ * Some verions of chip will read temperatures in the ~60C range when
+ * its actually ~20C. This is the manufacturer recommended workaround
+ * to correct the issue. The registers used below are undocumented.
+ */
+static int dps310_temp_workaround(struct dps310_data *data)
+{
+ int rc;
+ int reg;
+
+ rc = regmap_read(data->regmap, 0x32, ®);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * If bit 1 is set then the device is okay, and the workaround does not
+ * need to be applied
+ */
+ if (reg & BIT(1))
+ return 0;
+
+ rc = regmap_write(data->regmap, 0x0e, 0xA5);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x0f, 0x96);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x62, 0x02);
+ if (rc < 0)
+ return rc;
+
+ rc = regmap_write(data->regmap, 0x0e, 0x00);
+ if (rc < 0)
+ return rc;
+
+ return regmap_write(data->regmap, 0x0f, 0x00);
+}
+
+static int dps310_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct dps310_data *data;
+ struct iio_dev *iio;
+ int rc, ready;
+
+ iio = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!iio)
+ return -ENOMEM;
+
+ data = iio_priv(iio);
+ data->client = client;
+ mutex_init(&data->lock);
+
+ iio->name = id->name;
+ iio->channels = dps310_channels;
+ iio->num_channels = ARRAY_SIZE(dps310_channels);
+ iio->info = &dps310_info;
+ iio->modes = INDIO_DIRECT_MODE;
+
+ data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ /* Register to run the device reset when the device is removed */
+ rc = devm_add_action_or_reset(&client->dev, dps310_reset, data);
+ if (rc)
+ return rc;
+
+ /*
+ * Set up pressure sensor in single sample, one measurement per second
+ * mode
+ */
+ rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0);
+
+ /*
+ * Set up external (MEMS) temperature sensor in single sample, one
+ * measurement per second mode
+ */
+ rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT);
+ if (rc < 0)
+ return rc;
+
+ /* Temp and pressure shifts are disabled when PRC <= 8 */
+ rc = regmap_write_bits(data->regmap, DPS310_CFG_REG,
+ DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0);
+ if (rc < 0)
+ return rc;
+
+ /* MEAS_CFG doesn't update correctly unless first written with 0 */
+ rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+ DPS310_MEAS_CTRL_BITS, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Turn on temperature and pressure measurement in the background */
+ rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG,
+ DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN |
+ DPS310_TEMP_EN | DPS310_BACKGROUND);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Calibration coefficients required for reporting temperature.
+ * They are available 40ms after the device has started
+ */
+ rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready,
+ ready & DPS310_COEF_RDY, 10000, 40000);
+ if (rc < 0)
+ return rc;
+
+ rc = dps310_get_coefs(data);
+ if (rc < 0)
+ return rc;
+
+ rc = dps310_temp_workaround(data);
+ if (rc < 0)
+ return rc;
+
+ rc = devm_iio_device_register(&client->dev, iio);
+ if (rc)
+ return rc;
+
+ i2c_set_clientdata(client, iio);
+
+ return 0;
+}
+
+static int dps310_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id dps310_id[] = {
+ { DPS310_DEV_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, dps310_id);
+
+static const struct acpi_device_id dps310_acpi_match[] = {
+ { "IFX3100" },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, dps310_acpi_match);
+
+static const struct of_device_id dps310_of_match[] = {
+ { .compatible = "infineon,dps310", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dps310_of_match);
+
+static struct i2c_driver dps310_driver = {
+ .driver = {
+ .name = DPS310_DEV_NAME,
+ .acpi_match_table = dps310_acpi_match,
+ .of_match_table = dps310_of_match,
+ },
+ .probe = dps310_probe,
+ .remove = dps310_remove,
+ .id_table = dps310_id,
+};
+module_i2c_driver(dps310_driver);
+
+MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
+MODULE_DESCRIPTION("Infineon DPS310 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9993-add-wed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9993-add-wed.patch
index baa88ef..b4f8e4e 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9993-add-wed.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9993-add-wed.patch
@@ -654,7 +654,7 @@
entry->ipv6.ib2 = val;
l2 = &entry->ipv6.l2;
} else {
-@@ -329,32 +351,167 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
+@@ -329,32 +351,168 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
return 0;
}
@@ -723,6 +723,7 @@
+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
+ MTK_FOE_STATE_INVALID);
+ dma_wmb();
++ mtk_ppe_cache_clear(ppe);
+ }
+ entry->hash = 0xffff;
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-2-flow-offload-add-mtkhnat-flow-accounting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-2-flow-offload-add-mtkhnat-flow-accounting.patch
index f6243d0..5b6253f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-2-flow-offload-add-mtkhnat-flow-accounting.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-2-flow-offload-add-mtkhnat-flow-accounting.patch
@@ -139,9 +139,10 @@
static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
{
ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
-@@ -412,6 +452,18 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
+@@ -412,7 +452,19 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
MTK_FOE_STATE_INVALID);
dma_wmb();
+ mtk_ppe_cache_clear(ppe);
+
+ if (ppe->accounting) {
+ struct mtk_foe_accounting *acct, *acct_updated;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-8-flow-offload-add-mtkhnat-dscp.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-8-flow-offload-add-mtkhnat-dscp.patch
new file mode 100644
index 0000000..fe278a7
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-8-flow-offload-add-mtkhnat-dscp.patch
@@ -0,0 +1,169 @@
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+index c2416b1..bc13a9b 100755
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -435,6 +435,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
+
+ return 0;
+ }
++
++int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
++{
++ u32 *ib2 = mtk_foe_entry_ib2(entry);
++
++ *ib2 &= ~MTK_FOE_IB2_DSCP;
++ *ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
++
++ return 0;
++}
++
+ static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
+ {
+ return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+index e7ecbf7..df10040 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -430,6 +430,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
+ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+ int bss, int wcid);
+ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
++int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
+ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index 23d2048..9bc0857 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -246,6 +246,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ int wed_index = -1;
+ u16 addr_type = 0;
+ u8 l4proto = 0;
++ u8 dscp = 0;
+ int err = 0;
+ int i;
+
+@@ -282,6 +283,15 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ return -EOPNOTSUPP;
+ }
+
++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
++ struct flow_match_ip match;
++
++ flow_rule_match_ip(rule, &match);
++ dscp = match.key->tos;
++ } else {
++ return -EOPNOTSUPP;
++ }
++
+ switch (addr_type) {
+ case 0:
+ offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
+@@ -441,6 +451,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ if (data.pppoe.num == 1)
+ mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+
++ mtk_foe_entry_set_dscp(&foe, dscp);
++
+ err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
+ &wed_index);
+ if (err)
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index 55359dd..1a23c03 100644
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -36,6 +36,7 @@ struct nf_flow_key {
+ };
+ struct flow_dissector_key_tcp tcp;
+ struct flow_dissector_key_ports tp;
++ struct flow_dissector_key_ip ip;
+ } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
+
+ struct nf_flow_match {
+@@ -145,6 +146,7 @@ struct flow_offload_tuple {
+ u8 h_dest[ETH_ALEN];
+ } out;
+ };
++ u8 tos;
+ };
+
+ struct flow_offload_tuple_rhash {
+diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
+index 61cc518..c1a5f64 100644
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -104,6 +104,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
+ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
+ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
+ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);
++ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IP, ip);
+
+ if (other_dst && other_dst->lwtstate) {
+ tun_info = lwt_tun_info(other_dst->lwtstate);
+@@ -183,10 +184,14 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
+ key->tp.dst = tuple->dst_port;
+ mask->tp.dst = 0xffff;
+
++ key->ip.tos = tuple->tos;
++ mask->ip.tos = 0xff;
++
+ match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
+ BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT(FLOW_DISSECTOR_KEY_BASIC) |
+- BIT(FLOW_DISSECTOR_KEY_PORTS);
++ BIT(FLOW_DISSECTOR_KEY_PORTS) |
++ BIT(FLOW_DISSECTOR_KEY_IP);
+ return 0;
+ }
+
+diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
+index 2d5c3cc..b231dd7 100644
+--- a/net/netfilter/xt_FLOWOFFLOAD.c
++++ b/net/netfilter/xt_FLOWOFFLOAD.c
+@@ -49,6 +49,35 @@ static DEFINE_SPINLOCK(hooks_lock);
+
+ struct xt_flowoffload_table flowtable[2];
+
++static int
++xt_flowoffload_dscp_init(struct sk_buff *skb, struct flow_offload *flow,
++ enum ip_conntrack_dir dir)
++{
++ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
++ struct iphdr *iph;
++ struct ipv6hdr *ip6h;
++ u32 offset = 0;
++ u8 tos = 0;
++
++ switch (flow_tuple->l3proto) {
++ case NFPROTO_IPV4:
++ iph = (struct iphdr *)(skb_network_header(skb) + offset);
++ tos = iph->tos;
++ break;
++ case NFPROTO_IPV6:
++ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
++ tos = ipv6_get_dsfield(ip6h);
++ break;
++ default:
++ return -1;
++ };
++
++ flow->tuplehash[dir].tuple.tos = tos;
++ flow->tuplehash[!dir].tuple.tos = tos;
++
++ return 0;
++}
++
+ static unsigned int
+ xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+@@ -599,6 +628,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
+ if (flow_offload_route_init(flow, &route) < 0)
+ goto err_flow_add;
+
++ if (xt_flowoffload_dscp_init(skb, flow, dir) < 0)
++ goto err_flow_add;
++
+ if (tcph) {
+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
+ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-9-flow-offload-add-mtkhnat-netlink.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-9-flow-offload-add-mtkhnat-netlink.patch
new file mode 100644
index 0000000..3b9e863
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9999-9-flow-offload-add-mtkhnat-netlink.patch
@@ -0,0 +1,337 @@
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index 8a84de3..1a23c03 100644
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -276,6 +276,7 @@ int nf_flow_table_init(struct nf_flowtable *flow_table);
+ void nf_flow_table_free(struct nf_flowtable *flow_table);
+
+ void flow_offload_teardown(struct flow_offload *flow);
++void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple);
+
+ int nf_flow_table_iterate(struct nf_flowtable *flow_table,
+ void (*iter)(struct flow_offload *flow, void *data),
+diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
+index 5bc960f..603d9c0 100644
+--- a/include/uapi/linux/netfilter/nfnetlink.h
++++ b/include/uapi/linux/netfilter/nfnetlink.h
+@@ -60,7 +60,8 @@ struct nfgenmsg {
+ #define NFNL_SUBSYS_CTHELPER 9
+ #define NFNL_SUBSYS_NFTABLES 10
+ #define NFNL_SUBSYS_NFT_COMPAT 11
+-#define NFNL_SUBSYS_COUNT 12
++#define NFNL_SUBSYS_FLOWTABLE 12
++#define NFNL_SUBSYS_COUNT 13
+
+ /* Reserved control nfnetlink messages */
+ #define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
+diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
+index 5d690ab..8ec87aa 100644
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -708,6 +708,15 @@ config NF_FLOW_TABLE
+
+ To compile it as a module, choose M here.
+
++config NF_FLOW_TABLE_NETLINK
++ tristate "Netfilter flow table netlink module"
++ depends on NETFILTER_INGRESS
++ depends on NF_CONNTRACK
++ help
++ This option adds the flow table core infrastructure.
++
++ To compile it as a module, choose M here.
++
+ config NETFILTER_XTABLES
+ tristate "Netfilter Xtables support (required for ip_tables)"
+ default m if NETFILTER_ADVANCED=n
+diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
+index d93a121..fa6ffb1 100644
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -124,6 +124,7 @@ nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \
+ nf_flow_table_offload.o
+
+ obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
++obj-$(CONFIG_NF_FLOW_TABLE_NETLINK) += nf_flow_table_netlink.o
+
+ # generic X tables
+ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
+index 1036558..a0f52f6 100644
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -373,6 +373,29 @@ void flow_offload_teardown(struct flow_offload *flow)
+ }
+ EXPORT_SYMBOL_GPL(flow_offload_teardown);
+
++void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple)
++{
++ struct net_device *netdev;
++ struct nf_flowtable *flowtable;
++ struct flow_offload_tuple_rhash *tuplehash;
++ struct flow_offload *flow;
++ int dir;
++
++ list_for_each_entry(flowtable, &flowtables, list) {
++ for_each_netdev(&init_net, netdev) {
++ tuple->iifidx = netdev->ifindex;
++ tuplehash = flow_offload_lookup(flowtable, tuple);
++ if (!tuplehash)
++ continue;
++
++ dir = tuplehash->tuple.dir;
++ flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
++ flow_offload_teardown(flow);
++ }
++ };
++}
++EXPORT_SYMBOL_GPL(flow_offload_teardown_by_tuple);
++
+ struct flow_offload_tuple_rhash *
+ flow_offload_lookup(struct nf_flowtable *flow_table,
+ struct flow_offload_tuple *tuple)
+diff --git a/net/netfilter/nf_flow_table_netlink.c b/net/netfilter/nf_flow_table_netlink.c
+new file mode 100644
+index 0000000..f05f29e
+--- /dev/null
++++ b/net/netfilter/nf_flow_table_netlink.c
+@@ -0,0 +1,239 @@
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/netlink.h>
++#include <net/netlink.h>
++#include <net/ip.h>
++#include <linux/netfilter/nfnetlink.h>
++#include <net/netfilter/nf_flow_table.h>
++
++enum ft_netlink_msg_types {
++ FT_MSG_DEL,
++ FT_MSG_ADD,
++ FT_MSG_FLUSH,
++ FT_MSG_MAX
++};
++
++enum ftattr_type {
++ FTA_UNSPEC,
++ FTA_TUPLE,
++ __FTA_MAX
++};
++#define FTA_MAX (__FTA_MAX - 1)
++
++enum ftattr_tuple {
++ FTA_TUPLE_UNSPEC,
++ FTA_TUPLE_IP,
++ FTA_TUPLE_PROTO,
++ FTA_TUPLE_ZONE,
++ __FTA_TUPLE_MAX
++};
++#define FTA_TUPLE_MAX (__FTA_TUPLE_MAX - 1)
++
++enum ftattr_ip {
++ FTA_IP_UNSPEC,
++ FTA_IP_V4_SRC,
++ FTA_IP_V4_DST,
++ __FTA_IP_MAX
++};
++#define FTA_IP_MAX (__FTA_IP_MAX - 1)
++
++enum ftattr_l4proto {
++ FTA_PROTO_UNSPEC,
++ FTA_PROTO_NUM,
++ FTA_PROTO_SPORT,
++ FTA_PROTO_DPORT,
++ __FTA_PROTO_MAX
++};
++#define FTA_PROTO_MAX (__FTA_PROTO_MAX - 1)
++
++static const struct nla_policy tuple_nla_policy[FTA_TUPLE_MAX + 1] = {
++ [FTA_TUPLE_IP] = { .type = NLA_NESTED },
++ [FTA_TUPLE_PROTO] = { .type = NLA_NESTED },
++ [FTA_TUPLE_ZONE] = { .type = NLA_U16 },
++};
++
++static const struct nla_policy ip_nla_policy[FTA_IP_MAX + 1] = {
++ [FTA_IP_V4_SRC] = { .type = NLA_U32 },
++ [FTA_IP_V4_DST] = { .type = NLA_U32 },
++};
++
++static const struct nla_policy l4proto_nla_policy[FTA_PROTO_MAX + 1] = {
++ [FTA_PROTO_NUM] = { .type = NLA_U8 },
++ [FTA_PROTO_SPORT] = {.type = NLA_U16},
++ [FTA_PROTO_DPORT] = {.type = NLA_U16},
++};
++
++static inline int ftnetlink_parse_tuple_ip(struct nlattr *attr,
++ struct flow_offload_tuple *tuple)
++{
++ struct nlattr *tb[FTA_IP_MAX+1];
++ int err;
++
++ err = nla_parse_nested_deprecated(tb, FTA_IP_MAX, attr, ip_nla_policy, NULL);
++
++ if (err < 0)
++ return err;
++
++ switch (tuple->l3proto) {
++ case NFPROTO_IPV4:
++ if (!tb[FTA_IP_V4_SRC] || !tb[FTA_IP_V4_DST])
++ return -EINVAL;
++
++ tuple->src_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_SRC]);
++ tuple->dst_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_DST]);
++ }
++
++ return err;
++}
++
++static inline int ftnetlink_parse_tuple_proto(struct nlattr *attr,
++ struct flow_offload_tuple *tuple)
++{
++ struct nlattr *tb[FTA_PROTO_MAX+1];
++ int err;
++
++ err = nla_parse_nested_deprecated(tb, FTA_PROTO_MAX, attr, l4proto_nla_policy, NULL);
++
++ if(err < 0)
++ return err;
++
++ if (!tb[FTA_PROTO_NUM] || !tb[FTA_PROTO_SPORT] || !tb[FTA_PROTO_DPORT])
++ return -EINVAL;
++
++ tuple->l4proto = nla_get_u8(tb[FTA_PROTO_NUM]);
++ tuple->src_port = nla_get_u16(tb[FTA_PROTO_SPORT]);
++ tuple->dst_port = nla_get_u16(tb[FTA_PROTO_DPORT]);
++
++ return err;
++}
++
++static int ftnetlink_parse_tuple(const struct nlattr * const cda[],
++ struct flow_offload_tuple *tuple,
++ int attrtype, int l3proto)
++{
++ struct nlattr *tb[FTA_TUPLE_MAX+1];
++ int err;
++
++ memset(tuple, 0, sizeof(*tuple));
++
++ err = nla_parse_nested_deprecated(tb, FTA_TUPLE_MAX, cda[attrtype], tuple_nla_policy, NULL);
++ if (err < 0)
++ return err;
++
++ if (!tb[FTA_TUPLE_IP])
++ return -EINVAL;
++
++ /* parse IP */
++ tuple->l3proto = l3proto;
++ err = ftnetlink_parse_tuple_ip(tb[FTA_TUPLE_IP], tuple);
++ if (err < 0)
++ return err;
++
++ /* parse proto */
++ if (!tb[FTA_TUPLE_PROTO])
++ return -EINVAL;
++ err = ftnetlink_parse_tuple_proto(tb[FTA_TUPLE_PROTO], tuple);
++
++ if (err >= 0)
++ printk("tuple info:sip=%pI4,dip=%pI4 proto=%d "
++ "sport=%d dport=%d\n",
++ &tuple->src_v4, &tuple->dst_v4, tuple->l4proto,
++ ntohs(tuple->src_port), ntohs(tuple->dst_port));
++
++ return err;
++}
++
++static int ftnetlink_del_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
++ const struct nlmsghdr *nlh,
++ const struct nlattr * const cda[],
++ struct netlink_ext_ack *extack)
++{
++ struct net_device *dev = skb->dev;
++ struct flow_offload_tuple tuple;
++ int err = -1;
++ struct nfgenmsg *nfmsg = nlmsg_data(nlh);
++ u_int8_t u3 = nfmsg->nfgen_family;
++
++ /* parse tuple */
++ if(!cda[FTA_TUPLE])
++ return -EINVAL;
++
++ err = ftnetlink_parse_tuple(cda, &tuple, FTA_TUPLE, u3);
++ if (err < 0)
++ return err;
++
++ /* teardown the flow */
++ flow_offload_teardown_by_tuple(&tuple);
++
++ return 0;
++}
++
++static int ftnetlink_add_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
++ const struct nlmsghdr *nlh,
++ const struct nlattr * const cda[],
++ struct netlink_ext_ack *extack)
++{
++ return 0;
++}
++
++static int ftnetlink_flush_table(struct net *net, struct sock *ftnl, struct sk_buff *skb,
++ const struct nlmsghdr *nlh,
++ const struct nlattr * const cda[],
++ struct netlink_ext_ack *extack)
++{
++ struct net_device *dev = skb->dev;
++
++ nf_flow_table_cleanup(dev);
++
++ return 0;
++}
++
++static const struct nla_policy ft_nla_policy[FTA_MAX + 1] = {
++ [FTA_TUPLE] = { .type = NLA_NESTED },
++};
++
++static const struct nfnl_callback flow_table_cb[FT_MSG_MAX] = {
++ [FT_MSG_DEL] = {
++ .call = ftnetlink_del_nf_flow,
++ .attr_count = FTA_MAX,
++ .policy = ft_nla_policy
++ },
++ [FT_MSG_ADD] = {
++ .call = ftnetlink_add_nf_flow,
++ .attr_count = FTA_MAX,
++ .policy = ft_nla_policy
++ },
++ [FT_MSG_FLUSH] = {
++ .call = ftnetlink_flush_table,
++ .attr_count = FTA_MAX,
++ .policy = ft_nla_policy
++ },
++};
++
++static const struct nfnetlink_subsystem ftnl_subsys = {
++ .name = "flowtable",
++ .subsys_id = NFNL_SUBSYS_FLOWTABLE,
++ .cb_count = FT_MSG_MAX,
++ .cb = flow_table_cb,
++};
++
++static int __init ftnetlink_init(void)
++{
++ int ret;
++
++ ret = nfnetlink_subsys_register(&ftnl_subsys);
++
++ return ret;
++}
++
++static void ftnetlink_exit(void)
++{
++ nfnetlink_subsys_unregister(&ftnl_subsys);
++}
++
++MODULE_LICENSE("GPL");
++module_init(ftnetlink_init);
++module_exit(ftnetlink_exit);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
index 7ff8795..2675268 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -3,11 +3,11 @@
# CONFIG_AIROHA_EN8801SC_PHY is not set
# CONFIG_AIROHA_EN8811H_PHY is not set
CONFIG_AQUANTIA_PHY=y
-# CONFIG_AQUANTIA_PHY_MDI_SWAP is not set
CONFIG_AQUANTIA_PHY_FW_DOWNLOAD=y
CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_GANG=y
# CONFIG_AQUANTIA_PHY_FW_DOWNLOAD_SINGLE is not set
CONFIG_AQUANTIA_PHY_FW_FILE="Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
+# CONFIG_AQUANTIA_PHY_MDI_SWAP is not set
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
@@ -56,6 +56,7 @@
CONFIG_ARM_MEDIATEK_CPUFREQ=y
CONFIG_ARM_PMU=y
CONFIG_ARM_PSCI_FW=y
+# CONFIG_ASN1 is not set
CONFIG_ATA=y
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
CONFIG_BLK_DEV_DM=y
@@ -118,7 +119,6 @@
# CONFIG_CPUFREQ_DT is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
@@ -179,6 +179,7 @@
CONFIG_DM_VERITY=y
# CONFIG_DM_VERITY_FEC is not set
# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
+CONFIG_DPS310=y
CONFIG_DRM_RCAR_WRITEBACK=y
CONFIG_DTC=y
CONFIG_DYNAMIC_DEBUG=y
@@ -203,6 +204,7 @@
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
@@ -238,6 +240,7 @@
CONFIG_HZ_250=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MT65XX=y
CONFIG_ICPLUS_PHY=y
CONFIG_IIO=y
@@ -289,7 +292,6 @@
CONFIG_MTD_NAND_MTK=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPI_NAND=y
-# CONFIG_MTD_SPI_NAND_W25N01KV is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIT_FW=y
@@ -305,9 +307,9 @@
CONFIG_MTK_INFRACFG=y
CONFIG_MTK_PMIC_WRAP=y
CONFIG_MTK_SCPSYS=y
+CONFIG_MTK_SOC_THERMAL_LVTS=y
CONFIG_MTK_SPI_NAND=y
# CONFIG_MTK_THERMAL is not set
-CONFIG_MTK_SOC_THERMAL_LVTS=y
CONFIG_MTK_TIMER=y
# CONFIG_MTK_UART_APDMA is not set
CONFIG_MUTEX_SPIN_ON_OWNER=y
@@ -360,12 +362,8 @@
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PHYS_ADDR_T_64BIT=y
-# CONFIG_PHY_MTK_A60810 is not set
-# CONFIG_PHY_MTK_A60931 is not set
-# CONFIG_PHY_MTK_A60XXX is not set
CONFIG_PHY_MTK_TPHY=y
# CONFIG_PHY_MTK_UFS is not set
-# CONFIG_PHY_MTK_USB3_I2C_FPGA is not set
CONFIG_PHY_MTK_XSPHY=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_MT2712 is not set
@@ -506,5 +504,3 @@
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA32=y
-# CONFIG_BPF_KPROBE_OVERRIDE is not set
-# CONFIG_HIST_TRIGGERS is not set