Merge f3f68f9615 on remote branch

Change-Id: Ic162f491a5bce4793b25a54cf56256963c819495
This commit is contained in:
Linux Build Service Account 2022-02-11 01:25:58 -08:00
commit ea45b4c722
67 changed files with 2283 additions and 217 deletions

View file

@ -1 +1 @@
LTS_5.4.147_983a7e7c981b
LTS_5.4.147_f2bbf1b7baa5

View file

@ -810,9 +810,7 @@ CONFIG_SND_DYNAMIC_MINORS=y
# CONFIG_SND_AUDIO_GRAPH_CARD is not set
# CONFIG_HID_PRODIKEYS is not set
# CONFIG_USB_CONFIGFS_F_AUDIO_SRC is not set
# CONFIG_USB_CONFIGFS_F_UAC1 is not set
# CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set
# CONFIG_USB_CONFIGFS_F_UAC2 is not set
# CONFIG_USB_CONFIGFS_F_MIDI is not set
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_MFD_SPMI_PMIC=y

View file

@ -850,12 +850,12 @@ CONFIG_SND_DYNAMIC_MINORS=y
# CONFIG_SND_AUDIO_GRAPH_CARD is not set
# CONFIG_HID_PRODIKEYS is not set
# CONFIG_USB_CONFIGFS_F_AUDIO_SRC is not set
# CONFIG_USB_CONFIGFS_F_UAC1 is not set
# CONFIG_USB_CONFIGFS_F_UAC1_LEGACY is not set
# CONFIG_USB_CONFIGFS_F_UAC2 is not set
# CONFIG_USB_CONFIGFS_F_MIDI is not set
# CONFIG_MEDIA_SUPPORT is not set
# CONFIG_SND_SOC_TLV320AIC3X is not set
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_UAC2=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
# CONFIG_QCOM_COINCELL is not set

View file

@ -425,7 +425,7 @@ static acpi_status find_mboard_resource(acpi_handle handle, u32 lvl,
return AE_OK;
}
static bool is_acpi_reserved(u64 start, u64 end, unsigned not_used)
static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used)
{
struct resource mcfg_res;
@ -442,7 +442,7 @@ static bool is_acpi_reserved(u64 start, u64 end, unsigned not_used)
return mcfg_res.flags;
}
typedef bool (*check_reserved_t)(u64 start, u64 end, unsigned type);
typedef bool (*check_reserved_t)(u64 start, u64 end, enum e820_type type);
static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
struct pci_mmcfg_region *cfg,

View file

@ -42,7 +42,7 @@ static ssize_t active_time_ms_show(struct device *dev,
ktime_t active_time =
ws->active ? ktime_sub(ktime_get(), ws->last_time) : 0;
return sprintf(buf, "%lld\n", ktime_to_ms(active_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(active_time));
}
static DEVICE_ATTR_RO(active_time_ms);
@ -57,7 +57,7 @@ static ssize_t total_time_ms_show(struct device *dev,
active_time = ktime_sub(ktime_get(), ws->last_time);
total_time = ktime_add(total_time, active_time);
}
return sprintf(buf, "%lld\n", ktime_to_ms(total_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(total_time));
}
static DEVICE_ATTR_RO(total_time_ms);
@ -73,7 +73,7 @@ static ssize_t max_time_ms_show(struct device *dev,
if (active_time > max_time)
max_time = active_time;
}
return sprintf(buf, "%lld\n", ktime_to_ms(max_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(max_time));
}
static DEVICE_ATTR_RO(max_time_ms);
@ -82,7 +82,7 @@ static ssize_t last_change_ms_show(struct device *dev,
{
struct wakeup_source *ws = dev_get_drvdata(dev);
return sprintf(buf, "%lld\n", ktime_to_ms(ws->last_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(ws->last_time));
}
static DEVICE_ATTR_RO(last_change_ms);
@ -91,7 +91,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
{
struct wakeup_source *ws = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", ws->name);
return sysfs_emit(buf, "%s\n", ws->name);
}
static DEVICE_ATTR_RO(name);
@ -106,7 +106,7 @@ static ssize_t prevent_suspend_time_ms_show(struct device *dev,
prevent_sleep_time = ktime_add(prevent_sleep_time,
ktime_sub(ktime_get(), ws->start_prevent_time));
}
return sprintf(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
return sysfs_emit(buf, "%lld\n", ktime_to_ms(prevent_sleep_time));
}
static DEVICE_ATTR_RO(prevent_suspend_time_ms);

View file

@ -143,6 +143,17 @@ bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie)
{
int ret;
u32 val;
int i;
bool result = false;
struct {
char *name;
u32 offset;
} error_reg[] = {
{ "ERROR_DBG1", BHI_ERRDBG1 },
{ "ERROR_DBG2", BHI_ERRDBG2 },
{ "ERROR_DBG3", BHI_ERRDBG3 },
{ NULL },
};
if (!mhi_cntrl->rddm_supported || !cookie)
return false;
@ -152,15 +163,23 @@ bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie)
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
return false;
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_ERRDBG2, &val);
if (ret)
return false;
/* look for an RDDM cookie match in any of the error debug registers */
for (i = 0; error_reg[i].name; i++) {
ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi,
error_reg[i].offset, &val);
if (ret)
break;
MHI_CNTRL_LOG("reg:%s value:0x%x\n", error_reg[i].name, val);
MHI_CNTRL_LOG("BHI_ERRDBG2 value:0x%x\n", val);
if (val == cookie)
return true;
if (!(val ^ cookie)) {
MHI_CNTRL_ERR("RDDM cookie found in %s\n",
error_reg[i].name);
return true;
}
}
return false;
MHI_CNTRL_ERR("RDDM cookie not found\n");
return result;
}
EXPORT_SYMBOL(mhi_scan_rddm_cookie);

View file

@ -5350,6 +5350,7 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer,
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%s%s%s%s%s\n", single_line, single_line,
single_line, single_line, single_line);
spin_lock(&me->hlock);
hlist_for_each_entry_safe(gmaps, n, &me->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20d|0x%-18llX|0x%-18X|0x%-20lX\n\n",
@ -5357,18 +5358,21 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer,
(uint32_t)gmaps->size,
gmaps->va);
}
spin_unlock(&me->hlock);
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20s|%-20s|%-20s|%-20s\n",
"len", "refs", "raddr", "flags");
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%s%s%s%s%s\n", single_line, single_line,
single_line, single_line, single_line);
spin_lock(&me->hlock);
hlist_for_each_entry_safe(gmaps, n, &me->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"0x%-18X|%-20d|%-20lu|%-20u\n",
(uint32_t)gmaps->len, gmaps->refs,
gmaps->raddr, gmaps->flags);
}
spin_unlock(&me->hlock);
} else {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"\n%s %13s %d\n", "cid", ":", fl->cid);
@ -5410,12 +5414,14 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer,
"%s%s%s%s%s\n",
single_line, single_line, single_line,
single_line, single_line);
mutex_lock(&fl->map_mutex);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"0x%-20lX|0x%-20llX|0x%-20zu\n\n",
map->va, map->phys,
map->size);
}
mutex_unlock(&fl->map_mutex);
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20s|%-20s|%-20s|%-20s\n",
"len", "refs",
@ -5424,24 +5430,27 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer,
"%s%s%s%s%s\n",
single_line, single_line, single_line,
single_line, single_line);
mutex_lock(&fl->map_mutex);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20zu|%-20d|0x%-20lX|%-20d\n\n",
map->len, map->refs, map->raddr,
map->uncached);
}
mutex_unlock(&fl->map_mutex);
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20s|%-20s\n", "secure", "attr");
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%s%s%s%s%s\n",
single_line, single_line, single_line,
single_line, single_line);
mutex_lock(&fl->map_mutex);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"%-20d|0x%-20lX\n\n",
map->secure, map->attr);
}
mutex_unlock(&fl->map_mutex);
len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len,
"\n======%s %s %s======\n", title,
" LIST OF BUFS ", title);

View file

@ -776,7 +776,7 @@ static int cpu_power_select(struct cpuidle_device *dev,
}
done_select:
trace_cpu_power_select(best_level, sleep_us, latency_us, 0);
trace_cpu_power_select(best_level, sleep_us, latency_us, cpu->bias);
trace_cpu_pred_select(idx_restrict_time ? 2 : (ipi_predicted ?
3 : (predicted ? 1 : 0)), predicted, htime);

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/component.h>
#include <linux/delay.h>
@ -3131,12 +3132,14 @@ int adreno_gmu_fenced_write(struct adreno_device *adreno_dev,
unsigned int status, i;
const struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
unsigned int reg_offset = gpudev->reg_offsets[offset];
u64 ts1, ts2;
adreno_writereg(adreno_dev, offset, val);
if (!gmu_core_isenabled(KGSL_DEVICE(adreno_dev)))
return 0;
ts1 = gpudev->read_alwayson(adreno_dev);
for (i = 0; i < GMU_CORE_LONG_WAKEUP_RETRY_LIMIT; i++) {
/*
* Make sure the previous register write is posted before
@ -3165,10 +3168,10 @@ int adreno_gmu_fenced_write(struct adreno_device *adreno_dev,
return 0;
if (i == GMU_CORE_LONG_WAKEUP_RETRY_LIMIT) {
ts2 = gpudev->read_alwayson(adreno_dev);
dev_err(adreno_dev->dev.dev,
"Timed out waiting %d usecs to write fenced register 0x%x\n",
i * GMU_CORE_WAKEUP_DELAY_US,
reg_offset);
"Timed out waiting %d usecs to write fenced register 0x%x, timestamps: %llx %llx\n",
i * GMU_CORE_WAKEUP_DELAY_US, reg_offset, ts1, ts2);
return -ETIMEDOUT;
}

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <uapi/linux/msm_ion.h>
@ -2517,6 +2518,15 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, unsigned long useraddr)
ret = sg_alloc_table_from_pages(memdesc->sgt, pages, npages,
0, memdesc->size, GFP_KERNEL);
if (ret)
goto out;
ret = kgsl_cache_range_op(memdesc, 0, memdesc->size,
KGSL_CACHE_OP_FLUSH);
if (ret)
sg_free_table(memdesc->sgt);
out:
if (ret) {
for (i = 0; i < npages; i++)

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/atomic.h>
@ -890,7 +891,12 @@ static int haptics_get_status_data(struct haptics_chip *chip,
mod_sel_val[0] = sel & 0xff;
mod_sel_val[1] = (sel >> 8) & 0xff;
rc = haptics_write(chip, chip->cfg_addr_base,
HAP_CFG_MOD_STATUS_SEL_REG, mod_sel_val, 2);
HAP_CFG_MOD_STATUS_XT_V2_REG, &mod_sel_val[1], 1);
if (rc < 0)
return rc;
rc = haptics_write(chip, chip->cfg_addr_base,
HAP_CFG_MOD_STATUS_SEL_REG, mod_sel_val, 1);
if (rc < 0)
return rc;
@ -1919,10 +1925,17 @@ static int haptics_toggle_module_enable(struct haptics_chip *chip)
{
int rc;
/*
* Updating HAPTICS_EN would vote hBoost enable status. Add 100us
* delay before updating HAPTICS_EN for hBoost to have enough time
* to handle its power transition.
*/
usleep_range(100, 101);
rc = haptics_module_enable(chip, false);
if (rc < 0)
return rc;
usleep_range(100, 101);
return haptics_module_enable(chip, true);
}
@ -2064,22 +2077,11 @@ static int haptics_load_predefined_effect(struct haptics_chip *chip,
return -EINVAL;
play->effect = effect;
if (play->pattern_src == FIFO) {
/* Toggle HAPTICS_EN for a clear start point of FIFO playing */
rc = haptics_toggle_module_enable(chip);
if (rc < 0)
return rc;
}
/* Clamp VMAX for different vibration strength */
rc = haptics_set_vmax_mv(chip, play->vmax_mv);
if (rc < 0)
return rc;
rc = haptics_enable_autores(chip, !play->effect->auto_res_disable);
if (rc < 0)
return rc;
play->pattern_src = play->effect->src;
if (play->pattern_src != PATTERN1 &&
play->pattern_src != PATTERN2 &&
@ -2089,6 +2091,17 @@ static int haptics_load_predefined_effect(struct haptics_chip *chip,
return -EINVAL;
}
if (play->pattern_src == FIFO) {
/* Toggle HAPTICS_EN for a clear start point of FIFO playing */
rc = haptics_toggle_module_enable(chip);
if (rc < 0)
return rc;
}
rc = haptics_enable_autores(chip, !play->effect->auto_res_disable);
if (rc < 0)
return rc;
play->brake = play->effect->brake;
/* Config brake settings if it's necessary */
if (play->brake) {
@ -2252,12 +2265,12 @@ static int haptics_load_custom_effect(struct haptics_chip *chip,
play->effect = chip->custom_effect;
play->brake = NULL;
play->vmax_mv = (magnitude * chip->custom_effect->vmax_mv) / 0x7fff;
/* Toggle HAPTICS_EN for a clear start point of FIFO playing */
rc = haptics_toggle_module_enable(chip);
rc = haptics_set_vmax_mv(chip, play->vmax_mv);
if (rc < 0)
goto cleanup;
rc = haptics_set_vmax_mv(chip, play->vmax_mv);
/* Toggle HAPTICS_EN for a clear start point of FIFO playing */
rc = haptics_toggle_module_enable(chip);
if (rc < 0)
goto cleanup;
@ -2374,6 +2387,46 @@ static u8 get_direct_play_max_amplitude(struct haptics_chip *chip)
return (u8)amplitude;
}
static int haptics_stop_fifo_play(struct haptics_chip *chip)
{
int rc;
u8 val;
if (atomic_read(&chip->play.fifo_status.is_busy) == 0) {
dev_dbg(chip->dev, "FIFO playing is not in progress\n");
return 0;
}
rc = haptics_enable_play(chip, false);
if (rc < 0)
return rc;
/* restore FIFO play rate back to T_LRA */
rc = haptics_set_fifo_playrate(chip, T_LRA);
if (rc < 0)
return rc;
haptics_fifo_empty_irq_config(chip, false);
kvfree(chip->custom_effect->fifo->samples);
chip->custom_effect->fifo->samples = NULL;
atomic_set(&chip->play.fifo_status.is_busy, 0);
/*
* All other playing modes would use AUTO mode RC
* calibration except FIFO streaming mode, so restore
* back to AUTO RC calibration after FIFO playing.
*/
val = CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT;
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val);
if (rc < 0)
return rc;
dev_dbg(chip->dev, "stopped FIFO playing successfully\n");
return 0;
}
static int haptics_upload_effect(struct input_dev *dev,
struct ff_effect *effect, struct ff_effect *old)
{
@ -2443,46 +2496,21 @@ static int haptics_upload_effect(struct input_dev *dev,
return rc;
}
return haptics_wait_hboost_ready(chip);
}
static int haptics_stop_fifo_play(struct haptics_chip *chip)
{
int rc;
u8 val;
if (atomic_read(&chip->play.fifo_status.is_busy) == 0) {
dev_dbg(chip->dev, "FIFO playing is not in progress\n");
return 0;
rc = haptics_wait_hboost_ready(chip);
if (rc < 0 && chip->play.pattern_src == FIFO) {
/*
* Call haptics_stop_fifo_play(chip) explicitly if hBoost is
* not ready for the FIFO play. This drops current FIFO play
* but it restores the SW back to initial status so that the
* following FIFO play requests can still be served.
*/
dev_dbg(chip->dev, "stop FIFO play explicitly to restore SW status\n");
mutex_lock(&chip->play.lock);
haptics_stop_fifo_play(chip);
mutex_unlock(&chip->play.lock);
return rc;
}
rc = haptics_enable_play(chip, false);
if (rc < 0)
return rc;
/* restore FIFO play rate back to T_LRA */
rc = haptics_set_fifo_playrate(chip, T_LRA);
if (rc < 0)
return rc;
haptics_fifo_empty_irq_config(chip, false);
kvfree(chip->custom_effect->fifo->samples);
chip->custom_effect->fifo->samples = NULL;
atomic_set(&chip->play.fifo_status.is_busy, 0);
/*
* All other playing modes would use AUTO mode RC
* calibration except FIFO streaming mode, so restore
* back to AUTO RC calibration after FIFO playing.
*/
val = CAL_RC_CLK_AUTO_VAL << CAL_RC_CLK_SHIFT;
rc = haptics_masked_write(chip, chip->cfg_addr_base,
HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val);
if (rc < 0)
return rc;
dev_dbg(chip->dev, "stopped FIFO playing successfully\n");
return 0;
}

View file

@ -821,9 +821,22 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
int err = 0;
struct ubi_ainf_peb *aeb, *tmp_aeb;
if (!list_empty(&ai->free)) {
aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list);
list_for_each_entry_safe(aeb, tmp_aeb, &ai->free, u.list) {
list_del(&aeb->u.list);
if (aeb->ec == UBI_UNKNOWN) {
ubi_err(ubi, "PEB %d in freelist has unknown EC",
aeb->pnum);
aeb->ec = ai->mean_ec;
}
err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1);
if (err) {
ubi_err(ubi, "Erase failed for PEB %d in freelist",
aeb->pnum);
list_add(&aeb->u.list, &ai->erase);
continue;
}
aeb->ec += 1;
dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec);
return aeb;
}

View file

@ -121,7 +121,7 @@ static int __init ubiblock_set_param(const char *val,
return -EINVAL;
}
strcpy(buf, val);
strlcpy(buf, val, sizeof(buf));
/* Get rid of the final newline */
if (buf[len - 1] == '\n')
@ -141,12 +141,12 @@ static int __init ubiblock_set_param(const char *val,
ret = kstrtoint(tokens[1], 10, &param->vol_id);
if (ret < 0) {
param->vol_id = -1;
strcpy(param->name, tokens[1]);
strlcpy(param->name, tokens[1], UBIBLOCK_PARAM_LEN+1);
}
} else {
/* One parameter: must be device path */
strcpy(param->name, tokens[0]);
strlcpy(param->name, tokens[0], UBIBLOCK_PARAM_LEN+1);
param->ubi_num = -1;
param->vol_id = -1;
}
@ -412,7 +412,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
goto out_put_disk;
}
gd->private_data = dev;
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
scnprintf(gd->disk_name, DISK_NAME_LEN, "ubiblock%d_%d",
dev->ubi_num, dev->vol_id);
set_capacity(gd, disk_capacity);
dev->gd = gd;

View file

@ -95,7 +95,7 @@ static DEFINE_SPINLOCK(ubi_devices_lock);
static ssize_t version_show(struct class *class, struct class_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", UBI_VERSION);
return scnprintf(buf, sizeof(int), "%d\n", UBI_VERSION);
}
static CLASS_ATTR_RO(version);
@ -114,6 +114,9 @@ struct class ubi_class = {
static ssize_t dev_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t dev_attribute_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */
static struct device_attribute dev_eraseblock_size =
@ -140,6 +143,13 @@ static struct device_attribute dev_mtd_num =
__ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
static struct device_attribute dev_ro_mode =
__ATTR(ro_mode, S_IRUGO, dev_attribute_show, NULL);
static struct device_attribute dev_mtd_trigger_scrub =
__ATTR(scrub_all, 0644,
dev_attribute_show, dev_attribute_store);
static struct device_attribute dev_mtd_max_scrub_sqnum =
__ATTR(scrub_max_sqnum, 0444, dev_attribute_show, NULL);
static struct device_attribute dev_mtd_min_scrub_sqnum =
__ATTR(scrub_min_sqnum, 0444, dev_attribute_show, NULL);
/**
* ubi_volume_notify - send a volume change notification.
@ -332,6 +342,17 @@ int ubi_major2num(int major)
return ubi_num;
}
static unsigned long long get_max_sqnum(struct ubi_device *ubi)
{
unsigned long long max_sqnum;
spin_lock(&ubi->ltree_lock);
max_sqnum = ubi->global_sqnum - 1;
spin_unlock(&ubi->ltree_lock);
return max_sqnum;
}
/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
static ssize_t dev_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf)
@ -355,29 +376,50 @@ static ssize_t dev_attribute_show(struct device *dev,
return -ENODEV;
if (attr == &dev_eraseblock_size)
ret = sprintf(buf, "%d\n", ubi->leb_size);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->leb_size);
else if (attr == &dev_avail_eraseblocks)
ret = sprintf(buf, "%d\n", ubi->avail_pebs);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->avail_pebs);
else if (attr == &dev_total_eraseblocks)
ret = sprintf(buf, "%d\n", ubi->good_peb_count);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->good_peb_count);
else if (attr == &dev_volumes_count)
ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->vol_count - UBI_INT_VOL_COUNT);
else if (attr == &dev_max_ec)
ret = sprintf(buf, "%d\n", ubi->max_ec);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->max_ec);
else if (attr == &dev_reserved_for_bad)
ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->beb_rsvd_pebs);
else if (attr == &dev_bad_peb_count)
ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->bad_peb_count);
else if (attr == &dev_max_vol_count)
ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->vtbl_slots);
else if (attr == &dev_min_io_size)
ret = sprintf(buf, "%d\n", ubi->min_io_size);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->min_io_size);
else if (attr == &dev_bgt_enabled)
ret = sprintf(buf, "%d\n", ubi->thread_enabled);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->thread_enabled);
else if (attr == &dev_mtd_num)
ret = sprintf(buf, "%d\n", ubi->mtd->index);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->mtd->index);
else if (attr == &dev_ro_mode)
ret = sprintf(buf, "%d\n", ubi->ro_mode);
ret = scnprintf(buf, sizeof(int), "%d\n",
ubi->ro_mode);
else if (attr == &dev_mtd_trigger_scrub)
ret = scnprintf(buf, sizeof(int), "%d\n",
atomic_read(&ubi->scrub_work_count));
else if (attr == &dev_mtd_max_scrub_sqnum)
ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n",
get_max_sqnum(ubi));
else if (attr == &dev_mtd_min_scrub_sqnum)
ret = scnprintf(buf, sizeof(unsigned long long), "%llu\n",
ubi_wl_scrub_get_min_sqnum(ubi));
else
ret = -EINVAL;
@ -398,10 +440,46 @@ static struct attribute *ubi_dev_attrs[] = {
&dev_bgt_enabled.attr,
&dev_mtd_num.attr,
&dev_ro_mode.attr,
&dev_mtd_trigger_scrub.attr,
&dev_mtd_max_scrub_sqnum.attr,
&dev_mtd_min_scrub_sqnum.attr,
NULL
};
ATTRIBUTE_GROUPS(ubi_dev);
static ssize_t dev_attribute_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
struct ubi_device *ubi;
unsigned long long scrub_sqnum;
ubi = container_of(dev, struct ubi_device, dev);
ubi = ubi_get_device(ubi->ubi_num);
if (!ubi)
return -ENODEV;
if (attr == &dev_mtd_trigger_scrub) {
if (kstrtoull(buf, 10, &scrub_sqnum)) {
ret = -EINVAL;
goto out;
}
if (!ubi->lookuptbl) {
pr_err("lookuptbl is null\n");
ret = -ENOENT;
goto out;
}
ret = ubi_wl_scrub_all(ubi, scrub_sqnum);
if (ret == 0)
ret = count;
}
out:
ubi_put_device(ubi);
return ret;
}
static void dev_release(struct device *dev)
{
struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);
@ -438,7 +516,8 @@ static int uif_init(struct ubi_device *ubi)
int i, err;
dev_t dev;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
scnprintf(ubi->ubi_name, sizeof(UBI_NAME_STR) + 5,
UBI_NAME_STR "%d", ubi->ubi_num);
/*
* Major numbers for the UBI character devices are allocated
@ -1376,7 +1455,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
return 0;
}
strcpy(buf, val);
strlcpy(buf, val, sizeof(buf));
/* Get rid of the final newline */
if (buf[len - 1] == '\n')
@ -1391,7 +1470,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp)
}
p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]);
strlcpy(&p->name[0], tokens[0], MTD_PARAM_LEN_MAX);
token = tokens[1];
if (token) {

View file

@ -1056,6 +1056,15 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
dbg_io("write VID header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
/*
* Re-erase the PEB before using it. This should minimize any issues
* from decay of charge in this block.
*/
if (ubi->wl_is_inited) {
err = ubi_wl_re_erase_peb(ubi, pnum);
if (err)
return err;
}
err = self_check_peb_ec_hdr(ubi, pnum);
if (err)
return err;
@ -1074,6 +1083,8 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
ubi->vid_hdr_alsize);
if (!err && ubi->wl_is_inited)
ubi_wl_update_peb_sqnum(ubi, pnum, vid_hdr);
return err;
}

View file

@ -170,6 +170,8 @@ struct ubi_vid_io_buf {
* @u.list: link in the protection queue
* @ec: erase counter
* @pnum: physical eraseblock number
* @tagged_scrub_all: if the entry is tagged for scrub all
* @sqnum: The sequence number of the vol header.
*
* This data structure is used in the WL sub-system. Each physical eraseblock
* has a corresponding &struct wl_entry object which may be kept in different
@ -182,6 +184,8 @@ struct ubi_wl_entry {
} u;
int ec;
int pnum;
unsigned int tagged_scrub_all:1;
unsigned long long sqnum;
};
/**
@ -625,6 +629,9 @@ struct ubi_device {
struct task_struct *bgt_thread;
int thread_enabled;
char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
bool scrub_in_progress;
atomic_t scrub_work_count;
int wl_is_inited;
/* I/O sub-system's stuff */
long long flash_size;
@ -919,7 +926,12 @@ int ubi_is_erase_work(struct ubi_work *wrk);
void ubi_refill_pools(struct ubi_device *ubi);
int ubi_ensure_anchor_pebs(struct ubi_device *ubi);
int ubi_bitflip_check(struct ubi_device *ubi, int pnum, int force_scrub);
ssize_t ubi_wl_scrub_all(struct ubi_device *ubi,
unsigned long long scrub_sqnum);
void ubi_wl_update_peb_sqnum(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr);
unsigned long long ubi_wl_scrub_get_min_sqnum(struct ubi_device *ubi);
int ubi_wl_re_erase_peb(struct ubi_device *ubi, int pnum);
/* io.c */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len);

View file

@ -54,7 +54,7 @@ static struct device_attribute attr_vol_upd_marker =
static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
int ret, size;
struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
struct ubi_device *ubi;
@ -73,27 +73,36 @@ static ssize_t vol_attribute_show(struct device *dev,
spin_unlock(&ubi->volumes_lock);
if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs);
ret = scnprintf(buf, sizeof(int), "%d\n", vol->reserved_pebs);
else if (attr == &attr_vol_type) {
const char *tp;
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
tp = "dynamic";
else
size = 8;
} else {
tp = "static";
ret = sprintf(buf, "%s\n", tp);
size = 7;
}
ret = scnprintf(buf, size, "%s\n", tp);
} else if (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name);
ret = scnprintf(buf, vol->name_len + 1, "%s\n",
vol->name);
else if (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted);
ret = scnprintf(buf, sizeof(int), "%d\n",
vol->corrupted);
else if (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment);
ret = scnprintf(buf, sizeof(int), "%d\n",
vol->alignment);
else if (attr == &attr_vol_usable_eb_size)
ret = sprintf(buf, "%d\n", vol->usable_leb_size);
ret = scnprintf(buf, sizeof(int), "%d\n",
vol->usable_leb_size);
else if (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes);
ret = scnprintf(buf, sizeof(unsigned long long), "%lld\n",
vol->used_bytes);
else if (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker);
ret = scnprintf(buf, sizeof(int), "%d\n",
vol->upd_marker);
else
/* This must be a bug */
ret = -EINVAL;

View file

@ -89,6 +89,7 @@
#include <linux/crc32.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include "ubi.h"
#include "wl.h"
@ -488,6 +489,42 @@ out_free:
return err;
}
int ubi_wl_re_erase_peb(struct ubi_device *ubi, int pnum)
{
int err;
struct ubi_wl_entry *e;
struct ubi_ec_hdr *ec_hdr;
spin_lock(&ubi->wl_lock);
e = ubi->lookuptbl[pnum];
spin_unlock(&ubi->wl_lock);
dbg_wl("Re-erase PEB %d, EC %u", e->pnum, e->ec);
err = self_check_ec(ubi, e->pnum, e->ec);
if (err)
return -EINVAL;
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
err = ubi_io_sync_erase(ubi, e->pnum, 0);
if (err < 0)
goto out_free;
dbg_wl("re-erased PEB %d, EC %u", e->pnum, e->ec);
ec_hdr->ec = cpu_to_be64(e->ec);
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (err)
goto out_free;
out_free:
kfree(ec_hdr);
return err;
}
/**
* serve_prot_queue - check if it is time to stop protecting PEBs.
* @ubi: UBI device description object
@ -863,9 +900,19 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
}
/* The PEB has been successfully moved */
if (scrubbing)
ubi_msg(ubi, "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d",
e1->pnum, vol_id, lnum, e2->pnum);
if (scrubbing) {
spin_lock(&ubi->wl_lock);
if (e1->tagged_scrub_all) {
WARN_ON(atomic_read(&ubi->scrub_work_count) <= 0);
atomic_dec(&ubi->scrub_work_count);
e1->tagged_scrub_all = 0;
e2->tagged_scrub_all = 0;
} else {
ubi_msg(ubi, "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d",
e1->pnum, vol_id, lnum, e2->pnum);
}
spin_unlock(&ubi->wl_lock);
}
ubi_free_vid_buf(vidb);
spin_lock(&ubi->wl_lock);
@ -1233,6 +1280,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
retry:
spin_lock(&ubi->wl_lock);
e = ubi->lookuptbl[pnum];
e->sqnum = UBI_UNKNOWN;
if (e == ubi->move_from) {
/*
* User is putting the physical eraseblock which was selected to
@ -1269,6 +1317,20 @@ retry:
} else if (in_wl_tree(e, &ubi->scrub)) {
self_check_in_wl_tree(ubi, e, &ubi->scrub);
rb_erase(&e->u.rb, &ubi->scrub);
/*
* Since this PEB has been put we dont need to worry
* about it anymore
*/
if (e->tagged_scrub_all) {
int wrk_count;
wrk_count = atomic_read(&ubi->scrub_work_count);
WARN_ON(wrk_count <= 0);
atomic_dec(&ubi->scrub_work_count);
e->tagged_scrub_all = 0;
}
} else if (in_wl_tree(e, &ubi->erroneous)) {
self_check_in_wl_tree(ubi, e, &ubi->erroneous);
rb_erase(&e->u.rb, &ubi->erroneous);
@ -1300,6 +1362,197 @@ retry:
return err;
}
/**
* ubi_wl_scrub_get_min_sqnum - Return the minimum sqnum of the used/pq/scrub.
* @ubi: UBI device description object
*
* This function returns the minimum sqnum of the PEB that are currently in use.
*
* Return the min sqnum if there are any used PEB's otherwise return ~(0)
*
*/
unsigned long long ubi_wl_scrub_get_min_sqnum(struct ubi_device *ubi)
{
int i;
struct ubi_wl_entry *e, *tmp;
struct rb_node *node;
unsigned long long min_sqnum = ~0;
spin_lock(&ubi->wl_lock);
/* Go through the pq list */
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) {
list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) {
if (e->sqnum < min_sqnum)
min_sqnum = e->sqnum;
}
}
/* Go through used PEB tree */
for (node = rb_first(&ubi->used); node; node = rb_next(node)) {
e = rb_entry(node, struct ubi_wl_entry, u.rb);
self_check_in_wl_tree(ubi, e, &ubi->used);
if (e->sqnum < min_sqnum)
min_sqnum = e->sqnum;
}
/* Go through scrub PEB tree */
for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
e = rb_entry(node, struct ubi_wl_entry, u.rb);
self_check_in_wl_tree(ubi, e, &ubi->scrub);
if (e->sqnum < min_sqnum)
min_sqnum = e->sqnum;
}
spin_unlock(&ubi->wl_lock);
return min_sqnum;
}
/**
* ubi_wl_update_peb_sqnum - Update the vol hdr sqnum of the PEB.
* @pnum: The PEB number.
* @vid_hdr: The vol hdr being written to the PEB.
*
*/
void ubi_wl_update_peb_sqnum(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr)
{
struct ubi_wl_entry *e;
spin_lock(&ubi->wl_lock);
e = ubi->lookuptbl[pnum];
e->sqnum = be64_to_cpu(vid_hdr->sqnum);
e->tagged_scrub_all = 0;
spin_unlock(&ubi->wl_lock);
}
static int is_ubi_readonly(struct ubi_device *ubi)
{
int is_readonly = 0;
spin_lock(&ubi->wl_lock);
if (ubi->ro_mode || !ubi->thread_enabled ||
ubi_dbg_is_bgt_disabled(ubi))
is_readonly = 1;
spin_unlock(&ubi->wl_lock);
return is_readonly;
}
/**
* ubi_wl_scan_all - Scan all PEB's
* @ubi: UBI device description object
* @scrub_sqnum: The max seqnum of the PEB to scrub from the used/pq lists
*
* This function schedules all device PEBs for scrubbing if the sqnum of the
* vol hdr is less than the sqnum in the trigger.
*
* Return 0 in case of success, (negative) error code otherwise
*
*/
ssize_t ubi_wl_scrub_all(struct ubi_device *ubi, unsigned long long scrub_sqnum)
{
struct rb_node *node;
struct ubi_wl_entry *e, *tmp;
int scrub_count = 0;
int total_scrub_count = 0;
int err, i;
if (!ubi->lookuptbl) {
ubi_err(ubi, "lookuptbl is null");
return -ENOENT;
}
if (is_ubi_readonly(ubi)) {
ubi_err(ubi, "Cannot *Initiate* scrub:background thread disabled or readonly!");
return -EROFS;
}
/* Wait for all currently running work to be done! */
down_write(&ubi->work_sem);
spin_lock(&ubi->wl_lock);
ubi_msg(ubi, "Scrub triggered sqnum = %llu!", scrub_sqnum);
if (ubi->scrub_in_progress) {
ubi_err(ubi, "Scrub already in progress, ignoring the trigger");
spin_unlock(&ubi->wl_lock);
up_write(&ubi->work_sem); /* Allow new work to start. */
return -EBUSY;
}
ubi->scrub_in_progress = true;
/* Go through scrub PEB tree and count pending */
for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
e = rb_entry(node, struct ubi_wl_entry, u.rb);
self_check_in_wl_tree(ubi, e, &ubi->scrub);
e->tagged_scrub_all = 1;
total_scrub_count++;
}
/* Move all used pebs to scrub tree */
node = rb_first(&ubi->used);
while (node != NULL) {
e = rb_entry(node, struct ubi_wl_entry, u.rb);
self_check_in_wl_tree(ubi, e, &ubi->used);
node = rb_next(node);
if (e->sqnum > scrub_sqnum)
continue;
rb_erase(&e->u.rb, &ubi->used);
wl_tree_add(e, &ubi->scrub);
e->tagged_scrub_all = 1;
scrub_count++;
total_scrub_count++;
}
/* Move all protected pebs to scrub tree */
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) {
list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) {
if (e->sqnum > scrub_sqnum)
continue;
list_del(&e->u.list);
wl_tree_add(e, &ubi->scrub);
e->tagged_scrub_all = 1;
scrub_count++;
total_scrub_count++;
}
}
atomic_set(&ubi->scrub_work_count, total_scrub_count);
spin_unlock(&ubi->wl_lock);
up_write(&ubi->work_sem); /* Allow new work to start. */
/*
* Technically scrubbing is the same as wear-leveling, so it is done
* by the WL worker.
*/
err = ensure_wear_leveling(ubi, 0);
if (err) {
ubi_err(ubi, "Failed to start the WL worker err =%d", err);
return err;
}
ubi_msg(ubi, "Scheduled %d PEB's for scrubbing!", scrub_count);
ubi_msg(ubi, "Total PEB's for scrub = %d", total_scrub_count);
/* Wait for scrub to finish */
while (atomic_read(&ubi->scrub_work_count) > 0) {
/* Poll every second to check if the scrub work is done */
msleep(1000);
if (is_ubi_readonly(ubi)) {
ubi_err(ubi, "Cannot *Complete* scrub:background thread disabled or readonly!");
return -EROFS;
}
wake_up_process(ubi->bgt_thread);
}
spin_lock(&ubi->wl_lock);
ubi->scrub_in_progress = false;
spin_unlock(&ubi->wl_lock);
ubi_msg(ubi, "Done scrubbing %d PEB's!", scrub_count);
return 0;
}
/**
* ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing.
* @ubi: UBI device description object
@ -1753,7 +2006,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
ubi->max_ec = ai->max_ec;
INIT_LIST_HEAD(&ubi->works);
sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
scnprintf(ubi->bgt_name, sizeof(UBI_BGT_NAME_PATTERN)+2,
UBI_BGT_NAME_PATTERN, ubi->ubi_num);
err = -ENOMEM;
ubi->lookuptbl = kcalloc(ubi->peb_count, sizeof(void *), GFP_KERNEL);
@ -1786,6 +2040,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
e->pnum = aeb->pnum;
e->ec = aeb->ec;
e->tagged_scrub_all = 0;
e->sqnum = aeb->sqnum;
ubi_assert(e->ec >= 0);
wl_tree_add(e, &ubi->free);
@ -1808,6 +2064,8 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
e->pnum = aeb->pnum;
e->ec = aeb->ec;
e->tagged_scrub_all = 0;
e->sqnum = aeb->sqnum;
ubi->lookuptbl[e->pnum] = e;
if (!aeb->scrub) {
@ -1891,6 +2149,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
#ifdef CONFIG_MTD_UBI_FASTMAP
ubi_ensure_anchor_pebs(ubi);
#endif
ubi->wl_is_inited = 1;
return 0;
out_free:

View file

@ -973,6 +973,15 @@ int atl2_fw_init(struct atl_hw *hw)
atl2_get_fw_version(hw);
/* Warn if FW is lower than 1.3.1 */
if (((mcp->fw_rev >> 24) < 1) ||
(((mcp->fw_rev >> 16) & 0xFFU) < 3) ||
((mcp->fw_rev & 0xFFFFU) < 1))
atl_dev_warn("FW_version: %u.%u.%u, is not stable version",
(mcp->fw_rev >> 24),
((mcp->fw_rev >> 16) & 0xFFU),
(mcp->fw_rev & 0xFFFFU));
mcp->ops = &atl2_fw_ops;
atl_dev_dbg("Detect ATL2FW %x\n", mcp->fw_rev);

View file

@ -20,7 +20,7 @@
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
#define ATL_VERSION "1.1.18"
#define ATL_VERSION "1.1.23"
struct atl_nic;
@ -32,8 +32,6 @@ struct atl_nic;
#define ATL_MAX_QUEUES 8
#include "atl_fwd.h"
struct atl_ptp;
enum {
@ -414,6 +412,7 @@ void atl_update_global_stats(struct atl_nic *nic);
void atl_set_loopback(struct atl_nic *nic, int idx, bool on);
void atl_set_intr_mod(struct atl_nic *nic);
void atl_update_ntuple_flt(struct atl_nic *nic, int idx);
int atl_vlan_promisc_status(struct net_device *ndev);
void atl_set_vlan_promisc(struct atl_hw *hw, int promisc);
int atl_hwsem_get(struct atl_hw *hw, int idx);
void atl_hwsem_put(struct atl_hw *hw, int idx);
@ -424,18 +423,6 @@ int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val);
int atl_update_eth_stats(struct atl_nic *nic);
void atl_adjust_eth_stats(struct atl_ether_stats *stats,
struct atl_ether_stats *base, bool add);
void atl_fwd_release_rings(struct atl_nic *nic);
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
enum atl_fwd_notify;
int atl_fwd_suspend_rings(struct atl_nic *nic);
int atl_fwd_resume_rings(struct atl_nic *nic);
void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data);
#else
static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; }
static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; }
static inline void atl_fwd_notify(struct atl_nic *nic,
enum atl_fwd_notify notif, void *data) {}
#endif
int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay);
void atl_refresh_rxfs(struct atl_nic *nic);
void atl_schedule_work(struct atl_nic *nic);

View file

@ -0,0 +1,123 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2021 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ATL_DUMP_H_
#define _ATL_DUMP_H_
enum atl_crash_dump_types {
atl_crash_dump_type_regs = 0,
atl_crash_dump_type_fwiface = 1,
atl_crash_dump_type_act_res = 2,
atl_crash_dump_type_ring = 3,
};
/** Some of the registers we can not read safely from the device.
* Those will not be read, with value 0xFFFFFFFF stored instead.
*/
struct atl_crash_dump_regs {
u32 type;
u32 length;
union {
u32 regs_data[0x9000/4];
struct{
u32 mif[0x1000/4];
u32 pci[0x1000/4];
u32 itr[0x1000/4];
u32 com[0x1000/4];
u32 mac_phy[0x1000/4];
union {
u32 rx[0x2000/4];
struct{
u32 res1[0x700/4];
u32 pb_ctrl;
u32 res2;
u32 pb_status;
u32 res3;
/* 0x5710 */
struct{
u32 pb_reg1;
u32 pb_reg2;
u32 pb_reg3;
} pb[8];
u32 res4[0x100]; /* TODO */
/* 0x5B00 */
struct{
u32 base_lo;
u32 base_hi;
u32 ctrl;
u32 head;
u32 tail;
u32 status;
u32 size;
u32 threshold;
} dma_desc[32];
} layout;
};
u32 tx[0x2000/4];
} layout;
};
};
struct atl_crash_dump_fwiface {
u32 type;
u32 length;
/* struct fw_interface_in */
u32 fw_interface_in[0x1000/4];
/* struct fw_interface_out */
u32 fw_interface_out[0x1000/4];
};
/* Record table size of 128 with each entry holding (tag, mask, action) */
#define ATL_ACT_RES_TABLE_SIZE 384
struct atl_crash_dump_act_res {
u32 type;
u32 length;
u32 act_res_data[ATL_ACT_RES_TABLE_SIZE];
};
/* max_size = 'ring_size * (tx + rx) * 16 byte raw descriptor data' */
#define ATL_MAX_RING_DESC_SIZE ATL_MAX_RING_SIZE * 32
struct atl_crash_dump_ring {
u32 type;
u32 length;
u32 index;
u32 rx_head;
u32 rx_tail;
u32 tx_head;
u32 tx_tail;
u32 rx_ring_size;
u32 tx_ring_size;
u8 ring_data[ATL_MAX_RING_DESC_SIZE];
};
/* This is an extensible structure to collect various debug data from
* AQC device
*/
struct atl_crash_dump {
u32 length; /* total crash structure length, in bytes */
u32 sections_count; /* number of sections of type atl_crash_dump* following */
u8 drv_version[16];
u8 fw_version[16];
union {
struct {
struct atl_crash_dump_regs regs;
struct atl_crash_dump_fwiface fwiface;
struct atl_crash_dump_act_res act_res;
struct atl_crash_dump_ring ring[ATL_MAX_QUEUES];
} antigua;
struct {
struct atl_crash_dump_regs regs;
struct atl_crash_dump_ring ring[ATL_MAX_QUEUES];
} atlantic;
};
};
#endif

View file

@ -0,0 +1,21 @@
The tool atl_dump_parser is used to parse the register/device dump collected
using "ethtool -d" command. Parser accepts dump in the binary format, hence the
dump must be collected using 'raw' option i.e., 'ethtool -d <device> raw on'
Use gcc to build the binary from sources,
gcc -o atl_dump_parser atl_dump_parser.c
Example:
--------
1. Collect ethtool dump from SUT machine
#ethtool -d enp1s0 raw on > ethd_dump
2. Parse the dump
#ls
atl_dump_parser ethd_dump
#./atl_dump_parser ethd_dump
Parsing is completed successfully
#ls ethd_dump_parsed
action_resolver.txt atl_dump_parser ethd_dump fw_interface.txt registers.txt rings.txt
#
Parsed data will be copied to the text files under <input_file>_parsed folder.

View file

@ -0,0 +1,306 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2021 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include "atl_dump_parser.h"
#include "../atl_dump.h"
#define DEV_FILE "device.txt"
#define REG_FILE "registers.txt"
#define FW_IFACE_FILE "fw_interface.txt"
#define ACT_RES_FILE "action_resolver.txt"
#define RING_FILE "rings.txt"
struct section_header {
u32 type;
u32 length;
};
char out_folder[64];
int dump_device_info(struct atl_crash_dump *crash_dump)
{
char file_name[64];
FILE *file;
snprintf(file_name, 64, "%s/%s", out_folder, DEV_FILE);
file = fopen(file_name, "w");
if (file == NULL) {
printf("Error opening file %s\n", file_name);
return -1;
}
fprintf(file, "Driver version: %s\n", crash_dump->drv_version);
fprintf(file, "FW version: %s\n", crash_dump->fw_version);
fclose(file);
return 0;
}
int dump_registers(struct atl_crash_dump_regs *reg)
{
int block = 0x1000/4, i, offset;
char file_name[64];
FILE *file;
snprintf(file_name, 64, "%s/%s", out_folder, REG_FILE);
file = fopen(file_name, "w");
if (file == NULL) {
printf("Error opening file %s\n", file_name);
return -1;
}
/* Skip MIF block */
offset = block * 4;
fprintf(file, "PCI Registers\n");
fprintf(file, "=============\n");
for (i = 0; i < block; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.pci[i]);
offset += block * 4;
fprintf(file, "\n\nInterrupt Registers\n");
fprintf(file, "=====================\n");
for (i = 0; i < block; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.itr[i]);
offset += block * 4;
fprintf(file, "\n\nCOM Registers\n");
fprintf(file, "===============\n");
for (i = 0; i < block; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.com[i]);
offset += block * 4;
fprintf(file, "\n\nMac Phy Registers\n");
fprintf(file, "=====================\n");
for (i = 0; i < block; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.mac_phy[i]);
offset += block * 4;
fprintf(file, "\n\nRx Registers\n");
fprintf(file, "===============\n");
/* Rx block size is 0x2000 */
for (i = 0; i < block * 2; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.rx[i]);
offset += block * 2 * 4;
fprintf(file, "\n\nTx Registers\n");
fprintf(file, "===============\n");
/* Tx block size is 0x2000 */
for (i = 0; i < block * 2; i++)
fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.tx[i]);
fclose(file);
return 0;
}
int dump_fwiface(struct atl_crash_dump_fwiface *fwiface)
{
int block = 0x1000/4, i;
char file_name[64];
FILE *file;
snprintf(file_name, 64, "%s/%s", out_folder, FW_IFACE_FILE);
file = fopen(file_name, "w");
if (file == NULL) {
printf("Error opening file %s\n", file_name);
return -1;
}
fprintf(file, "FW input interface\n");
fprintf(file, "==================\n");
for (i = 0; i < block; i += 4)
fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i,
fwiface->fw_interface_in[i], fwiface->fw_interface_in[i + 1],
fwiface->fw_interface_in[i + 2], fwiface->fw_interface_in[i + 3]);
fprintf(file, "\n\nFW output interface\n");
fprintf(file, "=======================\n");
for (i = 0; i < block; i += 4)
fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i,
fwiface->fw_interface_out[i], fwiface->fw_interface_out[i + 1],
fwiface->fw_interface_out[i + 2], fwiface->fw_interface_out[i + 3]);
fclose(file);
return 0;
}
int dump_act_res(struct atl_crash_dump_act_res *act_res)
{
char file_name[64];
int i, idx;
FILE *file;
snprintf(file_name, 64, "%s/%s", out_folder, ACT_RES_FILE);
file = fopen(file_name, "w");
if (file == NULL) {
printf("Error opening file %s\n", file_name);
return -1;
}
fprintf(file, "RECORD RESOLVER TAG TAG Mask Action\n");
fprintf(file, "==================================================\n");
for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) {
fprintf(file, "%d\t0x%08x\t0x%08x\t0x%08x\n", i, act_res->act_res_data[idx++],
act_res->act_res_data[idx++], act_res->act_res_data[idx++]);
}
fclose(file);
return 0;
}
int dump_ring(struct atl_crash_dump_ring *ring)
{
char file_name[64];
FILE *file;
u32 *data;
int i;
/* Assumption - file 'rings.txt' shouldn't exists */
snprintf(file_name, 64, "%s/%s", out_folder, RING_FILE);
file = fopen(file_name, "a+");
if (file == NULL) {
printf("Error opening file %s\n", file_name);
return -1;
}
fprintf(file, "Ring Index %d\n", ring->index);
fprintf(file, "==============\n");
fprintf(file, "Rx head = 0x%08x tail = 0x%08x\n", ring->rx_head, ring->rx_tail);
fprintf(file, "Tx head = 0x%08x tail = 0x%08x\n", ring->tx_head, ring->tx_tail);
fprintf(file, "HW Ring rx_size = %d tx_size = %d\n", ring->rx_ring_size, ring->tx_ring_size);
fprintf(file, "Rx Ring descriptor:\n");
fprintf(file, "-------------------\n");
data = (u32 *)ring->ring_data;
for (i = 0; i < ring->rx_ring_size; i += 4)
fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1],
data[i + 2], data[i + 3]);
fprintf(file, "Tx Ring descriptor:\n");
fprintf(file, "-------------------\n");
data = (u32 *)ring->ring_data + ring->rx_ring_size;
for (i = 0; i < ring->tx_ring_size; i += 4)
fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1],
data[i + 2], data[i + 3]);
fprintf(file, "\n");
fclose(file);
return 0;
}
int main(int argc, char *argv[])
{
struct atl_crash_dump *crash_dump;
struct section_header *header;
int i, offset, ret = 0;
time_t t = time(NULL);
struct tm *tm_val;
FILE *input_file;
struct stat st;
char *buffer;
if (argc < 2) {
printf("No intput file\n");
return -1;
}
if (stat(argv[1], &st) == -1) {
printf("File stat error\n");
return -1;
}
buffer = malloc(st.st_size);
if (!buffer) {
printf("Mem alloc error\n");
return -1;
}
/* open the source file for reading */
input_file = fopen(argv[1],"rb");
if (input_file == NULL) {
ret = -1;
printf("Error opening file %s\n", argv[1]);
goto err;
}
fread(buffer, sizeof(char), st.st_size, input_file);
fclose(input_file);
tm_val = localtime(&t);
tm_val = NULL;
if (tm_val)
snprintf(out_folder, 64, "%s_%02d-%02d-%02d_%02d-%02d-%02d", argv[1],
tm_val->tm_mon + 1, (int) tm_val->tm_mday, 1900 + tm_val->tm_year,
tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec);
else
snprintf(out_folder, 64, "%s_parsed", argv[1]);
if (stat(out_folder, &st) == -1) {
if (mkdir(out_folder, 0644) == -1) {
ret = -1;
printf("Failed to creat folder` %s\n", out_folder);
goto err;
}
}
crash_dump = (struct atl_crash_dump *)buffer;
ret = dump_device_info(crash_dump);
if (ret)
goto err;
offset = offsetof(struct atl_crash_dump, antigua);
for (i = 0; i < crash_dump->sections_count; i++) {
header = (struct section_header *)(buffer + offset);
switch (header->type) {
case atl_crash_dump_type_regs:
ret = dump_registers((struct atl_crash_dump_regs *)(buffer + offset));
if (ret)
goto err;
break;
case atl_crash_dump_type_fwiface:
ret = dump_fwiface((struct atl_crash_dump_fwiface *)(buffer + offset));
if (ret)
goto err;
break;
case atl_crash_dump_type_act_res:
ret = dump_act_res((struct atl_crash_dump_act_res *)(buffer + offset));
if (ret)
goto err;
break;
case atl_crash_dump_type_ring:
ret = dump_ring((struct atl_crash_dump_ring *)(buffer + offset));
if (ret)
goto err;
break;
default:
printf("Parsing Error - invalid section\n");
goto err;
}
offset += header->length;
}
err:
free(buffer);
if (ret)
printf("Failed to parse the dump\n");
else
printf("Parsing is completed successfully\n");
return 0;
}

View file

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Atlantic Network Driver
*
* Copyright (C) 2021 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ATL_DUMP_PARSER
#define __ATL_DUMP_PARSER
#define ATL_MAX_RING_SIZE (8192 - 8)
#define ATL_MAX_QUEUES 8
typedef unsigned int u32;
typedef unsigned char u8;
#endif

View file

@ -20,6 +20,7 @@
#include "atl_fwdnl.h"
#include "atl_macsec.h"
#include "atl_ptp.h"
#include "atl_fwd.h"
static uint32_t atl_ethtool_get_link(struct net_device *ndev)
{
@ -633,8 +634,8 @@ static const struct atl_stat_desc eth_stat_descs[] = {
ATL_ETH_STAT(tx_pause, tx_pause),
ATL_ETH_STAT(tx_ether_pkts, tx_ether_pkts),
ATL_ETH_STAT(tx_ether_octets, tx_ether_octets),
ATL_ETH_STAT(tx_errors, tx_errors),
ATL_ETH_STAT(rx_pause, rx_pause),
ATL_ETH_STAT(rx_ether_drops, rx_ether_drops),
ATL_ETH_STAT(rx_ether_octets, rx_ether_octets),
ATL_ETH_STAT(rx_ether_pkts, rx_ether_pkts),
ATL_ETH_STAT(rx_ether_broacasts, rx_ether_broacasts),
@ -642,6 +643,13 @@ static const struct atl_stat_desc eth_stat_descs[] = {
ATL_ETH_STAT(rx_ether_crc_align_errs, rx_ether_crc_align_errs),
ATL_ETH_STAT(rx_filter_host, rx_filter_host),
ATL_ETH_STAT(rx_filter_lost, rx_filter_lost),
ATL_ETH_STAT(rx_errors, rx_errors),
ATL_ETH_STAT(rx_drops, rx_drops),
ATL_ETH_STAT(rx_dma_packets, rx_dma_packets),
ATL_ETH_STAT(rx_dma_octets, rx_dma_octets),
ATL_ETH_STAT(rx_dma_drops, rx_dma_drops),
ATL_ETH_STAT(tx_dma_packets, tx_dma_packets),
ATL_ETH_STAT(tx_dma_octets, tx_dma_octets),
};
#define ATL_PRIV_FLAG(_name, _bit) \
@ -1173,8 +1181,15 @@ static int atl_set_priv_flags(struct net_device *ndev, uint32_t flags)
return 0;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
static int atl_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kec,
struct netlink_ext_ack *extack)
#else
static int atl_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ec)
#endif
{
struct atl_nic *nic = netdev_priv(ndev);
@ -1185,8 +1200,15 @@ static int atl_get_coalesce(struct net_device *ndev,
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
static int atl_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ec,
struct kernel_ethtool_coalesce *kec,
struct netlink_ext_ack *extack)
#else
static int atl_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *ec)
#endif
{
struct atl_nic *nic = netdev_priv(ndev);
@ -2711,9 +2733,7 @@ static void atl_refresh_rxf_desc(struct atl_nic *nic,
atl_for_each_rxf_idx(desc, idx)
desc->update_rxf(nic, idx);
atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) ||
nic->rxf_vlan.promisc_count ||
!nic->rxf_vlan.vlans_active);
atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev));
}
void atl_refresh_rxfs(struct atl_nic *nic)
@ -2723,9 +2743,7 @@ void atl_refresh_rxfs(struct atl_nic *nic)
atl_for_each_rxf_desc(desc)
atl_refresh_rxf_desc(nic, desc);
atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) ||
nic->rxf_vlan.promisc_count ||
!nic->rxf_vlan.vlans_active);
atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev));
}
static bool atl_vlan_pull_from_promisc(struct atl_nic *nic, uint32_t idx)
@ -2765,9 +2783,8 @@ static bool atl_vlan_pull_from_promisc(struct atl_nic *nic, uint32_t idx)
} while (idx & ATL_VIDX_FREE);
kfree(map);
atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) ||
vlan->promisc_count ||
!vlan->vlans_active);
atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev));
return true;
}
@ -2955,9 +2972,7 @@ int atl_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
vlan->promisc_count++;
if (pm_runtime_active(&nic->hw.pdev->dev))
atl_set_vlan_promisc(&nic->hw,
(ndev->flags & IFF_PROMISC) ||
vlan->promisc_count ||
!vlan->vlans_active);
atl_vlan_promisc_status(nic->ndev));
return 0;
}
@ -2984,9 +2999,8 @@ update_vlan:
atl_rxf_update_vlan(nic, idx);
if (pm_runtime_active(&nic->hw.pdev->dev))
atl_set_vlan_promisc(&nic->hw,
(nic->ndev->flags & IFF_PROMISC) ||
vlan->promisc_count ||
!vlan->vlans_active);
atl_vlan_promisc_status(nic->ndev));
return 0;
}
@ -3027,9 +3041,9 @@ int atl_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
update_vlan_promisc:
if (pm_runtime_active(&nic->hw.pdev->dev))
atl_set_vlan_promisc(&nic->hw, (ndev->flags & IFF_PROMISC) ||
vlan->promisc_count ||
!vlan->vlans_active);
atl_set_vlan_promisc(&nic->hw,
atl_vlan_promisc_status(nic->ndev));
return 0;
}
@ -3086,6 +3100,18 @@ static void atl_ethtool_complete(struct net_device *ndev)
pm_runtime_put(&nic->hw.pdev->dev);
}
static int atl_ethool_get_regs_len(struct net_device *ndev)
{
return atl_get_crash_dump(ndev, NULL);
}
static void atl_ethool_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *buf)
{
regs->version = 0;
memset(buf, 0, regs->len);
atl_get_crash_dump(ndev, buf);
}
const struct ethtool_ops atl_ethtool_ops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
@ -3128,4 +3154,6 @@ const struct ethtool_ops atl_ethtool_ops = {
.set_wol = atl_set_wol,
.begin = atl_ethtool_begin,
.complete = atl_ethtool_complete,
.get_regs_len = atl_ethool_get_regs_len,
.get_regs = atl_ethool_get_regs,
};

View file

@ -1172,6 +1172,39 @@ int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val)
static unsigned int atl_wdog_period = 1100;
module_param_named(wdog_period, atl_wdog_period, uint, 0644);
static int atl_fw_rev_check_and_warn(int fw_rev)
{
int major = (fw_rev >> 24) & 0xFFU;
bool ret = true;
switch (major) {
case 2:
if ((((fw_rev >> 16) & 0xFFU) < 12) &&
((fw_rev & 0xFFFFU) < 12))
ret = false;
break;
case 3:
if ((((fw_rev >> 16) & 0xFFU) < 1) &&
((fw_rev & 0xFFFFU) < 102))
ret = false;
break;
case 4:
if ((((fw_rev >> 16) & 0xFFU) < 2) &&
((fw_rev & 0xFFFFU) < 37))
ret = false;
break;
default:
ret = false;
}
return ret;
}
int atl_fw_init(struct atl_hw *hw)
{
uint32_t tries, reg, major;
@ -1186,6 +1219,13 @@ int atl_fw_init(struct atl_hw *hw)
atl_dev_dbg("FW startup took %d ms\n", tries);
major = (reg >> 24) & 0xff;
/* Warn if FW is lower than 2.12.12, 3.1.102 and 4.2.37 */
if (!atl_fw_rev_check_and_warn(reg))
atl_dev_warn("FW_version: %u.%u.%u, is not stable version",
(reg >> 24), ((reg >> 16) & 0xFFU),
(reg & 0xFFFFU));
if (!major || major > 3) {
atl_dev_err("Unsupported FW major version: %u\n", major);
return -EINVAL;

View file

@ -12,6 +12,46 @@
#include <linux/etherdevice.h>
#include "atl_common.h"
#include "atl_desc.h"
#include "atl_fwd.h"
#include "atl_ring.h"
static u32 atl_skip_reglist[] = {
/* PCIE */
0x1030, 0x1200, 0x1514, 0x1F00, 0x1F04, 0x1F20, 0x1F24,
/* INTR Registers */
0x21A0, 0x21A4, 0x21A8,
/* COM Registers */
0x30A0, 0x30A8, 0x3900, 0x3920,
/* MAC PHY Registers */
0x4058, 0x4060, 0x4064, 0x40B0, 0x40B4, 0x40B8, 0x40BC,
0x4120, 0x4140, 0x4144, 0x4190, 0x419C, 0x41A0, 0x41A4,
0x41A8, 0x4270, 0x4288, 0x428C, 0x4290, 0x4294, 0x42E8,
0x42EC, 0x434C, 0x4378, 0x4380, 0x4384, 0x4440, 0x4444,
0x4970, 0x4B40, 0x4B44, 0x4B48, 0x4B4C,
/* RX Registers */
0x5108, 0x54CC, 0x55B0, 0x55B4, 0x55C0, 0x55E0, 0x55E4,
0x5640, 0x5718, 0x5728, 0x5738, 0x5748, 0x5758, 0x5768,
0x5778, 0x5788, 0x5808, 0x580C, 0x5A10, 0x5B14, 0x5B34,
0x5B54, 0x5B74, 0x5B94, 0x5BB4, 0x5BD4, 0x5BF4, 0x5C14,
0x5C34, 0x5C54, 0x5C74, 0x5C94, 0x5CB4, 0x5CD4, 0x5CF4,
0x5D14, 0x5D34, 0x5D54, 0x5D74, 0x5D94, 0x5DB4, 0x5DD4,
0x5DF4, 0x5E14, 0x5E34, 0x5E54, 0x5E74, 0x5E94, 0x5EB4,
0x5ED4, 0x5EF4, 0x6900, 0x6F00, 0x6F20,
/* TX Registers */
0x7808, 0x7848, 0x784C, 0x78B0, 0x78B4, 0x7918, 0x7928,
0x7938, 0x7948, 0x7958, 0x7968, 0x7978, 0x7988, 0x7A34,
0x7B10, 0x7B14, 0x7B18, 0x7C14, 0x7C54, 0x7C94, 0x7CD4,
0x7D14, 0x7D54, 0x7D94, 0x7DD4, 0x7E14, 0x7E54, 0x7E94,
0x7ED4, 0x7F14, 0x7F54, 0x7F94, 0x7FD4, 0x8014, 0x8054,
0x8094, 0x80D4, 0x8114, 0x8154, 0x8194, 0x81D4, 0x8214,
0x8254, 0x8294, 0x82D4, 0x8314, 0x8354, 0x8394, 0x83D4,
0x8900, 0x8904, 0x8F00, 0x8F20,
};
static const char *atl_fwd_dir_str(struct atl_fwd_ring *ring)
{
@ -903,3 +943,178 @@ int atl_fwd_resume_rings(struct atl_nic *nic)
err:
return ret;
}
int atl_get_ext_stats(struct net_device *ndev, struct atl_ext_stats *stats)
{
struct atl_nic *nic = netdev_priv(ndev);
if (!stats)
return -EINVAL;
atl_update_eth_stats(nic);
atl_update_global_stats(nic);
memcpy(&stats->rx, &nic->stats.rx, sizeof(stats->rx));
memcpy(&stats->tx, &nic->stats.tx, sizeof(stats->tx));
memcpy(&stats->rx_fwd, &nic->stats.rx_fwd, sizeof(stats->rx_fwd));
memcpy(&stats->eth, &nic->stats.eth, sizeof(stats->eth));
return 0;
}
EXPORT_SYMBOL(atl_get_ext_stats);
static bool atl_skip_register(u32 reg)
{
int i, count;
count = sizeof(atl_skip_reglist) / sizeof(u32);
for (i = 0; i < count; i++)
if (atl_skip_reglist[i] == reg)
return true;
return false;
}
static int atl_get_crash_dump_regs(struct atl_hw *hw, struct atl_crash_dump_regs *section)
{
int addr, index;
section->type = atl_crash_dump_type_regs;
section->length = sizeof(struct atl_crash_dump_regs);
/* prefill with 'skip' value */
for (addr = 0; addr < sizeof(section->regs_data); addr++)
section->regs_data[addr] = 0xFFFFFFFF;
for (addr = 0x1000, index = 0x1000 / 4; addr < 0x9000; addr += 4, index++) {
if (atl_skip_register(addr))
continue;
section->regs_data[index] = atl_read(hw, addr);
}
return section->length;
}
static int atl_get_crash_dump_fwiface(struct atl_hw *hw, struct atl_crash_dump_fwiface *section)
{
int i;
section->type = atl_crash_dump_type_fwiface;
section->length = sizeof(struct atl_crash_dump_fwiface);
for (i = 0; i < ARRAY_SIZE(section->fw_interface_in); i++)
section->fw_interface_in[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_IN(i));
for (i = 0; i < ARRAY_SIZE(section->fw_interface_out); i++)
section->fw_interface_out[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_OUT(i));
return section->length;
}
static int atl_get_crash_dump_act_res(struct atl_hw *hw, struct atl_crash_dump_act_res *section)
{
int i, idx, err;
section->type = atl_crash_dump_type_act_res;
section->length = sizeof(struct atl_crash_dump_act_res);
err = atl_hwsem_get(hw, ATL2_MCP_SEM_ACT_RSLVR);
if (err) {
printk("Failed to aquire act_res semaphore\n");
goto ret;
}
for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) {
section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_REQ_TAG(i));
section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_TAG_MASK(i));
section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_ACTN(i));
}
atl_hwsem_put(hw, ATL2_MCP_SEM_ACT_RSLVR);
ret:
return section->length;
}
static int atl_get_crash_dump_ring(struct atl_nic *nic, int idx,
struct atl_crash_dump_ring *section)
{
int size = sizeof(struct atl_crash_dump_ring), offset;
struct atl_queue_vec *qvec = &nic->qvecs[idx];
struct atl_hw_ring *hwring;
if (!test_bit(ATL_ST_UP, &nic->hw.state)) {
memset(section, 0, size);
goto ret;
}
section->type = atl_crash_dump_type_ring;
section->index = qvec->idx;
section->length = size;
section->rx_head = qvec->rx.head;
section->rx_tail = qvec->rx.tail;
section->tx_head = qvec->tx.head;
section->tx_tail = qvec->tx.tail;
hwring = &qvec->rx.hw;
section->rx_ring_size = hwring->size;
memcpy(section->ring_data, hwring->descs, hwring->size * sizeof(*hwring->descs));
offset = hwring->size * sizeof(*hwring->descs);
hwring = &qvec->tx.hw;
section->tx_ring_size = hwring->size;
memcpy(section->ring_data + offset, hwring->descs, hwring->size * sizeof(*hwring->descs));
ret:
return size;
}
int atl_get_crash_dump(struct net_device *ndev, struct atl_crash_dump *crash_dump)
{
struct atl_nic *nic = netdev_priv(ndev);
u32 fw_rev = nic->hw.mcp.fw_rev;
int recorded_sz = 0, i, nvecs;
u8 *section;
if (!crash_dump)
return sizeof(struct atl_crash_dump);
crash_dump->length = sizeof(*crash_dump);
crash_dump->sections_count = 0;
strlcpy(crash_dump->drv_version, ATL_VERSION, sizeof(crash_dump->drv_version));
snprintf(crash_dump->fw_version, sizeof(crash_dump->fw_version),
"%d.%d.%d", fw_rev >> 24, fw_rev >> 16 & 0xff, fw_rev & 0xffff);
if (nic->hw.chip_id == ATL_ANTIGUA)
section = (void *)&crash_dump->antigua.regs;
else
section = (void *)&crash_dump->atlantic.regs;
recorded_sz = atl_get_crash_dump_regs(&nic->hw, (void *)section);
crash_dump->sections_count++;
crash_dump->length += recorded_sz;
section += recorded_sz;
if (nic->hw.chip_id == ATL_ANTIGUA) {
recorded_sz = atl_get_crash_dump_fwiface(&nic->hw, (void *)section);
crash_dump->sections_count++;
crash_dump->length += recorded_sz;
section += recorded_sz;
recorded_sz = atl_get_crash_dump_act_res(&nic->hw, (void *)section);
crash_dump->sections_count++;
crash_dump->length += recorded_sz;
section += recorded_sz;
}
nvecs = min_t(int, nic->nvecs, ATL_MAX_QUEUES);
for (i = 0; i < nvecs; i++) {
recorded_sz = atl_get_crash_dump_ring(nic, i, (void *)section);
crash_dump->sections_count++;
crash_dump->length += recorded_sz;
section += recorded_sz;
}
return crash_dump->length;
}
EXPORT_SYMBOL(atl_get_crash_dump);

View file

@ -13,9 +13,10 @@
#define _ATL_FWD_H_
#include "atl_common.h"
#include "atl_dump.h"
/* Each incompatible API change bumps the API version */
#define ATL_FWD_API_VERSION 3
#define ATL_FWD_API_VERSION 4
struct atl_fwd_event;
@ -405,4 +406,40 @@ enum atl_fwd_ring_state {
ATL_FWR_ST_EVT_ENABLED = BIT(1),
};
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
enum atl_fwd_notify;
void atl_fwd_release_rings(struct atl_nic *nic);
int atl_fwd_suspend_rings(struct atl_nic *nic);
int atl_fwd_resume_rings(struct atl_nic *nic);
void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data);
#else
static inline void atl_fwd_release_rings(struct atl_nic *nic) {}
static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; }
static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; }
static inline void atl_fwd_notify(struct atl_nic *nic,
enum atl_fwd_notify notif, void *data) {}
#endif
struct atl_ext_stats {
struct atl_rx_ring_stats rx;
struct atl_tx_ring_stats tx;
struct atl_rx_fwd_ring_stats rx_fwd;
struct atl_ether_stats eth;
};
/**
* Direct statistics fetch call for the device
*/
int atl_get_ext_stats(struct net_device *ndev, struct atl_ext_stats *stats);
/**
* Get the register and other crash related information from the device
* If @crash_dump is NULL, function will return the requested length of the buffer to
* store dump, in bytes
* if @crash_dump is not null, function will fill the buffer with crashdump
* sections filled, up to crash_dump->length
*/
int atl_get_crash_dump(struct net_device *ndev, struct atl_crash_dump *crash_dump);
#endif

View file

@ -21,6 +21,7 @@
#include "atl_fwdnl.h"
#include "atl_common.h"
#include "atl_fwd.h"
#include "atl_fwdnl_params.h"
#include "atl_ring.h"
#include "atl_trace.h"
@ -1742,7 +1743,9 @@ static const struct nla_policy atlfwd_nl_policy[NUM_ATL_FWD_ATTR] = {
[ATL_FWD_ATTR_QUEUE_INDEX] = { .type = NLA_S32 },
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) && \
RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8, 0)
#define ATLFWD_NL_OP_POLICY(op_policy) .policy = op_policy
#else
#define ATLFWD_NL_OP_POLICY(op_policy)

View file

@ -13,6 +13,7 @@
#include <linux/workqueue.h>
#include "atl_common.h"
#include "atl_fwd.h"
unsigned int atlfwd_nl_tx_clean_threshold_msec = 200;
unsigned int atlfwd_nl_tx_clean_threshold_frac = 8;

View file

@ -114,6 +114,16 @@ static void atl_set_promisc(struct atl_hw *hw, bool enabled, bool allmulti)
}
}
int atl_vlan_promisc_status(struct net_device *ndev)
{
struct atl_nic *nic = netdev_priv(ndev);
return ndev->flags & IFF_PROMISC ||
nic->rxf_vlan.promisc_count ||
!nic->rxf_vlan.vlans_active ||
!(ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER);
}
void atl_set_vlan_promisc(struct atl_hw *hw, int promisc)
{
atl_write_bit(hw, ATL_RX_VLAN_FLT_CTRL1, 1, !!promisc);
@ -746,7 +756,7 @@ void atl_start_hw_global(struct atl_nic *nic)
(tpb_size * 32 * 66 / 100) << 16 |
(tpb_size * 32 * 50 / 100));
/* 4-TC | Enable TPB */
atl_set_bits(hw, ATL_TX_PBUF_CTRL1, BIT(8) | BIT(0));
atl_set_bits(hw, ATL_TX_PBUF_CTRL1, BIT(8) | BIT(2) | BIT(0));
/* TX Buffer clk gate off */
if (hw->chip_id == ATL_ANTIGUA)
atl_clear_bits(hw, ATL_TX_PBUF_CTRL1, BIT(5));
@ -910,9 +920,7 @@ void atl_set_rx_mode(struct net_device *ndev)
/* Enable promisc VLAN mode if IFF_PROMISC explicitly
* requested or too many VIDs registered
*/
atl_set_vlan_promisc(hw,
ndev->flags & IFF_PROMISC || nic->rxf_vlan.promisc_count ||
!nic->rxf_vlan.vlans_active);
atl_set_vlan_promisc(hw, atl_vlan_promisc_status(ndev));
atl_set_promisc(hw, promisc_needed,
is_multicast_enabled && all_multi_needed);
@ -1319,6 +1327,14 @@ static int __atl_fetch_msm2_stats(struct atl_hw *hw,
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_OCTETS_HI, &reg2, hwsem_put);
stats->tx_ether_octets = ((uint64_t)reg2 << 32) | reg;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_LO, &reg, hwsem_put);
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_HI, &reg2, hwsem_put);
stats->tx_errors = ((uint64_t)reg2 << 32) | reg;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_LO, &reg, hwsem_put);
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_HI, &reg2, hwsem_put);
stats->tx_errors += ((uint64_t)reg2 << 32) | reg;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_PAUSE_LO, &reg, hwsem_put);
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_PAUSE_HI, &reg2, hwsem_put);
stats->rx_pause = ((uint64_t)reg2 << 32) | reg;
@ -1346,6 +1362,13 @@ static int __atl_fetch_msm2_stats(struct atl_hw *hw,
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ALIGN_ERRS_HI, &reg2, hwsem_put);
stats->rx_ether_crc_align_errs += ((uint64_t)reg2 << 32) | reg;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ERRS_CNTR_LO, &reg, hwsem_put);
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ERRS_CNTR_HI, &reg2, hwsem_put);
stats->rx_errors = ((uint64_t)reg2 << 32) | reg;
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_DROP_CNTR_LO, &reg, hwsem_put);
__READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_DROP_CNTR_HI, &reg2, hwsem_put);
stats->rx_drops = ((uint64_t)reg2 << 32) | reg;
hwsem_put:
atl_hwsem_put(hw, ATL_MCP_SEM_MSM);
return ret;
@ -1373,7 +1396,19 @@ int atl_update_eth_stats(struct atl_nic *nic)
if (ret)
goto unlock_fw;
stats.rx_ether_drops = atl_read(hw, ATL_RX_DMA_STATS_CNT7);
stats.rx_dma_drops = atl_read(hw, ATL_RX_DMA_STATS_CNT7);
stats.rx_dma_packets = atl_read(hw, ATL_RX_DMA_STATS_CNT1);
stats.rx_dma_packets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT2) << 32;
stats.rx_dma_octets = atl_read(hw, ATL_RX_DMA_STATS_CNT3);
stats.rx_dma_octets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT4) << 32;
stats.tx_dma_packets = atl_read(hw, ATL_TX_DMA_STATS_CNT1);
stats.tx_dma_packets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT2) << 32;
stats.tx_dma_octets = atl_read(hw, ATL_TX_DMA_STATS_CNT3);
stats.tx_dma_octets += (uint64_t)atl_read(hw, ATL_TX_DMA_STATS_CNT4) << 32;
/* capture debug counters*/
atl_write_bit(hw, ATL_RX_RPF_DBG_CNT_CTRL, 0x1f, 1);
@ -1685,4 +1720,3 @@ static void atl2_hw_new_rx_filter_promisc(struct atl_hw *hw, bool promisc,
off_action);
}

View file

@ -241,6 +241,8 @@ void hw_atl_extract_hwts(struct atl_hw *hw, struct atl_rx_desc_hwts_wb *hwts_wb,
sec += tmp;
tmp = (u64)((hwts_wb->sec_hw >> 22) & 0x3ff) << 38;
sec += tmp;
if (sec == 0xffffffffffff && hwts_wb->ns == 0xffffffff)
return;
ns = sec * NSEC_PER_SEC + hwts_wb->ns;
if (timestamp)
*timestamp = ns + hw->ptp_clk_offset;

View file

@ -12,6 +12,7 @@
#include "atl_macsec.h"
#if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC)
#include "atl_common.h"
#include "atl_fwd.h"
#include <linux/rtnetlink.h>
#include "macsec/macsec_api.h"

View file

@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>
#include "atl_macsec.h"
#include "atl_ptp.h"
#include "atl_fwd.h"
const char atl_driver_name[] = "atlantic-fwd";
@ -384,7 +385,7 @@ int atl_do_reset(struct atl_nic *nic)
hw->mcp.ops->dump_cfg(hw);
atl_stop(nic, true);
atl_stop(nic, false);
atl_fwd_suspend_rings(nic);
@ -765,9 +766,7 @@ static void atl_remove(struct pci_dev *pdev)
atl_ptp_unregister(nic);
unregister_netdev(nic->ndev);
#if IS_ENABLED(CONFIG_ATLFWD_FWD)
atl_fwd_release_rings(nic);
#endif
atl_clear_datapath(nic);
@ -948,6 +947,47 @@ static int atl_pm_runtime_idle(struct device *dev)
return -EBUSY;
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 0))
static void atl_reset_prepare(struct pci_dev *pdev)
{
struct atl_nic *nic = pci_get_drvdata(pdev);
pm_runtime_get_sync(&nic->hw.pdev->dev);
rtnl_lock();
if (netif_running(nic->ndev))
atl_stop(nic, false);
rtnl_unlock();
pm_runtime_put_sync(&nic->hw.pdev->dev);
}
static void atl_reset_done(struct pci_dev *pdev)
{
struct atl_nic *nic = pci_get_drvdata(pdev);
if (!nic) {
dev_err(&pdev->dev, "%s failed, device is unrecoverable\n",
__func__);
return;
}
pm_runtime_get_sync(&nic->hw.pdev->dev);
rtnl_lock();
if (netif_running(nic->ndev))
atl_start(nic);
rtnl_unlock();
pm_runtime_put_sync(&nic->hw.pdev->dev);
}
static const struct pci_error_handlers atl_err_handlers = {
.reset_prepare = atl_reset_prepare,
.reset_done = atl_reset_done,
};
#endif
const struct dev_pm_ops atl_pm_ops = {
.suspend = atl_suspend_poweroff,
.poweroff = atl_suspend_poweroff,
@ -968,6 +1008,11 @@ static struct pci_driver atl_pci_ops = {
#ifdef CONFIG_PM
.driver.pm = &atl_pm_ops,
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 0))
.err_handler = &atl_err_handlers,
#endif
};
struct atl_thermal atl_def_thermal;

View file

@ -893,8 +893,13 @@ void atl_ptp_tx_hwtstamp(struct atl_nic *nic, u64 timestamp)
return;
}
timestamp += atomic_read(&ptp->offset_egress);
atl_ptp_convert_to_hwtstamp(&hwtstamp, timestamp);
if (!timestamp) {
atl_nic_err("ptp timestamp all-F from FW\n");
memset(&hwtstamp, 0, sizeof(hwtstamp));
} else {
timestamp += atomic_read(&ptp->offset_egress);
atl_ptp_convert_to_hwtstamp(&hwtstamp, timestamp);
}
do {
skb_tstamp_tx(skb, &hwtstamp);
dev_kfree_skb_any(skb);

View file

@ -176,8 +176,17 @@ enum mcp_scratchpad {
#define ATL_RX_RING_BUF_SIZE(ring) ATL_RING_OFFT(ring, 0x18)
#define ATL_RX_RING_THRESH(ring) ATL_RING_OFFT(ring, 0x1c)
#define ATL_RX_DMA_STATS_CNT1 0x6800
#define ATL_RX_DMA_STATS_CNT2 0x6804
#define ATL_RX_DMA_STATS_CNT3 0x6808
#define ATL_RX_DMA_STATS_CNT4 0x680C
#define ATL_RX_DMA_STATS_CNT7 0x6818
#define ATL_TX_DMA_STATS_CNT1 0x8800
#define ATL_TX_DMA_STATS_CNT2 0x8804
#define ATL_TX_DMA_STATS_CNT3 0x8808
#define ATL_TX_DMA_STATS_CNT4 0x880C
/* TX @ 0x7000 */
#define ATL_TX_CTRL1 0x7000
#define ATL_TX_PO_CTRL1 0x7800
@ -224,6 +233,10 @@ enum mcp_scratchpad {
#define ATL_MSM_CTR_RX_ERRS 0x120
#define ATL_MSM2_CTR_RX_DROP_CNTR_LO 0x158
#define ATL_MSM2_CTR_RX_DROP_CNTR_HI 0x15C
#define ATL_MSM2_CTR_RX_ERRS_CNTR_LO 0x138
#define ATL_MSM2_CTR_RX_ERRS_CNTR_HI 0x13C
#define ATL_MSM2_CTR_RX_OCTETS_LO 0x100
#define ATL_MSM2_CTR_RX_OCTETS_HI 0x104
#define ATL_MSM2_CTR_RX_ALIGN_ERRS_LO 0x110
@ -245,5 +258,9 @@ enum mcp_scratchpad {
#define ATL_MSM2_CTR_TX_PKTS_LO 0x220
#define ATL_MSM2_CTR_TX_PKTS_HI 0x224
#define ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_LO 0x228
#define ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_HI 0x22C
#define ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_LO 0x238
#define ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_HI 0x23C
#endif

View file

@ -244,6 +244,14 @@ static uint32_t atl_insert_context(struct atl_txbuf *txbuf,
return tx_cmd;
}
static bool atl_ptp_udp(struct sk_buff *skb)
{
return (ip_hdr(skb)->version == 4) &&
(ip_hdr(skb)->protocol == IPPROTO_UDP) &&
((udp_hdr(skb)->dest == htons(319)) ||
(udp_hdr(skb)->dest == htons(320)));
}
netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct atl_nic *nic = netdev_priv(ndev);
@ -257,12 +265,9 @@ netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev)
* and hardware PTP design of the chip. Otherwise ptp stream
* will fail to sync
*/
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
unlikely((ip_hdr(skb)->version == 4) &&
(ip_hdr(skb)->protocol == IPPROTO_UDP) &&
((udp_hdr(skb)->dest == htons(319)) ||
(udp_hdr(skb)->dest == htons(320)))) ||
unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588)))
if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
atl_ptp_udp(skb) ||
(eth_hdr(skb)->h_proto == htons(ETH_P_1588))))
return atl_ptp_start_xmit(nic, skb);
}
@ -448,7 +453,7 @@ static bool atl_checksum_workaround(struct sk_buff *skb,
if (((desc->pkt_type & atl_rx_pkt_type_vlan_msk) ==
atl_rx_pkt_type_vlan) &&
!(desc->rx_estat & atl_rx_estat_vlan_stripped))
!(desc->rx_estat & atl_rx_estat_vlan_stripped))
ip_header_offset += sizeof(struct vlan_hdr);
if ((desc->pkt_type & atl_rx_pkt_type_vlan_msk) ==
@ -773,6 +778,9 @@ static int atl_fill_hwts_rx(struct atl_desc_ring *ring, uint32_t count, bool ato
count--;
}
wmb();
atl_write(ring_hw(ring), ATL_RX_RING_TAIL(ring), ring->tail);
return 0;
}
@ -1208,7 +1216,7 @@ int atl_clean_hwts_rx(struct atl_desc_ring *ring, int budget)
uint32_t space = ring_space(ring);
struct atl_rx_desc_hwts_wb *wb;
struct atl_rxbuf *rxbuf;
u64 ns;
u64 ns = 0;
DECLARE_SCRATCH_DESC(scratch);
if (space >= refill_batch)
@ -1389,7 +1397,11 @@ static void atl_calc_affinities(struct atl_nic *nic)
int i;
unsigned int cpu;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
cpus_read_lock();
#else
get_online_cpus();
#endif
cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < nic->nvecs; i++) {
@ -1406,7 +1418,11 @@ static void atl_calc_affinities(struct atl_nic *nic)
cpumask_set_cpu(cpu, cpumask);
cpu = cpumask_next(cpu, cpu_online_mask);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
cpus_read_unlock();
#else
put_online_cpus();
#endif
}
void atl_init_qvec(struct atl_nic *nic, struct atl_queue_vec *qvec, int idx)
@ -2104,9 +2120,15 @@ void atl_stop_rings(struct atl_nic *nic)
int atl_set_features(struct net_device *ndev, netdev_features_t features)
{
netdev_features_t changed = ndev->features ^ features;
struct atl_nic *nic = netdev_priv(ndev);
ndev->features = features;
if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
atl_set_vlan_promisc(&nic->hw,
atl_vlan_promisc_status(ndev));
}
if (changed & NETIF_F_LRO)
atl_set_lro(netdev_priv(ndev));

View file

@ -39,7 +39,7 @@ struct atl_rx_fwd_ring_stats {
struct atl_tx_ring_stats {
uint64_t packets;
uint64_t bytes;
uint64_t tx_busy;
uint64_t tx_busy; /* number of times ring was full and tx failed */
uint64_t tx_restart;
uint64_t dma_map_failed;
};
@ -55,8 +55,8 @@ struct atl_ether_stats {
uint64_t tx_pause;
uint64_t tx_ether_pkts;
uint64_t tx_ether_octets;
uint64_t tx_errors; /* from MSM block */
uint64_t rx_pause;
uint64_t rx_ether_drops;
uint64_t rx_ether_octets;
uint64_t rx_ether_pkts;
uint64_t rx_ether_broacasts;
@ -64,6 +64,13 @@ struct atl_ether_stats {
uint64_t rx_ether_crc_align_errs;
uint64_t rx_filter_host;
uint64_t rx_filter_lost;
uint64_t rx_errors; /* from MSM block */
uint64_t rx_drops; /* from MSM block */
uint64_t rx_dma_packets;
uint64_t rx_dma_octets;
uint64_t rx_dma_drops; /* DMA level RX drops */
uint64_t tx_dma_packets;
uint64_t tx_dma_octets;
};
struct atl_global_stats {

View file

@ -1,3 +1,45 @@
Version 1.1.23
Date 02/11/2021
==============
- Add License headers to atl_dump parser files
- Fixed cpus_read lock/unlock apis for latest kernel
- Fixed the coalescing APIs for the latest kernel
Version 1.1.22
Date 11/10/2021
==============
- Fixed header file and warning complains
Version 1.1.21
Date 29/09/2021
==============
- Atl-fwd: Fix name string for mac_phy stats in ethtool-dump
- Atl-fwd: Minor additions to ethtool dump implementation
- Atl-fwd: Add ethtool-dump parser
- ATLDRV-1776: Fix for link flip during IPA ring reconfig
- Atl-fwd: Update crash-dump structure to fixed size structure
Version 1.1.20
Date 23/08/2021
==============
- Atl-fwd: Correct driver README file and export couple of APIs
- Atl-fwd: Populate Action resolve table and Ring data in the ethtool-dump
- ATLDRV-1766: Fix to update HWTS ring tail value to HW
- Fix error in populating the extended stats
- AQC113 register dump support
- stats+crashdump implementation draft
- Statistics and crash dump API proposal
- factor out fwd stuff to drop headers dependencies
Version 1.1.19
Date 12/07/2021
==============
[ATLDRV-1744] - Add FW version check in Atl-fwd driver
- Move check for PTP UDP packets to separate function, Enable TX pad insert and Handle all FFs in ptp tx TS
[ATLDRV-1582] - Link not Up after FLR reset
[ATLDRV-1653] - Packet with vlan id 1 doesn't get received when rx vlan filter is disabled
[ATLDRV-1659] - Failed to compile with CONFIG_ATLFWD_FWD=y flag on RHEL 8.3 kernel
Version 1.1.18
Date 21/02/2021
==============

View file

@ -1421,7 +1421,6 @@ void cnss_schedule_recovery(struct device *dev,
{
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
struct cnss_recovery_data *data;
int gfp = GFP_KERNEL;
if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
@ -1432,10 +1431,11 @@ void cnss_schedule_recovery(struct device *dev,
return;
}
if (in_interrupt() || irqs_disabled())
gfp = GFP_ATOMIC;
data = kzalloc(sizeof(*data), gfp);
/* Allocating memory always with GFP_ATOMIC flag inside
* cnss_schedule_recovery(). Because there is a chance for
* this api to be invoked in atomic context on some platforms.
*/
data = kzalloc(sizeof(*data), GFP_ATOMIC);
if (!data)
return;

View file

@ -1392,7 +1392,7 @@ static const struct msm_pingroup blair_groups[] = {
[26] = PINGROUP(26, qup13_f1, qup13_f2, NA, NA, NA, NA, NA, NA, NA, 0, -1),
[27] = PINGROUP(27, qup11_f1, qup11_f2, MDP_VSYNC, PLL_BIST, NA, qdss_gpio14,
NA, NA, NA, 0x9C010, 0),
[28] = PINGROUP(28, qup11_f2, qup11_f2, MDP_VSYNC, NA, qdss_gpio15, NA, NA,
[28] = PINGROUP(28, qup11_f1, qup11_f2, MDP_VSYNC, NA, qdss_gpio15, NA, NA,
NA, NA, 0x9C010, 1),
[29] = PINGROUP(29, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA, 0, -1),
[30] = PINGROUP(30, cam_mclk, NA, NA, NA, NA, NA, NA, NA, NA, 0, -1),

View file

@ -31,6 +31,11 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev)
"PCIe V%d: PHY V%d: Initializing 7nm QMP phy - 100MHz\n",
dev->rev, dev->phy_rev);
break;
case 7:
EP_PCIE_DBG(dev,
"PCIe V%d: PHY V%d: Initializing 5nm QMP phy - 100MHz\n",
dev->rev, dev->phy_rev);
break;
default:
EP_PCIE_ERR(dev,
"PCIe V%d: Unexpected phy version %d is caught\n",

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/ipa_fmwk.h>
@ -318,6 +319,35 @@ struct ipa_fmwk_contex {
bool (*ipa_wdi_is_tx1_used)(void);
int (*ipa_wdi_get_capabilities)(struct ipa_wdi_capabilities_out_params *out);
int (*ipa_wdi_init_per_inst)(struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out);
int (*ipa_wdi_cleanup_per_inst)(u32 hdl);
int (*ipa_wdi_reg_intf_per_inst)(
struct ipa_wdi_reg_intf_in_params *in);
int (*ipa_wdi_dereg_intf_per_inst)(const char *netdev_name, u32 hdl);
int (*ipa_wdi_conn_pipes_per_inst)(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out);
int (*ipa_wdi_disconn_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_enable_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_disable_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_set_perf_profile_per_inst)(u32 hdl, struct ipa_wdi_perf_profile *profile);
int (*ipa_wdi_create_smmu_mapping_per_inst)(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info);
int (*ipa_wdi_release_smmu_mapping_per_inst)(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info);
/* ipa_gsb APIs*/
int (*ipa_bridge_init)(struct ipa_bridge_init_params *params, u32 *hdl);
@ -1248,7 +1278,19 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in)
|| ipa_fmwk_ctx->ipa_wdi_get_stats
|| ipa_fmwk_ctx->ipa_get_wdi_version
|| ipa_fmwk_ctx->ipa_wdi_sw_stats
|| ipa_fmwk_ctx->ipa_wdi_is_tx1_used) {
|| ipa_fmwk_ctx->ipa_wdi_is_tx1_used
|| ipa_fmwk_ctx->ipa_wdi_get_capabilities
|| ipa_fmwk_ctx->ipa_wdi_init_per_inst
|| ipa_fmwk_ctx->ipa_wdi_cleanup_per_inst
|| ipa_fmwk_ctx->ipa_wdi_reg_intf_per_inst
|| ipa_fmwk_ctx->ipa_wdi_dereg_intf_per_inst
|| ipa_fmwk_ctx->ipa_wdi_conn_pipes_per_inst
|| ipa_fmwk_ctx->ipa_wdi_disconn_pipes_per_inst
|| ipa_fmwk_ctx->ipa_wdi_enable_pipes_per_inst
|| ipa_fmwk_ctx->ipa_wdi_disable_pipes_per_inst
|| ipa_fmwk_ctx->ipa_wdi_set_perf_profile_per_inst
|| ipa_fmwk_ctx->ipa_wdi_create_smmu_mapping_per_inst
|| ipa_fmwk_ctx->ipa_wdi_release_smmu_mapping_per_inst) {
pr_err("ipa_wdi3 APIs were already initialized\n");
return -EPERM;
}
@ -1271,7 +1313,26 @@ int ipa_fmwk_register_ipa_wdi3(const struct ipa_wdi3_data *in)
ipa_fmwk_ctx->ipa_wdi_sw_stats = in->ipa_wdi_sw_stats;
ipa_fmwk_ctx->ipa_get_wdi_version = in->ipa_get_wdi_version;
ipa_fmwk_ctx->ipa_wdi_is_tx1_used = in->ipa_wdi_is_tx1_used;
ipa_fmwk_ctx->ipa_wdi_get_capabilities = in->ipa_wdi_get_capabilities;
ipa_fmwk_ctx->ipa_wdi_init_per_inst = in->ipa_wdi_init_per_inst;
ipa_fmwk_ctx->ipa_wdi_cleanup_per_inst = in->ipa_wdi_cleanup_per_inst;
ipa_fmwk_ctx->ipa_wdi_reg_intf_per_inst = in->ipa_wdi_reg_intf_per_inst;
ipa_fmwk_ctx->ipa_wdi_dereg_intf_per_inst =
in->ipa_wdi_dereg_intf_per_inst;
ipa_fmwk_ctx->ipa_wdi_conn_pipes_per_inst =
in->ipa_wdi_conn_pipes_per_inst;
ipa_fmwk_ctx->ipa_wdi_disconn_pipes_per_inst =
in->ipa_wdi_disconn_pipes_per_inst;
ipa_fmwk_ctx->ipa_wdi_enable_pipes_per_inst =
in->ipa_wdi_enable_pipes_per_inst;
ipa_fmwk_ctx->ipa_wdi_disable_pipes_per_inst =
in->ipa_wdi_disable_pipes_per_inst;
ipa_fmwk_ctx->ipa_wdi_set_perf_profile_per_inst =
in->ipa_wdi_set_perf_profile_per_inst;
ipa_fmwk_ctx->ipa_wdi_create_smmu_mapping_per_inst =
in->ipa_wdi_create_smmu_mapping_per_inst;
ipa_fmwk_ctx->ipa_wdi_release_smmu_mapping_per_inst =
in->ipa_wdi_release_smmu_mapping_per_inst;
pr_info("ipa_wdi3 registered successfully\n");
return 0;
@ -1411,6 +1472,139 @@ int ipa_wdi_release_smmu_mapping(u32 num_buffers,
}
EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping);
int ipa_wdi_get_capabilities(struct ipa_wdi_capabilities_out_params *out)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_get_capabilities, out);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_get_capabilities);
int ipa_wdi_init_per_inst(struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_init_per_inst,
in, out);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_init_per_inst);
int ipa_wdi_cleanup_per_inst(u32 hdl)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_cleanup_per_inst, hdl);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_cleanup_per_inst);
int ipa_wdi_reg_intf_per_inst(
struct ipa_wdi_reg_intf_in_params *in)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_reg_intf_per_inst,
in);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_reg_intf_per_inst);
int ipa_wdi_dereg_intf_per_inst(const char *netdev_name, u32 hdl)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_dereg_intf_per_inst,
netdev_name, hdl);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_dereg_intf_per_inst);
int ipa_wdi_conn_pipes_per_inst(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_conn_pipes_per_inst,
in, out);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_conn_pipes_per_inst);
int ipa_wdi_disconn_pipes_per_inst(u32 hdl)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_disconn_pipes_per_inst, hdl);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_disconn_pipes_per_inst);
int ipa_wdi_enable_pipes_per_inst(u32 hdl)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_enable_pipes_per_inst, hdl);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_enable_pipes_per_inst);
int ipa_wdi_disable_pipes_per_inst(u32 hdl)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_disable_pipes_per_inst, hdl);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_disable_pipes_per_inst);
int ipa_wdi_set_perf_profile_per_inst(u32 hdl,
struct ipa_wdi_perf_profile *profile)
{
int ret;
IPA_FMWK_DISPATCH_RETURN(ipa_wdi_set_perf_profile_per_inst,
hdl, profile);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_set_perf_profile_per_inst);
int ipa_wdi_create_smmu_mapping_per_inst(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
int ret;
IPA_FMWK_DISPATCH_RETURN_DP(ipa_wdi_create_smmu_mapping_per_inst,
hdl, num_buffers, info);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_create_smmu_mapping_per_inst);
int ipa_wdi_release_smmu_mapping_per_inst(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
int ret;
IPA_FMWK_DISPATCH_RETURN_DP(ipa_wdi_release_smmu_mapping_per_inst,
hdl, num_buffers, info);
return ret;
}
EXPORT_SYMBOL(ipa_wdi_release_smmu_mapping_per_inst);
int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
{
int ret;

View file

@ -372,8 +372,8 @@ static void mhi_dev_event_msi_cb(void *req)
ch->pend_flush_cnt = 0;
mhi = ch->ring->mhi_dev;
mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
ereq->flush_num);
mhi_log(MHI_MSG_VERBOSE, "MSI completed for %s flush req %d\n",
ereq->is_stale ? "stale" : "", ereq->flush_num);
/* Add back the flushed events space to the event buffer */
ch->evt_buf_wp = ereq->start + ereq->num_events;
@ -383,8 +383,11 @@ static void mhi_dev_event_msi_cb(void *req)
spin_lock_irqsave(&mhi->lock, flags);
if (ch->curr_ereq == NULL)
ch->curr_ereq = ereq;
else
else {
if (ereq->is_stale)
ereq->is_stale = false;
list_add_tail(&ereq->list, &ch->event_req_buffers);
}
spin_unlock_irqrestore(&mhi->lock, flags);
}
@ -3256,6 +3259,7 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
struct mhi_dev_channel *ch;
int count = 0;
int rc = 0;
struct event_req *itr, *tmp;
if (!handle) {
mhi_log(MHI_MSG_ERROR, "Invalid channel access:%d\n", -ENODEV);
return;
@ -3291,20 +3295,14 @@ void mhi_dev_close_channel(struct mhi_dev_client *handle)
"Trying to close an active channel (%d)\n",
ch->ch_id);
if (!list_empty(&ch->flush_event_req_buffers)) {
list_for_each_entry_safe(itr, tmp, &ch->flush_event_req_buffers, list) {
itr->is_stale = true;
}
}
ch->state = MHI_DEV_CH_CLOSED;
ch->active_client = NULL;
kfree(ch->ereqs);
mhi_log(MHI_MSG_INFO,
"MEM_DEALLOC:ch:%d size:%d EREQ\n",
ch->ch_id, ch->evt_req_size);
kfree(ch->tr_events);
mhi_log(MHI_MSG_INFO,
"MEM_DEALLOC:ch:%d size:%d TR_EVENTS\n",
ch->ch_id, ch->evt_buf_size);
ch->evt_buf_size = 0;
ch->evt_req_size = 0;
ch->ereqs = NULL;
ch->tr_events = NULL;
kfree(handle);
mhi_log(MHI_MSG_INFO,
"MEM_ALLOC:ch:%d size:%d CLNT_HANDLE\n",
@ -3535,13 +3533,16 @@ int mhi_dev_write_channel(struct mhi_req *wreq)
* Expected usage is when there is a write
* to the MHI core -> notify SM.
*/
mutex_lock(&mhi_ctx->mhi_lock);
mhi_log(MHI_MSG_CRITICAL, "Wakeup by chan:%d\n", ch->ch_id);
rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_CORE_WAKEUP);
if (rc) {
pr_err("error sending core wakeup event\n");
mutex_unlock(&mhi_ctx->mhi_lock);
mutex_unlock(&mhi_ctx->mhi_write_test);
return rc;
}
mutex_unlock(&mhi_ctx->mhi_lock);
}
while (atomic_read(&mhi_ctx->is_suspended) &&

View file

@ -452,6 +452,7 @@ struct event_req {
struct list_head list;
u32 flush_num;
bool is_cmd_cpl;
bool is_stale;
};
struct mhi_cmd_cmpl_ctx {

View file

@ -334,9 +334,15 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
memset_io(data_buf->base, 0, data_buf->size);
data_buf->iova = dma_map_resource(dev, data_buf->phys_base,
data_buf->size, DMA_BIDIRECTIONAL, 0);
if (dma_mapping_error(dev, data_buf->iova))
if (dma_mapping_error(dev, data_buf->iova)) {
log_event_err("%s(): oci_mem: err mapping data_buf\n",
__func__);
iounmap(data_buf->base);
data_buf->base = NULL;
ret = -ENOMEM;
goto err_exit;
}
log_event_dbg("%s: data_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
__func__, dev_name(dev), data_buf->base,
(unsigned long)data_buf->phys_base, data_buf->iova);
@ -348,7 +354,11 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
if (!desc_buf->base) {
log_event_err("%s: ioremap failed for desc fifo\n",
__func__);
dma_unmap_resource(dev, data_buf->iova,
data_buf->size,
DMA_BIDIRECTIONAL, 0);
iounmap(data_buf->base);
data_buf->base = NULL;
ret = -ENOMEM;
goto err_exit;
}
@ -356,9 +366,19 @@ static int usb_bam_alloc_buffer(struct usb_bam_pipe_connect *pipe_connect)
desc_buf->iova = dma_map_resource(dev, desc_buf->phys_base,
desc_buf->size,
DMA_BIDIRECTIONAL, 0);
if (dma_mapping_error(dev, desc_buf->iova))
if (dma_mapping_error(dev, desc_buf->iova)) {
log_event_err("%s(): oci_mem: err mapping desc_buf\n",
__func__);
dma_unmap_resource(dev, data_buf->iova,
data_buf->size,
DMA_BIDIRECTIONAL, 0);
iounmap(data_buf->base);
data_buf->base = NULL;
iounmap(desc_buf->base);
desc_buf->base = NULL;
ret = -ENOMEM;
goto err_exit;
}
log_event_dbg("%s: desc_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
__func__, dev_name(dev), desc_buf->base,

View file

@ -39,6 +39,7 @@ static bool enable_dump =
IS_ENABLED(CONFIG_POWER_RESET_QCOM_DOWNLOAD_MODE_DEFAULT);
static enum qcom_download_mode current_download_mode = QCOM_DOWNLOAD_NODUMP;
static enum qcom_download_mode dump_mode = QCOM_DOWNLOAD_FULLDUMP;
static bool early_pcie_init_enable;
static int set_download_mode(enum qcom_download_mode mode)
{
@ -262,8 +263,10 @@ static int qcom_dload_reboot(struct notifier_block *this, unsigned long event,
set_download_mode(QCOM_DOWNLOAD_NODUMP);
if (cmd) {
if (!strcmp(cmd, "edl"))
set_download_mode(QCOM_DOWNLOAD_EDL);
if (!strcmp(cmd, "edl")) {
early_pcie_init_enable ? set_download_mode(QCOM_EDLOAD_PCI_MODE)
: set_download_mode(QCOM_DOWNLOAD_EDL);
}
else if (!strcmp(cmd, "qcom_dload"))
msm_enable_dump_mode(true);
}
@ -311,6 +314,33 @@ static void store_kaslr_offset(void)
static void store_kaslr_offset(void) {}
#endif /* CONFIG_RANDOMIZE_BASE */
static void check_pci_edl(struct device_node *np)
{
void __iomem *mem;
uint32_t read_val;
int ret_l, ret_h, l, h, mask_value;
mem = of_iomap(np, 0);
if (!mem) {
pr_info("Unable to map memory for DT property: %s\n", np->name);
return;
}
read_val = __raw_readl(mem);
ret_l = of_property_read_u32_index(np, "qcom,boot-config-shift", 0, &l);
ret_h = of_property_read_u32_index(np, "qcom,boot-config-shift", 1, &h);
if (!ret_l && !ret_h) {
mask_value = (read_val >> l) & GENMASK(h - l, 0);
if (mask_value == 5 || mask_value == 7) {
early_pcie_init_enable = true;
pr_info("Setting up EDL mode to PCIE\n");
}
}
iounmap(mem);
}
static int qcom_dload_probe(struct platform_device *pdev)
{
struct qcom_dload *poweroff;
@ -340,6 +370,7 @@ static int qcom_dload_probe(struct platform_device *pdev)
poweroff->dload_dest_addr = map_prop_mem("qcom,msm-imem-dload-type");
store_kaslr_offset();
check_pci_edl(pdev->dev.of_node);
msm_enable_dump_mode(enable_dump);
if (!enable_dump)

View file

@ -1778,14 +1778,17 @@ static int msm_serial_probe(struct platform_device *pdev)
struct uart_port *port;
const struct of_device_id *id;
int irq, line;
bool flag = false;
if (pdev->dev.of_node)
line = of_alias_get_id(pdev->dev.of_node, "serial");
else
line = pdev->id;
if (line < 0)
if (line < 0) {
flag = true;
line = atomic_inc_return(&msm_uart_next_id) - 1;
}
if (unlikely(line < 0 || line >= UART_NR))
return -ENXIO;
@ -1803,26 +1806,40 @@ static int msm_serial_probe(struct platform_device *pdev)
msm_port->is_uartdm = 0;
msm_port->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(msm_port->clk))
if (IS_ERR(msm_port->clk)) {
if (flag)
atomic_dec(&msm_uart_next_id);
return PTR_ERR(msm_port->clk);
}
if (msm_port->is_uartdm) {
msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(msm_port->pclk))
if (IS_ERR(msm_port->pclk)) {
if (flag)
atomic_dec(&msm_uart_next_id);
return PTR_ERR(msm_port->pclk);
}
}
port->uartclk = clk_get_rate(msm_port->clk);
dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk);
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!resource))
if (unlikely(!resource)) {
if (flag)
atomic_dec(&msm_uart_next_id);
return -ENXIO;
}
port->mapbase = resource->start;
irq = platform_get_irq(pdev, 0);
if (unlikely(irq < 0))
if (unlikely(irq < 0)) {
if (flag)
atomic_dec(&msm_uart_next_id);
return -ENXIO;
}
port->irq = irq;
platform_set_drvdata(pdev, port);

View file

@ -78,7 +78,16 @@ int set_qdss_data_connection(struct f_qdss *qdss, int enable)
return -ENOMEM;
}
usb_bam_alloc_fifos(usb_bam_type, idx);
ret = usb_bam_alloc_fifos(usb_bam_type, idx);
if (ret) {
pr_err("%s: usb_bam_alloc_fifos failed(%d)\n",
__func__, ret);
dma_unmap_resource(dev->parent, bam_info.qdss_bam_iova,
bam_info.qdss_bam_size,
DMA_BIDIRECTIONAL, 0);
return ret;
}
bam_info.data_fifo =
kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
if (!bam_info.data_fifo) {

View file

@ -3623,8 +3623,10 @@ sm_done:
spin_unlock_irqrestore(&pd->rx_lock, flags);
/* requeue if there are any new/pending RX messages */
if (!ret && !pd->sm_queued)
if (!ret) {
usbpd_dbg(&pd->dev, "Requeuing new/pending RX messages\n");
kick_sm(pd, 0);
}
if (!pd->sm_queued)
pm_relax(&pd->dev);

View file

@ -50,6 +50,11 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
//Handle HYFI_BRIDGING hooks related stuffs, only if HYFI_BRIDGE_HOOKS is defined
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
struct net_bridge_port;
#endif
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
#ifdef CONFIG_ENABLE_SFE
@ -151,4 +156,11 @@ br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
}
#endif
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
extern br_notify_hook_t __rcu *br_notify_hook;
typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src,
struct sk_buff *skb);
extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook;
#endif
#endif

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 - 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _IPA_FMWK_H_
@ -207,6 +208,35 @@ struct ipa_wdi3_data {
int (*ipa_get_wdi_version)(void);
bool (*ipa_wdi_is_tx1_used)(void);
int (*ipa_wdi_get_capabilities)(struct ipa_wdi_capabilities_out_params *out);
int (*ipa_wdi_init_per_inst)(struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out);
int (*ipa_wdi_cleanup_per_inst)(u32 hdl);
int (*ipa_wdi_reg_intf_per_inst)(
struct ipa_wdi_reg_intf_in_params *in);
int (*ipa_wdi_dereg_intf_per_inst)(const char *netdev_name, u32 hdl);
int (*ipa_wdi_conn_pipes_per_inst)(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out);
int (*ipa_wdi_disconn_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_enable_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_disable_pipes_per_inst)(u32 hdl);
int (*ipa_wdi_set_perf_profile_per_inst)(u32 hdl, struct ipa_wdi_perf_profile *profile);
int (*ipa_wdi_create_smmu_mapping_per_inst)(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info);
int (*ipa_wdi_release_smmu_mapping_per_inst)(u32 hdl, u32 num_buffers,
struct ipa_wdi_buffer_info *info);
};
struct ipa_qdss_data {

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 - 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _IPA_WDI3_H_
@ -19,15 +20,19 @@
#define IPA_WDI_MAX_SUPPORTED_SYS_PIPE 3
typedef u32 ipa_wdi_hdl_t;
enum ipa_wdi_version {
IPA_WDI_1,
IPA_WDI_2,
IPA_WDI_3
IPA_WDI_3,
IPA_WDI_VER_MAX
};
#define IPA_WDI3_TX_DIR 1
#define IPA_WDI3_TX1_DIR 2
#define IPA_WDI3_RX_DIR 3
#define IPA_WDI_INST_MAX (2)
/**
* struct ipa_wdi_init_in_params - wdi init input parameters
@ -43,6 +48,7 @@ struct ipa_wdi_init_in_params {
#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
ipa_wdi_meter_notifier_cb wdi_notify;
#endif
int inst_id;
};
/**
@ -57,6 +63,7 @@ struct ipa_wdi_init_out_params {
bool is_uC_ready;
bool is_smmu_enabled;
bool is_over_gsi;
ipa_wdi_hdl_t hdl;
};
/**
@ -93,6 +100,7 @@ struct ipa_wdi_reg_intf_in_params {
u32 meta_data;
u32 meta_data_mask;
u8 is_tx1_used;
ipa_wdi_hdl_t hdl;
};
/**
@ -208,6 +216,7 @@ struct ipa_wdi_conn_in_params {
struct ipa_wdi_pipe_setup_info tx;
struct ipa_wdi_pipe_setup_info_smmu tx_smmu;
} u_tx1;
ipa_wdi_hdl_t hdl;
};
/**
@ -236,8 +245,30 @@ struct ipa_wdi_perf_profile {
u32 max_supported_bw_mbps;
};
/**
* struct ipa_wdi_capabilities - wdi capability parameters
*
* @num_of_instances: Number of WLAN instances supported.
*/
struct ipa_wdi_capabilities_out_params {
u8 num_of_instances;
};
#if IS_ENABLED(CONFIG_IPA3)
/**
* ipa_wdi_get_capabilities - Client should call this function to
* know the WDI capabilities
*
* Note: Should not be called from atomic context and only
* after checking IPA readiness using ipa_register_ipa_ready_cb()
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_get_capabilities(
struct ipa_wdi_capabilities_out_params *out);
/**
* ipa_wdi_init - Client should call this function to
* init WDI IPA offload data path
@ -256,6 +287,18 @@ int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
*/
bool ipa_wdi_is_tx1_used(void);
/**
* ipa_wdi_init_per_inst - Client should call this function to
* init WDI IPA offload data path
*
* Note: Should not be called from atomic context and only
* after checking IPA readiness using ipa_register_ipa_ready_cb()
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_init_per_inst(struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out);
/**
* ipa_wdi_cleanup - Client should call this function to
* clean up WDI IPA offload data path
@ -264,6 +307,17 @@ bool ipa_wdi_is_tx1_used(void);
*/
int ipa_wdi_cleanup(void);
/**
* ipa_wdi_cleanup_per_inst - Client should call this function to
* clean up WDI IPA offload data path
*
* @hdl: hdl to wdi client
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_cleanup_per_inst(ipa_wdi_hdl_t hdl);
/**
* ipa_wdi_reg_intf - Client should call this function to
* register interface
@ -275,6 +329,17 @@ int ipa_wdi_cleanup(void);
int ipa_wdi_reg_intf(
struct ipa_wdi_reg_intf_in_params *in);
/**
* ipa_wdi_reg_intf_per_inst - Client should call this function to
* register interface
*
* Note: Should not be called from atomic context
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_reg_intf_per_inst(
struct ipa_wdi_reg_intf_in_params *in);
/**
* ipa_wdi_dereg_intf - Client Driver should call this
* function to deregister before unload and after disconnect
@ -283,6 +348,14 @@ int ipa_wdi_reg_intf(
*/
int ipa_wdi_dereg_intf(const char *netdev_name);
/**
* ipa_wdi_dereg_intf_per_inst - Client Driver should call this
* function to deregister before unload and after disconnect
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_dereg_intf_per_inst(const char *netdev_name, ipa_wdi_hdl_t hdl);
/**
* ipa_wdi_conn_pipes - Client should call this
* function to connect pipes
@ -297,6 +370,20 @@ int ipa_wdi_dereg_intf(const char *netdev_name);
int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out);
/**
* ipa_wdi_conn_pipes_per_inst - Client should call this
* function to connect pipes
*
* @in: [in] input parameters from client
* @out: [out] output params to client
*
* Note: Should not be called from atomic context
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_conn_pipes_per_inst(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out);
/**
* ipa_wdi_disconn_pipes() - Client should call this
* function to disconnect pipes
@ -307,6 +394,17 @@ int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
*/
int ipa_wdi_disconn_pipes(void);
/**
* ipa_wdi_disconn_pipes_per_inst() - Client should call this
* function to disconnect pipes
*
* @hdl: hdl to wdi client
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
int ipa_wdi_disconn_pipes_per_inst(ipa_wdi_hdl_t hdl);
/**
* ipa_wdi_enable_pipes() - Client should call this
* function to enable IPA offload data path
@ -317,6 +415,17 @@ int ipa_wdi_disconn_pipes(void);
*/
int ipa_wdi_enable_pipes(void);
/**
* ipa_wdi_enable_pipes_per_inst() - Client should call this
* function to enable IPA offload data path
*
* @hdl: hdl to wdi client
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
int ipa_wdi_enable_pipes_per_inst(ipa_wdi_hdl_t hdl);
/**
* ipa_wdi_disable_pipes() - Client should call this
* function to disable IPA offload data path
@ -327,6 +436,17 @@ int ipa_wdi_enable_pipes(void);
*/
int ipa_wdi_disable_pipes(void);
/**
* ipa_wdi_disable_pipes_per_inst() - Client should call this
* function to disable IPA offload data path
*
* @hdl: hdl to wdi client
* Note: Should not be called from atomic context
*
* Returns: 0 on success, negative on failure
*/
int ipa_wdi_disable_pipes_per_inst(ipa_wdi_hdl_t hdl);
/**
* ipa_wdi_set_perf_profile() - Client should call this function to
* set IPA clock bandwidth based on data rates
@ -337,6 +457,18 @@ int ipa_wdi_disable_pipes(void);
*/
int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile);
/**
* ipa_wdi_set_perf_profile_per_inst() - Client should call this function to
* set IPA clock bandwidth based on data rates
*
* @hdl: hdl to wdi client
* @profile: [in] BandWidth profile to use
*
* Returns: 0 on success, negative on failure
*/
int ipa_wdi_set_perf_profile_per_inst(ipa_wdi_hdl_t hdl,
struct ipa_wdi_perf_profile *profile);
/**
* ipa_wdi_create_smmu_mapping() - Create smmu mapping
*
@ -347,6 +479,17 @@ int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile);
int ipa_wdi_create_smmu_mapping(u32 num_buffers,
struct ipa_wdi_buffer_info *info);
/**
* ipa_wdi_create_smmu_mapping_per_inst() - Create smmu mapping
*
* @hdl: hdl to wdi client
* @num_buffers: number of buffers
* @info: wdi buffer info
*/
int ipa_wdi_create_smmu_mapping_per_inst(ipa_wdi_hdl_t hdl,
u32 num_buffers,
struct ipa_wdi_buffer_info *info);
/**
* ipa_wdi_release_smmu_mapping() - Release smmu mapping
*
@ -357,6 +500,18 @@ int ipa_wdi_create_smmu_mapping(u32 num_buffers,
int ipa_wdi_release_smmu_mapping(u32 num_buffers,
struct ipa_wdi_buffer_info *info);
/**
* ipa_wdi_release_smmu_mapping_per_inst() - Release smmu mapping
*
* @hdl: hdl to wdi client
* @num_buffers: number of buffers
*
* @info: wdi buffer info
*/
int ipa_wdi_release_smmu_mapping_per_inst(ipa_wdi_hdl_t hdl,
u32 num_buffers,
struct ipa_wdi_buffer_info *info);
/**
* ipa_wdi_get_stats() - Query WDI statistics
* @stats: [inout] stats blob from client populated by driver
@ -394,12 +549,34 @@ int ipa_get_wdi_version(void);
#else /* IS_ENABLED(CONFIG_IPA3) */
/**
* ipa_wdi_get_capabilities - Client should call this function to
* know the WDI capabilities
*
* Note: Should not be called from atomic context and only
* after checking IPA readiness using ipa_register_ipa_ready_cb()
*
* @Return 0 on success, negative on failure
*/
int ipa_wdi_get_capabilities(
struct ipa_wdi_capabilities_out_params *out)
{
return -EPERM;
}
static inline int ipa_wdi_init(struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out)
{
return -EPERM;
}
static inline int ipa_wdi_init_per_inst(
struct ipa_wdi_init_in_params *in,
struct ipa_wdi_init_out_params *out)
{
return -EPERM;
}
static inline int ipa_get_wdi_version(void)
{
return -EPERM;
@ -415,56 +592,119 @@ static inline int ipa_wdi_cleanup(void)
return -EPERM;
}
static inline int ipa_wdi_cleanup_per_inst(ipa_wdi_hdl_t hdl)
{
return -EPERM;
}
static inline int ipa_wdi_reg_intf(
struct ipa_wdi_reg_intf_in_params *in)
{
return -EPERM;
}
static inline int ipa_wdi_reg_intf_per_inst(
struct ipa_wdi_reg_intf_in_params *in)
{
return -EPERM;
}
static inline int ipa_wdi_dereg_intf(const char *netdev_name)
{
return -EPERM;
}
static inline int ipa_wdi_dereg_intf_per_inst(const char *netdev_name,
ipa_wdi_hdl_t hdl)
{
return -EPERM;
}
static inline int ipa_wdi_conn_pipes(struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out)
{
return -EPERM;
}
static inline int ipa_wdi_conn_pipes_per_inst(
struct ipa_wdi_conn_in_params *in,
struct ipa_wdi_conn_out_params *out)
{
return -EPERM;
}
static inline int ipa_wdi_disconn_pipes(void)
{
return -EPERM;
}
static inline int ipa_wdi_disconn_pipes_per_inst(ipa_wdi_hdl_t hdl)
{
return -EPERM;
}
static inline int ipa_wdi_enable_pipes(void)
{
return -EPERM;
}
static inline int ipa_wdi_enable_pipes_per_inst(ipa_wdi_hdl_t hdl)
{
return -EPERM;
}
static inline int ipa_wdi_disable_pipes(void)
{
return -EPERM;
}
static inline int ipa_wdi_disable_pipes_per_inst(ipa_wdi_hdl_t hdl)
{
return -EPERM;
}
static inline int ipa_wdi_set_perf_profile(
struct ipa_wdi_perf_profile *profile)
{
return -EPERM;
}
static inline int ipa_wdi_set_perf_profile_per_inst(
ipa_wdi_hdl_t hdl,
struct ipa_wdi_perf_profile *profile)
{
return -EPERM;
}
static inline int ipa_wdi_create_smmu_mapping(u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
return -EPERM;
}
static inline int ipa_wdi_create_smmu_mapping_per_inst(
ipa_wdi_hdl_t hdl,
u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
return -EPERM;
}
static inline int ipa_wdi_release_smmu_mapping(u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
return -EPERM;
}
static inline int ipa_wdi_release_smmu_mapping_per_inst(
ipa_wdi_hdl_t hdl,
u32 num_buffers,
struct ipa_wdi_buffer_info *info)
{
return -EPERM;
}
static inline int ipa_wdi_get_stats(struct IpaHwStatsWDIInfoData_t *stats)
{
return -EPERM;

View file

@ -83,6 +83,8 @@ enum {
NETIF_F_HW_TLS_RECORD_BIT, /* Offload TLS record */
NETIF_F_GRO_FRAGLIST_BIT, /* Fraglist GRO */
NETIF_F_HW_MACSEC_BIT, /* Offload MACsec operations */
/*
* Add your fresh new feature above and remember to update
* netdev_features_strings[] in net/ethtool/common.c and maybe
@ -154,6 +156,7 @@ enum {
#define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX)
#define NETIF_F_GRO_FRAGLIST __NETIF_F(GRO_FRAGLIST)
#define NETIF_F_GSO_FRAGLIST __NETIF_F(GSO_FRAGLIST)
#define NETIF_F_HW_MACSEC __NETIF_F(HW_MACSEC)
/* Finds the next feature with the highest number of the range of start till 0.
*/

View file

@ -54,6 +54,8 @@ struct netpoll_info;
struct device;
struct phy_device;
struct dsa_port;
struct macsec_context;
struct macsec_ops;
struct sfp_bus;
/* 802.11 specific */
@ -1809,6 +1811,8 @@ enum netdev_priv_flags {
*
* @wol_enabled: Wake-on-LAN is enabled
*
* @macsec_ops: MACsec offloading ops
*
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
*/
@ -2100,6 +2104,11 @@ struct net_device {
bool proto_down;
unsigned wol_enabled:1;
#if IS_ENABLED(CONFIG_MACSEC)
/* MACsec management functions */
const struct macsec_ops *macsec_ops;
#endif
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);

View file

@ -17,6 +17,7 @@
enum qcom_download_mode {
QCOM_DOWNLOAD_NODUMP = 0x00,
QCOM_DOWNLOAD_EDL = 0x01,
QCOM_EDLOAD_PCI_MODE = 0X04,
QCOM_DOWNLOAD_FULLDUMP = 0x10,
QCOM_DOWNLOAD_MINIDUMP = 0x20,
};

View file

@ -231,7 +231,10 @@ struct macsec_secy {
* struct macsec_context - MACsec context for hardware offloading
*/
struct macsec_context {
struct phy_device *phydev;
union {
struct net_device *netdev;
struct phy_device *phydev;
};
enum macsec_offload offload;
struct macsec_secy *secy;

View file

@ -14,27 +14,27 @@
TRACE_EVENT(cpu_power_select,
TP_PROTO(int index, u32 sleep_us, u32 latency, u32 next_event_us),
TP_PROTO(int index, u32 sleep_us, u32 latency, u64 sched_bias),
TP_ARGS(index, sleep_us, latency, next_event_us),
TP_ARGS(index, sleep_us, latency, sched_bias),
TP_STRUCT__entry(
__field(int, index)
__field(u32, sleep_us)
__field(u32, latency)
__field(u32, next_event_us)
__field(u64, sched_bias)
),
TP_fast_assign(
__entry->index = index;
__entry->sleep_us = sleep_us;
__entry->latency = latency;
__entry->next_event_us = next_event_us;
__entry->sched_bias = sched_bias;
),
TP_printk("idx:%d sleep_time:%u latency:%u next_event:%u",
TP_printk("idx:%d sleep_time:%u latency:%u sched_bias:%lu",
__entry->index, __entry->sleep_us, __entry->latency,
__entry->next_event_us)
__entry->sched_bias)
);
TRACE_EVENT(cpu_pred_select,

View file

@ -2841,7 +2841,7 @@ struct ipa_move_nat_table_complt_ind_msg_v01 {
#define QMI_IPA_MOVE_NAT_COMPLETE_IND_V01 0x0046
/* add for max length*/
#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 210
#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 197
#define QMI_IPA_INIT_MODEM_DRIVER_RESP_MAX_MSG_LEN_V01 25
#define QMI_IPA_INDICATION_REGISTER_REQ_MAX_MSG_LEN_V01 16
#define QMI_IPA_INDICATION_REGISTER_RESP_MAX_MSG_LEN_V01 7

View file

@ -61,3 +61,15 @@ config BRIDGE_VLAN_FILTERING
Say N to exclude this support and reduce the binary size.
If unsure, say Y.
config HYFI_BRIDGE_HOOKS
bool "Port Hy-Fi Bridging Hooks"
depends on BRIDGE
depends on QGKI
default y
help
If you say Y here, then the Port Hy-Fi Bridging Hooks will be enabled.
Say N to exclude this support.
If unsure, say Y.

View file

@ -394,6 +394,12 @@ static void __exit br_deinit(void)
br_fdb_fini();
}
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
/* Hook for bridge event notifications */
br_notify_hook_t __rcu *br_notify_hook __read_mostly;
EXPORT_SYMBOL(br_notify_hook);
#endif
module_init(br_init)
module_exit(br_deinit)
MODULE_LICENSE("GPL");

View file

@ -81,6 +81,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
if (is_broadcast_ether_addr(dest)) {
br_flood(br, skb, BR_PKT_BROADCAST, false, true);
} else if (is_multicast_ether_addr(dest)) {
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
br_multicast_handle_hook_t *multicast_handle_hook =
rcu_dereference(br_multicast_handle_hook);
if (!__br_get(multicast_handle_hook, true, NULL, skb))
goto out;
#endif
if (unlikely(netpoll_tx_running(dev))) {
br_flood(br, skb, BR_PKT_MULTICAST, false, true);
goto out;

View file

@ -147,6 +147,10 @@ struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
return fdb_find_rcu(&br->fdb_hash_tbl, addr, vid);
}
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
EXPORT_SYMBOL(br_fdb_find_rcu);
#endif
/* When a static FDB entry is added, the mac address from the entry is
* added to the bridge private HW address list and all required ports
* are then updated with the new information.
@ -709,6 +713,9 @@ static void fdb_notify(struct net_bridge *br,
kfree_skb(skb);
goto errout;
}
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
__br_notify(RTNLGRP_NEIGH, type, fdb);
#endif
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
return;
errout:

View file

@ -29,7 +29,13 @@ br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
return netif_receive_skb(skb);
}
static int br_pass_frame_up(struct sk_buff *skb)
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
/* Hook for external Multicast handler */
br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly;
EXPORT_SYMBOL(br_multicast_handle_hook);
#endif
int br_pass_frame_up(struct sk_buff *skb)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
@ -66,6 +72,10 @@ static int br_pass_frame_up(struct sk_buff *skb)
br_netif_receive_skb);
}
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
EXPORT_SYMBOL(br_pass_frame_up);
#endif
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
@ -75,6 +85,9 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
struct net_bridge_mdb_entry *mdst;
bool local_rcv, mcast_hit = false;
struct net_bridge *br;
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
br_multicast_handle_hook_t *multicast_handle_hook;
#endif
u16 vid = 0;
if (!p || p->state == BR_STATE_DISABLED)
@ -128,6 +141,11 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
switch (pkt_type) {
case BR_PKT_MULTICAST:
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
multicast_handle_hook = rcu_dereference(br_multicast_handle_hook);
if (!__br_get(multicast_handle_hook, true, p, skb))
goto out;
#endif
mdst = br_mdb_get(br, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb))) {

View file

@ -499,6 +499,9 @@ void br_ifinfo_notify(int event, const struct net_bridge *br,
kfree_skb(skb);
goto errout;
}
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
__br_notify(RTNLGRP_LINK, event, port);
#endif
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
return;
errout:

View file

@ -18,6 +18,9 @@
#include <linux/if_vlan.h>
#include <linux/rhashtable.h>
#include <linux/refcount.h>
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
#include <linux/export.h>
#endif
#define BR_HASH_BITS 8
#define BR_HASH_SIZE (1 << BR_HASH_BITS)
@ -625,6 +628,9 @@ void br_manage_promisc(struct net_bridge *br);
int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev);
/* br_input.c */
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
int br_pass_frame_up(struct sk_buff *skb);
#endif
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
rx_handler_result_t br_handle_frame(struct sk_buff **pskb);
@ -1266,4 +1272,17 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br,
void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
u16 vid, struct net_bridge_port *p, struct nd_msg *msg);
struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m);
#ifdef CONFIG_HYFI_BRIDGE_HOOKS
#define __br_get(__hook, __default, __args ...) \
({ typeof(__hook) HOOK_ = (__hook); \
(HOOK_ ? (HOOK_(__args)) : (__default)); })
static inline void __br_notify(int group, int type, const void *data)
{
br_notify_hook_t *notify_hook = rcu_dereference(br_notify_hook);
if (notify_hook)
notify_hook(group, type, data);
}
#endif
#endif

View file

@ -112,6 +112,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_HW_TLS_RECORD_BIT] = "tls-hw-record",
[NETIF_F_HW_TLS_TX_BIT] = "tls-hw-tx-offload",
[NETIF_F_HW_TLS_RX_BIT] = "tls-hw-rx-offload",
[NETIF_F_HW_MACSEC_BIT] = "macsec-hw-offload",
};
static const char