Ping? > Le 24 août 2020 à 12:38, Thibaut VARÈNE <ha...@slashdirt.org> a écrit : > > MikroTik recently changed again the way they store wlan calibration data > on devices. Prior to this change, ERD calibration data for all available > radios was stored within a single identifier node ("tag" in RouterBoot > parlance). > > Recent devices have been seen with calibration (and BDF) data stored in > separate identifiers within LZOR packing for each radio: this patch > addresses this by: > 1) ensuring that both variants are properly supported, > 2) preserving backward compatibility with existing data consumers, > 3) allowing for more than 2 calibration blobs to be exposed via sysfs. > > Specifically, before this patch, the driver would provide a single sysfs > file named /sys/firmware/mikrotik/hard_config/wlan_data that contained > whatever calibration data found on the device's flash. After this patch, > when executed on a device that uses the old style storage, this behavior > is unchanged, but when executed on a device that uses new style storage > (for either traditional "ERD" packing or "LZOR" packing), the driver > replaces that single file with a folder containing one or more files > each containing the data encoded within individual identifiers. > > As far as OpenWRT is concerned, this means that for devices which are > known to exist with both styles of data storage, a suitable hotplug stub > could look like this for e.g. the second radio: > > wdata="/sys/firmware/mikrotik/hard_config/wlan_data" > ( [ -f "$wdata" ] && caldata_sysfsload_from_file "$wdata" 0x8000 0x2f20 ) || \ > ( [ -d "$wdata" ] && caldata_sysfsload_from_file "$wdata/data_2" 0x0 0x2f20 ) > > This patch has been tested with LZOR old and new style packing on ipq4019, > and with old style on ath79. > > Tested-by: John Thomson <g...@johnthomson.fastmail.com.au> > Tested-by: Шебанов Алексей <ad...@ublaze.ru> > Tested-by: Alen Opačić <subixonf...@gmail.com> > Signed-off-by: Thibaut VARÈNE <ha...@slashdirt.org> > --- > .../drivers/platform/mikrotik/rb_hardconfig.c | 139 +++++++++++++----- > 1 file changed, 106 insertions(+), 33 deletions(-) > > diff --git > a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c > b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c > index 8861814be4..41dea98b5e 100644 > --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c > +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c > @@ -39,7 +39,7 @@ > > #include "routerboot.h" > > -#define RB_HARDCONFIG_VER "0.05" > +#define RB_HARDCONFIG_VER "0.06" > #define RB_HC_PR_PFX "[rb_hardconfig] " > > /* ID values for hardware settings */ > @@ -76,6 +76,17 @@ > #define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22) > #define RB_HW_OPT_HAS_PLC BIT(29) > > +/* > + * Tag ID values for ERD data. > + * Mikrotik used to pack all calibration data under a single tag id 0x1, but > + * recently switched to a new scheme where each radio calibration gets a > + * separate tag. The new scheme has tag id bit 15 always set and seems to be > + * mutually exclusive with the old scheme. > + */ > +#define RB_WLAN_ERD_ID_SOLO 0x0001 > +#define RB_WLAN_ERD_ID_MULTI_8001 0x8001 > +#define RB_WLAN_ERD_ID_MULTI_8201 0x8201 > + > static struct kobject *hc_kobj; > static u8 *hc_buf; // ro buffer after init(): no locking required > static size_t hc_buflen; > @@ -351,10 +362,22 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, > struct kobject *kobj, > loff_t off, size_t count); > > static struct hc_wlan_attr { > + const u16 erd_tag_id; > struct bin_attribute battr; > u16 pld_ofs; > u16 pld_len; > -} hc_wlandata_battr = { > +} hc_wd_multi_battrs[] = { > + { > + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001, > + .battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, > NULL, 0), > + }, { > + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201, > + .battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, > NULL, 0), > + } > +}; > + > +static struct hc_wlan_attr hc_wd_solo_battr = { > + .erd_tag_id = RB_WLAN_ERD_ID_SOLO, > .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), > }; > > @@ -426,19 +449,19 @@ static struct hc_attr { > /* > * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past > * that magic number the payload itself contains a routerboot tag node > - * locating the LZO-compressed calibration data at id 0x1. > + * locating the LZO-compressed calibration data. So far this scheme is only > + * known to use a single tag at id 0x1. > */ > -static int hc_wlan_data_unpack_erd(const u8 *inbuf, size_t inlen, > +static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t > inlen, > void *outbuf, size_t *outlen) > { > u16 lzo_ofs, lzo_len; > int ret; > > /* Find embedded tag */ > - ret = routerboot_tag_find(inbuf, inlen, 0x1, // always id 1 > - &lzo_ofs, &lzo_len); > + ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len); > if (ret) { > - pr_debug(RB_HC_PR_PFX "ERD data not found\n"); > + pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id); > goto fail; > } > > @@ -461,10 +484,10 @@ fail: > * that magic number is a payload that must be appended to the hc_lzor_prefix, > * the resulting blob is LZO-compressed. In the LZO decompression result, > * the RB_MAGIC_ERD magic number (aligned) must be located. Following that > - * magic, there is a routerboot tag node (id 0x1) locating the RLE-encoded > + * magic, there is one or more routerboot tag node(s) locating the > RLE-encoded > * calibration data payload. > */ > -static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen, > +static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, > size_t inlen, > void *outbuf, size_t *outlen) > { > u16 rle_ofs, rle_len; > @@ -492,10 +515,8 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, > size_t inlen, > if (ret) { > if (LZO_E_INPUT_NOT_CONSUMED == ret) { > /* > - * The tag length appears to always be aligned (probably > - * because it is the "root" RB_ID_WLAN_DATA tag), thus > - * the LZO payload may be padded, which can trigger a > - * spurious error which we ignore here. > + * The tag length is always aligned thus the LZO > payload may be padded, > + * which can trigger a spurious error which we ignore > here. > */ > pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end > - this may be harmless\n"); > } else { > @@ -520,9 +541,9 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, > size_t inlen, > templen -= (u8 *)needle - tempbuf; > > /* Past magic. Look for tag node */ > - ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, > &rle_len); > + ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, > &rle_len); > if (ret) { > - pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n"); > + pr_debug(RB_HC_PR_PFX "LZOR: no RLE data for id 0x%04x\n", > tag_id); > goto fail; > } > > @@ -542,7 +563,7 @@ fail: > return ret; > } > > -static int hc_wlan_data_unpack(const size_t tofs, size_t tlen, > +static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t > tlen, > void *outbuf, size_t *outlen) > { > const u8 *lbuf; > @@ -562,23 +583,25 @@ static int hc_wlan_data_unpack(const size_t tofs, > size_t tlen, > /* Skip magic */ > lbuf += sizeof(magic); > tlen -= sizeof(magic); > - ret = hc_wlan_data_unpack_lzor(lbuf, tlen, outbuf, outlen); > + ret = hc_wlan_data_unpack_lzor(tag_id, lbuf, tlen, outbuf, > outlen); > break; > case RB_MAGIC_ERD: > /* Skip magic */ > lbuf += sizeof(magic); > tlen -= sizeof(magic); > - ret = hc_wlan_data_unpack_erd(lbuf, tlen, outbuf, outlen); > + ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, > outlen); > break; > default: > /* > * If the RB_ID_WLAN_DATA payload doesn't start with a > * magic number, the payload itself is the raw RLE-encoded > - * calibration data. > + * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here. > */ > - ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen); > - if (ret) > - pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); > + if (RB_WLAN_ERD_ID_SOLO == tag_id) { > + ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen); > + if (ret) > + pr_debug(RB_HC_PR_PFX "RLE decoding error > (%d)\n", ret); > + } > break; > } > > @@ -633,7 +656,7 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, > struct kobject *kobj, > if (!outbuf) > return -ENOMEM; > > - ret = hc_wlan_data_unpack(hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, > &outlen); > + ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, > hc_wattr->pld_len, outbuf, &outlen); > if (ret) { > kfree(outbuf); > return ret; > @@ -655,14 +678,17 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, > struct kobject *kobj, > > int __init rb_hardconfig_init(struct kobject *rb_kobj) > { > + struct kobject *hc_wlan_kobj; > struct mtd_info *mtd; > - size_t bytes_read, buflen; > + size_t bytes_read, buflen, outlen; > const u8 *buf; > - int i, ret; > + void *outbuf; > + int i, j, ret; > u32 magic; > > hc_buf = NULL; > hc_kobj = NULL; > + hc_wlan_kobj = NULL; > > // TODO allow override > mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG); > @@ -713,15 +739,62 @@ int __init rb_hardconfig_init(struct kobject *rb_kobj) > /* Account for skipped magic */ > hc_attrs[i].pld_ofs += sizeof(magic); > > - /* Special case RB_ID_WLAN_DATA to prep and create the binary > attribute */ > + /* > + * Special case RB_ID_WLAN_DATA to prep and create the binary > attribute. > + * We first check if the data is "old style" within a single > tag (or no tag at all): > + * If it is we publish this single blob as a binary attribute > child of hc_kobj to > + * preserve backward compatibility. > + * If it isn't and instead uses multiple ERD tags, we create a > subfolder and > + * publish the known ones there. > + */ > if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && > hc_attrs[i].pld_len) { > - hc_wlandata_battr.pld_ofs = hc_attrs[i].pld_ofs; > - hc_wlandata_battr.pld_len = hc_attrs[i].pld_len; > - > - ret = sysfs_create_bin_file(hc_kobj, > &hc_wlandata_battr.battr); > - if (ret) > - pr_warn(RB_HC_PR_PFX "Could not create %s sysfs > entry (%d)\n", > - hc_wlandata_battr.battr.attr.name, ret); > + outlen = RB_ART_SIZE; > + outbuf = kmalloc(outlen, GFP_KERNEL); > + if (!outbuf) { > + pr_warn(RB_HC_PR_PFX "Out of memory parsing > WLAN tag\n"); > + continue; > + } > + > + /* Test ID_SOLO first, if found: done */ > + ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, > hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); > + if (!ret) { > + hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs; > + hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len; > + > + ret = sysfs_create_bin_file(hc_kobj, > &hc_wd_solo_battr.battr); > + if (ret) > + pr_warn(RB_HC_PR_PFX "Could not create > %s sysfs entry (%d)\n", > + > hc_wd_solo_battr.battr.attr.name, ret); > + } > + /* Otherwise, create "wlan_data" subtree and publish > known data */ > + else { > + hc_wlan_kobj = > kobject_create_and_add("wlan_data", hc_kobj); > + if (!hc_wlan_kobj) { > + kfree(outbuf); > + pr_warn(RB_HC_PR_PFX "Could not create > wlan_data sysfs folder\n"); > + continue; > + } > + > + for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); > j++) { > + outlen = RB_ART_SIZE; > + ret = > hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id, > + > hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); > + if (ret) { > + hc_wd_multi_battrs[j].pld_ofs = > hc_wd_multi_battrs[j].pld_len = 0; > + continue; > + } > + > + hc_wd_multi_battrs[j].pld_ofs = > hc_attrs[i].pld_ofs; > + hc_wd_multi_battrs[j].pld_len = > hc_attrs[i].pld_len; > + > + ret = > sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr); > + if (ret) > + pr_warn(RB_HC_PR_PFX "Could not > create wlan_data/%s sysfs entry (%d)\n", > + > hc_wd_multi_battrs[j].battr.attr.name, ret); > + } > + } > + > + kfree(outbuf); > } > /* All other tags are published via standard attributes */ > else { > -- > 2.24.3 (Apple Git-128) >
_______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/mailman/listinfo/openwrt-devel