mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-02-12 19:31:52 +00:00
Update Linux 5.4 kernel and clean some files
This commit is contained in:
parent
272324aa1a
commit
0a55523ea5
26 changed files with 870 additions and 4059 deletions
6
build.sh
6
build.sh
|
@ -94,9 +94,9 @@ fi
|
|||
if [ "$OMR_OPENWRT" = "default" ]; then
|
||||
if [ "$OMR_KERNEL" = "5.4" ]; then
|
||||
# Use OpenWrt 21.02 for 5.4 kernel
|
||||
_get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "f441be3921c769b732f0148f005d4f1bbace0508"
|
||||
_get_repo feeds/packages https://github.com/openwrt/packages "ab94e0709a9c796d34d723ddba44380f7b3d8698"
|
||||
_get_repo feeds/luci https://github.com/openwrt/luci "0818d835cacd9fa75b8685aabe6378ac09b95145"
|
||||
_get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "864bba55d8714a64abdf94cfb835450b8cd7789e"
|
||||
_get_repo feeds/packages https://github.com/openwrt/packages "793e7ee484ae4ec37b1cd920b4032dde3cae69cc"
|
||||
_get_repo feeds/luci https://github.com/openwrt/luci "701ea947fc920e63d14d8efb8287097fd63442ca"
|
||||
else
|
||||
_get_repo "$OMR_TARGET/source" https://github.com/openwrt/openwrt "02de391b086dd2b7a72c2394cfb66cec666a51c1"
|
||||
_get_repo feeds/packages https://github.com/openwrt/packages "7b2dd3e9efbc20ef4e7f47f60c3db9aaef37c0a5"
|
||||
|
|
|
@ -6,12 +6,13 @@ ifdef CONFIG_TESTING_KERNEL
|
|||
KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER)
|
||||
endif
|
||||
|
||||
LINUX_VERSION-5.4 = .132
|
||||
LINUX_VERSION-5.4 = .182
|
||||
LINUX_VERSION-5.10 = .64
|
||||
LINUX_VERSION-5.14 = .6
|
||||
LINUX_VERSION-5.15 = .17
|
||||
|
||||
LINUX_KERNEL_HASH-5.4.132 = 8466adbfb3579e751ede683496df7bb20f258b5f882250f3dd82be63736d00ef
|
||||
LINUX_KERNEL_HASH-5.4.182 = b2f1201f64f010e9e3c85d6f303a559a7944a80a0244a86b8f5035bd23f1f40d
|
||||
LINUX_KERNEL_HASH-5.10.64 = 3eb84bd24a2de2b4749314e34597c02401c5d6831b055ed5224adb405c35e30a
|
||||
LINUX_KERNEL_HASH-5.14.6 = 54848c1268771ee3515e4c33e29abc3f1fa90d8144894cce6d0ebc3b158bccec
|
||||
LINUX_KERNEL_HASH-5.15.4 = 549d0fb75e65f6158e6f4becc648f249d386843da0e1211460bde8b1ea99cbca
|
||||
|
|
8
root/package/network/wwan/files/data/05c6-9215
Normal file
8
root/package/network/wwan/files/data/05c6-9215
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"desc": "Quectel EC20",
|
||||
"type": "gobinet",
|
||||
"control": 2,
|
||||
"boudrate": 115200,
|
||||
"stop_bits": 8,
|
||||
"gps": 1
|
||||
}
|
11
root/package/network/wwan/files/data/2c7c-0121
Normal file
11
root/package/network/wwan/files/data/2c7c-0121
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"desc": "Quectel EC21",
|
||||
"type": "gobinet",
|
||||
"control": 2,
|
||||
"boudrate": 115200,
|
||||
"stop_bits": 8,
|
||||
"gps": 1,
|
||||
"ep_iface": 4,
|
||||
"dl_max_size": 4096,
|
||||
"dl_max_datagrams": 16
|
||||
}
|
11
root/package/network/wwan/files/data/2c7c-0296
Normal file
11
root/package/network/wwan/files/data/2c7c-0296
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"desc": "Quectel BG96",
|
||||
"type": "gobinet",
|
||||
"control": 3,
|
||||
"boudrate": 115200,
|
||||
"stop_bits": 8,
|
||||
"gps": 1,
|
||||
"ep_iface": 4,
|
||||
"dl_max_size": 2048,
|
||||
"dl_max_datagrams": 8
|
||||
}
|
11
root/package/network/wwan/files/data/2c7c-0306
Normal file
11
root/package/network/wwan/files/data/2c7c-0306
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"desc": "Quectel EG06",
|
||||
"type": "gobinet",
|
||||
"control": 2,
|
||||
"boudrate": 115200,
|
||||
"stop_bits": 8,
|
||||
"gps": 1,
|
||||
"ep_iface": 4,
|
||||
"dl_max_size": 16384,
|
||||
"dl_max_datagrams": 32
|
||||
}
|
11
root/package/network/wwan/files/data/2c7c-0512
Normal file
11
root/package/network/wwan/files/data/2c7c-0512
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"desc": "Quectel EG12/EG18",
|
||||
"type": "gobinet",
|
||||
"control": 2,
|
||||
"boudrate": 115200,
|
||||
"stop_bits": 8,
|
||||
"gps": 1,
|
||||
"ep_iface": 4,
|
||||
"dl_max_size": 16384,
|
||||
"dl_max_datagrams": 32
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,53 +0,0 @@
|
|||
From: Bui Quang Minh @ 2021-01-26 8:26 UTC (permalink / raw)
|
||||
To: ast, daniel, davem, kuba, hawk, john.fastabend, andrii, kafai,
|
||||
songliubraving, yhs, kpsingh, jakub, lmb
|
||||
Cc: netdev, bpf, linux-kernel, minhquangbui99
|
||||
|
||||
In 32-bit architecture, the result of sizeof() is a 32-bit integer so
|
||||
the expression becomes the multiplication between 2 32-bit integer which
|
||||
can potentially leads to integer overflow. As a result,
|
||||
bpf_map_area_alloc() allocates less memory than needed.
|
||||
|
||||
Fix this by casting 1 operand to u64.
|
||||
|
||||
Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
|
||||
---
|
||||
kernel/bpf/devmap.c | 4 ++--
|
||||
net/core/sock_map.c | 2 +-
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
Index: linux-5.4.147/kernel/bpf/devmap.c
|
||||
===================================================================
|
||||
--- linux-5.4.147.orig/kernel/bpf/devmap.c
|
||||
+++ linux-5.4.147/kernel/bpf/devmap.c
|
||||
@@ -94,7 +94,7 @@ static struct hlist_head *dev_map_create
|
||||
int i;
|
||||
struct hlist_head *hash;
|
||||
|
||||
- hash = bpf_map_area_alloc(entries * sizeof(*hash), numa_node);
|
||||
+ hash = bpf_map_area_alloc((u64) entries * sizeof(*hash), numa_node);
|
||||
if (hash != NULL)
|
||||
for (i = 0; i < entries; i++)
|
||||
INIT_HLIST_HEAD(&hash[i]);
|
||||
@@ -159,7 +159,7 @@ static int dev_map_init_map(struct bpf_d
|
||||
|
||||
spin_lock_init(&dtab->index_lock);
|
||||
} else {
|
||||
- dtab->netdev_map = bpf_map_area_alloc(dtab->map.max_entries *
|
||||
+ dtab->netdev_map = bpf_map_area_alloc((u64) dtab->map.max_entries *
|
||||
sizeof(struct bpf_dtab_netdev *),
|
||||
dtab->map.numa_node);
|
||||
if (!dtab->netdev_map)
|
||||
Index: linux-5.4.147/net/core/sock_map.c
|
||||
===================================================================
|
||||
--- linux-5.4.147.orig/net/core/sock_map.c
|
||||
+++ linux-5.4.147/net/core/sock_map.c
|
||||
@@ -48,7 +48,7 @@ static struct bpf_map *sock_map_alloc(un
|
||||
if (err)
|
||||
goto free_stab;
|
||||
|
||||
- stab->sks = bpf_map_area_alloc(stab->map.max_entries *
|
||||
+ stab->sks = bpf_map_area_alloc((u64) stab->map.max_entries *
|
||||
sizeof(struct sock *),
|
||||
stab->map.numa_node);
|
||||
if (stab->sks)
|
|
@ -1,115 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 13 Jun 2018 12:33:39 +0200
|
||||
Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout
|
||||
corner case
|
||||
|
||||
The full teardown of offloaded flows is deferred to a gc work item,
|
||||
however processing of packets by netfilter needs to happen immediately
|
||||
after a teardown is requested, because the conntrack state needs to be
|
||||
fixed up.
|
||||
|
||||
Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete,
|
||||
the netfilter conntrack gc can accidentally bump the timeout of a
|
||||
connection where offload was just stopped, causing a conntrack entry
|
||||
leak.
|
||||
|
||||
Fix this by moving the conntrack timeout bumping from conntrack core to
|
||||
the nf_flow_offload and add a check to prevent bogus timeout bumps.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_core.c
|
||||
+++ b/net/netfilter/nf_conntrack_core.c
|
||||
@@ -1207,18 +1207,6 @@ static bool gc_worker_can_early_drop(con
|
||||
return false;
|
||||
}
|
||||
|
||||
-#define DAY (86400 * HZ)
|
||||
-
|
||||
-/* Set an arbitrary timeout large enough not to ever expire, this save
|
||||
- * us a check for the IPS_OFFLOAD_BIT from the packet path via
|
||||
- * nf_ct_is_expired().
|
||||
- */
|
||||
-static void nf_ct_offload_timeout(struct nf_conn *ct)
|
||||
-{
|
||||
- if (nf_ct_expires(ct) < DAY / 2)
|
||||
- ct->timeout = nfct_time_stamp + DAY;
|
||||
-}
|
||||
-
|
||||
static void gc_worker(struct work_struct *work)
|
||||
{
|
||||
unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION;
|
||||
@@ -1250,11 +1238,9 @@ static void gc_worker(struct work_struct
|
||||
|
||||
tmp = nf_ct_tuplehash_to_ctrack(h);
|
||||
|
||||
scanned++;
|
||||
- if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
|
||||
- nf_ct_offload_timeout(tmp);
|
||||
+ if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
|
||||
continue;
|
||||
- }
|
||||
|
||||
if (nf_ct_is_expired(tmp)) {
|
||||
nf_ct_gc_expired(tmp);
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -198,10 +198,29 @@ static const struct rhashtable_params nf
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
+#define DAY (86400 * HZ)
|
||||
+
|
||||
+/* Set an arbitrary timeout large enough not to ever expire, this save
|
||||
+ * us a check for the IPS_OFFLOAD_BIT from the packet path via
|
||||
+ * nf_ct_is_expired().
|
||||
+ */
|
||||
+static void nf_ct_offload_timeout(struct flow_offload *flow)
|
||||
+{
|
||||
+ struct flow_offload_entry *entry;
|
||||
+ struct nf_conn *ct;
|
||||
+
|
||||
+ entry = container_of(flow, struct flow_offload_entry, flow);
|
||||
+ ct = entry->ct;
|
||||
+
|
||||
+ if (nf_ct_expires(ct) < DAY / 2)
|
||||
+ ct->timeout = nfct_time_stamp + DAY;
|
||||
+}
|
||||
+
|
||||
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
|
||||
{
|
||||
int err;
|
||||
|
||||
+ nf_ct_offload_timeout(flow);
|
||||
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
|
||||
|
||||
err = rhashtable_insert_fast(&flow_table->rhashtable,
|
||||
@@ -304,6 +323,7 @@ nf_flow_table_iterate(struct nf_flowtabl
|
||||
rhashtable_walk_start(&hti);
|
||||
|
||||
while ((tuplehash = rhashtable_walk_next(&hti))) {
|
||||
+
|
||||
if (IS_ERR(tuplehash)) {
|
||||
if (PTR_ERR(tuplehash) != -EAGAIN) {
|
||||
err = PTR_ERR(tuplehash);
|
||||
@@ -328,10 +348,17 @@ static void nf_flow_offload_gc_step(stru
|
||||
{
|
||||
struct nf_flowtable *flow_table = data;
|
||||
struct flow_offload_entry *e;
|
||||
+ bool teardown;
|
||||
|
||||
e = container_of(flow, struct flow_offload_entry, flow);
|
||||
- if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) ||
|
||||
- (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN)))
|
||||
+
|
||||
+ teardown = flow->flags & (FLOW_OFFLOAD_DYING |
|
||||
+ FLOW_OFFLOAD_TEARDOWN);
|
||||
+
|
||||
+ if (!teardown)
|
||||
+ nf_ct_offload_timeout(flow);
|
||||
+
|
||||
+ if (nf_flow_has_expired(flow) || teardown)
|
||||
flow_offload_del(flow_table, flow);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,554 @@
|
|||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Thu, 11 Jan 2018 16:32:00 +0100
|
||||
Subject: [PATCH] netfilter: nf_flow_table: add hardware offload support
|
||||
|
||||
This patch adds the infrastructure to offload flows to hardware, in case
|
||||
the nic/switch comes with built-in flow tables capabilities.
|
||||
|
||||
If the hardware comes with no hardware flow tables or they have
|
||||
limitations in terms of features, the existing infrastructure falls back
|
||||
to the software flow table implementation.
|
||||
|
||||
The software flow table garbage collector skips entries that resides in
|
||||
the hardware, so the hardware will be responsible for releasing this
|
||||
flow table entry too via flow_offload_dead().
|
||||
|
||||
Hardware configuration, either to add or to delete entries, is done from
|
||||
the hardware offload workqueue, to ensure this is done from user context
|
||||
given that we may sleep when grabbing the mdio mutex.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
create mode 100644 net/netfilter/nf_flow_table_hw.c
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -922,6 +922,13 @@ struct devlink;
|
||||
struct tlsdev_ops;
|
||||
|
||||
|
||||
+struct flow_offload;
|
||||
+
|
||||
+enum flow_offload_type {
|
||||
+ FLOW_OFFLOAD_ADD = 0,
|
||||
+ FLOW_OFFLOAD_DEL,
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* This structure defines the management hooks for network devices.
|
||||
* The following hooks can be defined; unless noted otherwise, they are
|
||||
@@ -1154,6 +1161,10 @@ struct tlsdev_ops;
|
||||
* int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
|
||||
* u16 flags);
|
||||
*
|
||||
+ * int (*ndo_flow_offload)(enum flow_offload_type type,
|
||||
+ * struct flow_offload *flow);
|
||||
+ * Adds/deletes flow entry to/from net device flowtable.
|
||||
+ *
|
||||
* int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
|
||||
* Called to change device carrier. Soft-devices (like dummy, team, etc)
|
||||
* which do not represent real hardware may define this to allow their
|
||||
@@ -1401,6 +1412,8 @@ struct net_device_ops {
|
||||
int (*ndo_bridge_dellink)(struct net_device *dev,
|
||||
struct nlmsghdr *nlh,
|
||||
u16 flags);
|
||||
+ int (*ndo_flow_offload)(enum flow_offload_type type,
|
||||
+ struct flow_offload *flow);
|
||||
int (*ndo_change_carrier)(struct net_device *dev,
|
||||
bool new_carrier);
|
||||
int (*ndo_get_phys_port_id)(struct net_device *dev,
|
||||
--- a/include/net/netfilter/nf_flow_table.h
|
||||
+++ b/include/net/netfilter/nf_flow_table.h
|
||||
@@ -21,11 +21,17 @@ struct nf_flowtable_type {
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
+enum nf_flowtable_flags {
|
||||
+ NF_FLOWTABLE_F_HW = 0x1,
|
||||
+};
|
||||
+
|
||||
struct nf_flowtable {
|
||||
struct list_head list;
|
||||
struct rhashtable rhashtable;
|
||||
const struct nf_flowtable_type *type;
|
||||
+ u32 flags;
|
||||
struct delayed_work gc_work;
|
||||
+ possible_net_t ft_net;
|
||||
};
|
||||
|
||||
enum flow_offload_tuple_dir {
|
||||
@@ -68,6 +74,7 @@ struct flow_offload_tuple_rhash {
|
||||
#define FLOW_OFFLOAD_DNAT 0x2
|
||||
#define FLOW_OFFLOAD_DYING 0x4
|
||||
#define FLOW_OFFLOAD_TEARDOWN 0x8
|
||||
+#define FLOW_OFFLOAD_HW 0x10
|
||||
|
||||
struct flow_offload {
|
||||
struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
|
||||
@@ -120,6 +127,22 @@ unsigned int nf_flow_offload_ip_hook(voi
|
||||
unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state);
|
||||
|
||||
+void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
|
||||
+ struct nf_conn *ct);
|
||||
+void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow);
|
||||
+
|
||||
+struct nf_flow_table_hw {
|
||||
+ struct module *owner;
|
||||
+ void (*add)(struct net *net, struct flow_offload *flow,
|
||||
+ struct nf_conn *ct);
|
||||
+ void (*del)(struct net *net, struct flow_offload *flow);
|
||||
+};
|
||||
+
|
||||
+int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
|
||||
+void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
|
||||
+
|
||||
+extern struct work_struct nf_flow_offload_hw_work;
|
||||
+
|
||||
#define MODULE_ALIAS_NF_FLOWTABLE(family) \
|
||||
MODULE_ALIAS("nf-flowtable-" __stringify(family))
|
||||
|
||||
--- a/include/uapi/linux/netfilter/nf_tables.h
|
||||
+++ b/include/uapi/linux/netfilter/nf_tables.h
|
||||
@@ -1516,6 +1516,7 @@ enum nft_object_attributes {
|
||||
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
|
||||
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
|
||||
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
|
||||
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
|
||||
*/
|
||||
enum nft_flowtable_attributes {
|
||||
NFTA_FLOWTABLE_UNSPEC,
|
||||
@@ -1525,6 +1526,7 @@ enum nft_flowtable_attributes {
|
||||
NFTA_FLOWTABLE_USE,
|
||||
NFTA_FLOWTABLE_HANDLE,
|
||||
NFTA_FLOWTABLE_PAD,
|
||||
+ NFTA_FLOWTABLE_FLAGS,
|
||||
__NFTA_FLOWTABLE_MAX
|
||||
};
|
||||
#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -711,6 +711,15 @@ config NF_FLOW_TABLE
|
||||
|
||||
To compile it as a module, choose M here.
|
||||
|
||||
+config NF_FLOW_TABLE_HW
|
||||
+ tristate "Netfilter flow table hardware offload module"
|
||||
+ depends on NF_FLOW_TABLE
|
||||
+ help
|
||||
+ This option adds hardware offload support for the flow table core
|
||||
+ infrastructure.
|
||||
+
|
||||
+ To compile it as a module, choose M here.
|
||||
+
|
||||
config NETFILTER_XTABLES
|
||||
tristate "Netfilter Xtables support (required for ip_tables)"
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -123,6 +123,7 @@ obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_t
|
||||
nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o
|
||||
|
||||
obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
|
||||
+obj-$(CONFIG_NF_FLOW_TABLE_HW) += nf_flow_table_hw.o
|
||||
|
||||
# generic X tables
|
||||
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -248,10 +248,16 @@ static inline bool nf_flow_has_expired(c
|
||||
return nf_flow_timeout_delta(flow->timeout) <= 0;
|
||||
}
|
||||
|
||||
+static inline bool nf_flow_in_hw(const struct flow_offload *flow)
|
||||
+{
|
||||
+ return flow->flags & FLOW_OFFLOAD_HW;
|
||||
+}
|
||||
+
|
||||
static void flow_offload_del(struct nf_flowtable *flow_table,
|
||||
struct flow_offload *flow)
|
||||
{
|
||||
struct flow_offload_entry *e;
|
||||
+ struct net *net = read_pnet(&flow_table->ft_net);
|
||||
|
||||
rhashtable_remove_fast(&flow_table->rhashtable,
|
||||
&flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
|
||||
@@ -271,6 +277,9 @@ static void flow_offload_del(struct nf_f
|
||||
if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
|
||||
flow_offload_fixup_ct_state(e->ct);
|
||||
|
||||
+ if (nf_flow_in_hw(flow))
|
||||
+ nf_flow_offload_hw_del(net, flow);
|
||||
+
|
||||
flow_offload_free(flow);
|
||||
}
|
||||
|
||||
@@ -490,10 +502,43 @@ int nf_flow_dnat_port(const struct flow_
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
|
||||
|
||||
+static const struct nf_flow_table_hw __rcu *nf_flow_table_hw_hook __read_mostly;
|
||||
+
|
||||
+static int nf_flow_offload_hw_init(struct nf_flowtable *flow_table)
|
||||
+{
|
||||
+ const struct nf_flow_table_hw *offload;
|
||||
+
|
||||
+ if (!rcu_access_pointer(nf_flow_table_hw_hook))
|
||||
+ request_module("nf-flow-table-hw");
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ offload = rcu_dereference(nf_flow_table_hw_hook);
|
||||
+ if (!offload)
|
||||
+ goto err_no_hw_offload;
|
||||
+
|
||||
+ if (!try_module_get(offload->owner))
|
||||
+ goto err_no_hw_offload;
|
||||
+
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_no_hw_offload:
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+
|
||||
int nf_flow_table_init(struct nf_flowtable *flowtable)
|
||||
{
|
||||
int err;
|
||||
|
||||
+ if (flowtable->flags & NF_FLOWTABLE_F_HW) {
|
||||
+ err = nf_flow_offload_hw_init(flowtable);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
|
||||
|
||||
err = rhashtable_init(&flowtable->rhashtable,
|
||||
@@ -534,6 +579,8 @@ static void nf_flow_table_iterate_cleanu
|
||||
{
|
||||
nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
|
||||
flush_delayed_work(&flowtable->gc_work);
|
||||
+ if (flowtable->flags & NF_FLOWTABLE_F_HW)
|
||||
+ flush_work(&nf_flow_offload_hw_work);
|
||||
}
|
||||
|
||||
void nf_flow_table_cleanup(struct net_device *dev)
|
||||
@@ -547,6 +594,26 @@ void nf_flow_table_cleanup(struct net_de
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
|
||||
|
||||
+struct work_struct nf_flow_offload_hw_work;
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_work);
|
||||
+
|
||||
+/* Give the hardware workqueue the chance to remove entries from hardware.*/
|
||||
+static void nf_flow_offload_hw_free(struct nf_flowtable *flowtable)
|
||||
+{
|
||||
+ const struct nf_flow_table_hw *offload;
|
||||
+
|
||||
+ flush_work(&nf_flow_offload_hw_work);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ offload = rcu_dereference(nf_flow_table_hw_hook);
|
||||
+ if (!offload) {
|
||||
+ rcu_read_unlock();
|
||||
+ return;
|
||||
+ }
|
||||
+ module_put(offload->owner);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
void nf_flow_table_free(struct nf_flowtable *flow_table)
|
||||
{
|
||||
mutex_lock(&flowtable_lock);
|
||||
@@ -556,9 +623,58 @@ void nf_flow_table_free(struct nf_flowta
|
||||
nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
|
||||
nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, flow_table);
|
||||
rhashtable_destroy(&flow_table->rhashtable);
|
||||
+ if (flow_table->flags & NF_FLOWTABLE_F_HW)
|
||||
+ nf_flow_offload_hw_free(flow_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_free);
|
||||
|
||||
+/* Must be called from user context. */
|
||||
+void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
|
||||
+ struct nf_conn *ct)
|
||||
+{
|
||||
+ const struct nf_flow_table_hw *offload;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ offload = rcu_dereference(nf_flow_table_hw_hook);
|
||||
+ if (offload)
|
||||
+ offload->add(net, flow, ct);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_add);
|
||||
+
|
||||
+/* Must be called from user context. */
|
||||
+void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow)
|
||||
+{
|
||||
+ const struct nf_flow_table_hw *offload;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ offload = rcu_dereference(nf_flow_table_hw_hook);
|
||||
+ if (offload)
|
||||
+ offload->del(net, flow);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_del);
|
||||
+
|
||||
+int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload)
|
||||
+{
|
||||
+ if (rcu_access_pointer(nf_flow_table_hw_hook))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ rcu_assign_pointer(nf_flow_table_hw_hook, offload);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_table_hw_register);
|
||||
+
|
||||
+void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload)
|
||||
+{
|
||||
+ WARN_ON(rcu_access_pointer(nf_flow_table_hw_hook) != offload);
|
||||
+ rcu_assign_pointer(nf_flow_table_hw_hook, NULL);
|
||||
+
|
||||
+ synchronize_rcu();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_table_hw_unregister);
|
||||
+
|
||||
static int nf_flow_table_netdev_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
--- /dev/null
|
||||
+++ b/net/netfilter/nf_flow_table_hw.c
|
||||
@@ -0,0 +1,169 @@
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/netfilter.h>
|
||||
+#include <linux/rhashtable.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <net/netfilter/nf_flow_table.h>
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_core.h>
|
||||
+#include <net/netfilter/nf_conntrack_tuple.h>
|
||||
+
|
||||
+static DEFINE_SPINLOCK(flow_offload_hw_pending_list_lock);
|
||||
+static LIST_HEAD(flow_offload_hw_pending_list);
|
||||
+
|
||||
+static DEFINE_MUTEX(nf_flow_offload_hw_mutex);
|
||||
+
|
||||
+struct flow_offload_hw {
|
||||
+ struct list_head list;
|
||||
+ enum flow_offload_type type;
|
||||
+ struct flow_offload *flow;
|
||||
+ struct nf_conn *ct;
|
||||
+ possible_net_t flow_hw_net;
|
||||
+};
|
||||
+
|
||||
+static int do_flow_offload_hw(struct net *net, struct flow_offload *flow,
|
||||
+ int type)
|
||||
+{
|
||||
+ struct net_device *indev;
|
||||
+ int ret, ifindex;
|
||||
+
|
||||
+ ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
|
||||
+ indev = dev_get_by_index(net, ifindex);
|
||||
+ if (WARN_ON(!indev))
|
||||
+ return 0;
|
||||
+
|
||||
+ mutex_lock(&nf_flow_offload_hw_mutex);
|
||||
+ ret = indev->netdev_ops->ndo_flow_offload(type, flow);
|
||||
+ mutex_unlock(&nf_flow_offload_hw_mutex);
|
||||
+
|
||||
+ dev_put(indev);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_hw_work_add(struct flow_offload_hw *offload)
|
||||
+{
|
||||
+ struct net *net;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (nf_ct_is_dying(offload->ct))
|
||||
+ return;
|
||||
+
|
||||
+ net = read_pnet(&offload->flow_hw_net);
|
||||
+ ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD);
|
||||
+ if (ret >= 0)
|
||||
+ offload->flow->flags |= FLOW_OFFLOAD_HW;
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_hw_work_del(struct flow_offload_hw *offload)
|
||||
+{
|
||||
+ struct net *net = read_pnet(&offload->flow_hw_net);
|
||||
+
|
||||
+ do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL);
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_hw_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct flow_offload_hw *offload, *next;
|
||||
+ LIST_HEAD(hw_offload_pending);
|
||||
+
|
||||
+ spin_lock_bh(&flow_offload_hw_pending_list_lock);
|
||||
+ list_replace_init(&flow_offload_hw_pending_list, &hw_offload_pending);
|
||||
+ spin_unlock_bh(&flow_offload_hw_pending_list_lock);
|
||||
+
|
||||
+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
|
||||
+ switch (offload->type) {
|
||||
+ case FLOW_OFFLOAD_ADD:
|
||||
+ flow_offload_hw_work_add(offload);
|
||||
+ break;
|
||||
+ case FLOW_OFFLOAD_DEL:
|
||||
+ flow_offload_hw_work_del(offload);
|
||||
+ break;
|
||||
+ }
|
||||
+ if (offload->ct)
|
||||
+ nf_conntrack_put(&offload->ct->ct_general);
|
||||
+ list_del(&offload->list);
|
||||
+ kfree(offload);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_queue_work(struct flow_offload_hw *offload)
|
||||
+{
|
||||
+ spin_lock_bh(&flow_offload_hw_pending_list_lock);
|
||||
+ list_add_tail(&offload->list, &flow_offload_hw_pending_list);
|
||||
+ spin_unlock_bh(&flow_offload_hw_pending_list_lock);
|
||||
+
|
||||
+ schedule_work(&nf_flow_offload_hw_work);
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_hw_add(struct net *net, struct flow_offload *flow,
|
||||
+ struct nf_conn *ct)
|
||||
+{
|
||||
+ struct flow_offload_hw *offload;
|
||||
+
|
||||
+ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
|
||||
+ if (!offload)
|
||||
+ return;
|
||||
+
|
||||
+ nf_conntrack_get(&ct->ct_general);
|
||||
+ offload->type = FLOW_OFFLOAD_ADD;
|
||||
+ offload->ct = ct;
|
||||
+ offload->flow = flow;
|
||||
+ write_pnet(&offload->flow_hw_net, net);
|
||||
+
|
||||
+ flow_offload_queue_work(offload);
|
||||
+}
|
||||
+
|
||||
+static void flow_offload_hw_del(struct net *net, struct flow_offload *flow)
|
||||
+{
|
||||
+ struct flow_offload_hw *offload;
|
||||
+
|
||||
+ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
|
||||
+ if (!offload)
|
||||
+ return;
|
||||
+
|
||||
+ offload->type = FLOW_OFFLOAD_DEL;
|
||||
+ offload->ct = NULL;
|
||||
+ offload->flow = flow;
|
||||
+ write_pnet(&offload->flow_hw_net, net);
|
||||
+
|
||||
+ flow_offload_queue_work(offload);
|
||||
+}
|
||||
+
|
||||
+static const struct nf_flow_table_hw flow_offload_hw = {
|
||||
+ .add = flow_offload_hw_add,
|
||||
+ .del = flow_offload_hw_del,
|
||||
+ .owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static int __init nf_flow_table_hw_module_init(void)
|
||||
+{
|
||||
+ INIT_WORK(&nf_flow_offload_hw_work, flow_offload_hw_work);
|
||||
+ nf_flow_table_hw_register(&flow_offload_hw);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __exit nf_flow_table_hw_module_exit(void)
|
||||
+{
|
||||
+ struct flow_offload_hw *offload, *next;
|
||||
+ LIST_HEAD(hw_offload_pending);
|
||||
+
|
||||
+ nf_flow_table_hw_unregister(&flow_offload_hw);
|
||||
+ cancel_work_sync(&nf_flow_offload_hw_work);
|
||||
+
|
||||
+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
|
||||
+ if (offload->ct)
|
||||
+ nf_conntrack_put(&offload->ct->ct_general);
|
||||
+ list_del(&offload->list);
|
||||
+ kfree(offload);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+module_init(nf_flow_table_hw_module_init);
|
||||
+module_exit(nf_flow_table_hw_module_exit);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||
+MODULE_ALIAS("nf-flow-table-hw");
|
||||
--- a/net/netfilter/nf_tables_api.c
|
||||
+++ b/net/netfilter/nf_tables_api.c
|
||||
@@ -5743,6 +5743,13 @@ static int nf_tables_flowtable_parse_hoo
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
+ for (i = 0; i < n; i++) {
|
||||
+ if (flowtable->data.flags & NF_FLOWTABLE_F_HW &&
|
||||
+ !dev_array[i]->netdev_ops->ndo_flow_offload) {
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
ops = kcalloc(n, sizeof(struct nf_hook_ops), GFP_KERNEL);
|
||||
if (!ops)
|
||||
return -ENOMEM;
|
||||
@@ -5873,10 +5880,19 @@ static int nf_tables_newflowtable(struct
|
||||
}
|
||||
|
||||
flowtable->data.type = type;
|
||||
+ write_pnet(&flowtable->data.ft_net, net);
|
||||
+
|
||||
err = type->init(&flowtable->data);
|
||||
if (err < 0)
|
||||
goto err3;
|
||||
|
||||
+ if (nla[NFTA_FLOWTABLE_FLAGS]) {
|
||||
+ flowtable->data.flags =
|
||||
+ ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
|
||||
+ if (flowtable->data.flags & ~NF_FLOWTABLE_F_HW)
|
||||
+ goto err4;
|
||||
+ }
|
||||
+
|
||||
err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK],
|
||||
flowtable);
|
||||
if (err < 0)
|
||||
@@ -6002,7 +6018,8 @@ static int nf_tables_fill_flowtable_info
|
||||
nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
|
||||
nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
|
||||
nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
|
||||
- NFTA_FLOWTABLE_PAD))
|
||||
+ NFTA_FLOWTABLE_PAD) ||
|
||||
+ nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags)))
|
||||
goto nla_put_failure;
|
||||
|
||||
nest = nla_nest_start_noflag(skb, NFTA_FLOWTABLE_HOOK);
|
||||
--- a/net/netfilter/nft_flow_offload.c
|
||||
+++ b/net/netfilter/nft_flow_offload.c
|
||||
@@ -128,6 +128,9 @@ static void nft_flow_offload_eval(const
|
||||
if (ret < 0)
|
||||
goto err_flow_add;
|
||||
|
||||
+ if (flowtable->flags & NF_FLOWTABLE_F_HW)
|
||||
+ nf_flow_offload_hw_add(nft_net(pkt), flow, ct);
|
||||
+
|
||||
dst_release(route.tuple[!dir].dst);
|
||||
return;
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 26 Jul 2020 14:03:21 +0200
|
||||
Subject: [PATCH] net: add support for threaded NAPI polling
|
||||
|
||||
For some drivers (especially 802.11 drivers), doing a lot of work in the NAPI
|
||||
poll function does not perform well. Since NAPI poll is bound to the CPU it
|
||||
was scheduled from, we can easily end up with a few very busy CPUs spending
|
||||
most of their time in softirq/ksoftirqd and some idle ones.
|
||||
|
||||
Introduce threaded NAPI for such drivers based on a workqueue. The API is the
|
||||
same except for using netif_threaded_napi_add instead of netif_napi_add.
|
||||
|
||||
In my tests with mt76 on MT7621 using threaded NAPI + a thread for tx scheduling
|
||||
improves LAN->WLAN bridging throughput by 10-50%. Throughput without threaded
|
||||
NAPI is wildly inconsistent, depending on the CPU that runs the tx scheduling
|
||||
thread.
|
||||
|
||||
With threaded NAPI it seems stable and consistent (and higher than the best
|
||||
results I got without it).
|
||||
|
||||
Based on a patch by Hillf Danton
|
||||
|
||||
Cc: Hillf Danton <hdanton@sina.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -340,6 +340,7 @@ struct napi_struct {
|
||||
struct list_head dev_list;
|
||||
struct hlist_node napi_hash_node;
|
||||
unsigned int napi_id;
|
||||
+ struct work_struct work;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -350,6 +351,7 @@ enum {
|
||||
NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */
|
||||
NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
|
||||
NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
|
||||
+ NAPI_STATE_THREADED, /* Use threaded NAPI */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -360,6 +362,7 @@ enum {
|
||||
NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED),
|
||||
NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
|
||||
NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
|
||||
+ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED),
|
||||
};
|
||||
|
||||
enum gro_result {
|
||||
@@ -2101,6 +2104,7 @@ struct net_device {
|
||||
struct lock_class_key addr_list_lock_key;
|
||||
bool proto_down;
|
||||
unsigned wol_enabled:1;
|
||||
+ unsigned threaded:1;
|
||||
};
|
||||
#define to_net_dev(d) container_of(d, struct net_device, dev)
|
||||
|
||||
@@ -2281,6 +2285,26 @@ void netif_napi_add(struct net_device *d
|
||||
int (*poll)(struct napi_struct *, int), int weight);
|
||||
|
||||
/**
|
||||
+ * netif_threaded_napi_add - initialize a NAPI context
|
||||
+ * @dev: network device
|
||||
+ * @napi: NAPI context
|
||||
+ * @poll: polling function
|
||||
+ * @weight: default weight
|
||||
+ *
|
||||
+ * This variant of netif_napi_add() should be used from drivers using NAPI
|
||||
+ * with CPU intensive poll functions.
|
||||
+ * This will schedule polling from a high priority workqueue
|
||||
+ */
|
||||
+static inline void netif_threaded_napi_add(struct net_device *dev,
|
||||
+ struct napi_struct *napi,
|
||||
+ int (*poll)(struct napi_struct *, int),
|
||||
+ int weight)
|
||||
+{
|
||||
+ set_bit(NAPI_STATE_THREADED, &napi->state);
|
||||
+ netif_napi_add(dev, napi, poll, weight);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* netif_tx_napi_add - initialize a NAPI context
|
||||
* @dev: network device
|
||||
* @napi: NAPI context
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -156,6 +156,7 @@ static DEFINE_SPINLOCK(offload_lock);
|
||||
struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
|
||||
struct list_head ptype_all __read_mostly; /* Taps */
|
||||
static struct list_head offload_base __read_mostly;
|
||||
+static struct workqueue_struct *napi_workq __read_mostly;
|
||||
|
||||
static int netif_rx_internal(struct sk_buff *skb);
|
||||
static int call_netdevice_notifiers_info(unsigned long val,
|
||||
@@ -5931,6 +5932,11 @@ void __napi_schedule(struct napi_struct
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
|
||||
+ queue_work(napi_workq, &n->work);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
local_irq_save(flags);
|
||||
____napi_schedule(this_cpu_ptr(&softnet_data), n);
|
||||
local_irq_restore(flags);
|
||||
@@ -6246,9 +6256,89 @@ static void init_gro_hash(struct napi_st
|
||||
napi->gro_bitmask = 0;
|
||||
}
|
||||
|
||||
+static int __napi_poll(struct napi_struct *n, bool *repoll)
|
||||
+{
|
||||
+ int work, weight;
|
||||
+
|
||||
+ weight = n->weight;
|
||||
+
|
||||
+ /* This NAPI_STATE_SCHED test is for avoiding a race
|
||||
+ * with netpoll's poll_napi(). Only the entity which
|
||||
+ * obtains the lock and sees NAPI_STATE_SCHED set will
|
||||
+ * actually make the ->poll() call. Therefore we avoid
|
||||
+ * accidentally calling ->poll() when NAPI is not scheduled.
|
||||
+ */
|
||||
+ work = 0;
|
||||
+ if (test_bit(NAPI_STATE_SCHED, &n->state)) {
|
||||
+ work = n->poll(n, weight);
|
||||
+ trace_napi_poll(n, work, weight);
|
||||
+ }
|
||||
+
|
||||
+ WARN_ON_ONCE(work > weight);
|
||||
+
|
||||
+ if (likely(work < weight))
|
||||
+ return work;
|
||||
+
|
||||
+ /* Drivers must not modify the NAPI state if they
|
||||
+ * consume the entire weight. In such cases this code
|
||||
+ * still "owns" the NAPI instance and therefore can
|
||||
+ * move the instance around on the list at-will.
|
||||
+ */
|
||||
+ if (unlikely(napi_disable_pending(n))) {
|
||||
+ napi_complete(n);
|
||||
+ return work;
|
||||
+ }
|
||||
+
|
||||
+ if (n->gro_bitmask) {
|
||||
+ /* flush too old packets
|
||||
+ * If HZ < 1000, flush all packets.
|
||||
+ */
|
||||
+ napi_gro_flush(n, HZ >= 1000);
|
||||
+ }
|
||||
+
|
||||
+ gro_normal_list(n);
|
||||
+
|
||||
+ *repoll = true;
|
||||
+
|
||||
+ return work;
|
||||
+}
|
||||
+
|
||||
+static void napi_workfn(struct work_struct *work)
|
||||
+{
|
||||
+ struct napi_struct *n = container_of(work, struct napi_struct, work);
|
||||
+ void *have;
|
||||
+
|
||||
+ for (;;) {
|
||||
+ bool repoll = false;
|
||||
+
|
||||
+ local_bh_disable();
|
||||
+
|
||||
+ have = netpoll_poll_lock(n);
|
||||
+ __napi_poll(n, &repoll);
|
||||
+ netpoll_poll_unlock(have);
|
||||
+
|
||||
+ local_bh_enable();
|
||||
+
|
||||
+ if (!repoll)
|
||||
+ return;
|
||||
+
|
||||
+ if (!need_resched())
|
||||
+ continue;
|
||||
+
|
||||
+ /*
|
||||
+ * have to pay for the latency of task switch even if
|
||||
+ * napi is scheduled
|
||||
+ */
|
||||
+ queue_work(napi_workq, work);
|
||||
+ return;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
|
||||
int (*poll)(struct napi_struct *, int), int weight)
|
||||
{
|
||||
+ if (dev->threaded)
|
||||
+ set_bit(NAPI_STATE_THREADED, &napi->state);
|
||||
INIT_LIST_HEAD(&napi->poll_list);
|
||||
hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
|
||||
napi->timer.function = napi_watchdog;
|
||||
@@ -6265,6 +6355,7 @@ void netif_napi_add(struct net_device *d
|
||||
#ifdef CONFIG_NETPOLL
|
||||
napi->poll_owner = -1;
|
||||
#endif
|
||||
+ INIT_WORK(&napi->work, napi_workfn);
|
||||
set_bit(NAPI_STATE_SCHED, &napi->state);
|
||||
set_bit(NAPI_STATE_NPSVC, &napi->state);
|
||||
list_add_rcu(&napi->dev_list, &dev->napi_list);
|
||||
@@ -6305,6 +6396,7 @@ static void flush_gro_hash(struct napi_s
|
||||
void netif_napi_del(struct napi_struct *napi)
|
||||
{
|
||||
might_sleep();
|
||||
+ cancel_work_sync(&napi->work);
|
||||
if (napi_hash_del(napi))
|
||||
synchronize_net();
|
||||
list_del_init(&napi->dev_list);
|
||||
@@ -6317,50 +6409,18 @@ EXPORT_SYMBOL(netif_napi_del);
|
||||
|
||||
static int napi_poll(struct napi_struct *n, struct list_head *repoll)
|
||||
{
|
||||
+ bool do_repoll = false;
|
||||
void *have;
|
||||
- int work, weight;
|
||||
+ int work;
|
||||
|
||||
list_del_init(&n->poll_list);
|
||||
|
||||
have = netpoll_poll_lock(n);
|
||||
|
||||
- weight = n->weight;
|
||||
-
|
||||
- /* This NAPI_STATE_SCHED test is for avoiding a race
|
||||
- * with netpoll's poll_napi(). Only the entity which
|
||||
- * obtains the lock and sees NAPI_STATE_SCHED set will
|
||||
- * actually make the ->poll() call. Therefore we avoid
|
||||
- * accidentally calling ->poll() when NAPI is not scheduled.
|
||||
- */
|
||||
- work = 0;
|
||||
- if (test_bit(NAPI_STATE_SCHED, &n->state)) {
|
||||
- work = n->poll(n, weight);
|
||||
- trace_napi_poll(n, work, weight);
|
||||
- }
|
||||
-
|
||||
- WARN_ON_ONCE(work > weight);
|
||||
+ work = __napi_poll(n, &do_repoll);
|
||||
|
||||
- if (likely(work < weight))
|
||||
- goto out_unlock;
|
||||
-
|
||||
- /* Drivers must not modify the NAPI state if they
|
||||
- * consume the entire weight. In such cases this code
|
||||
- * still "owns" the NAPI instance and therefore can
|
||||
- * move the instance around on the list at-will.
|
||||
- */
|
||||
- if (unlikely(napi_disable_pending(n))) {
|
||||
- napi_complete(n);
|
||||
+ if (!do_repoll)
|
||||
goto out_unlock;
|
||||
- }
|
||||
-
|
||||
- if (n->gro_bitmask) {
|
||||
- /* flush too old packets
|
||||
- * If HZ < 1000, flush all packets.
|
||||
- */
|
||||
- napi_gro_flush(n, HZ >= 1000);
|
||||
- }
|
||||
-
|
||||
- gro_normal_list(n);
|
||||
|
||||
/* Some drivers may have called napi_schedule
|
||||
* prior to exhausting their budget.
|
||||
@@ -10340,6 +10400,10 @@ static int __init net_dev_init(void)
|
||||
sd->backlog.weight = weight_p;
|
||||
}
|
||||
|
||||
+ napi_workq = alloc_workqueue("napi_workq", WQ_UNBOUND | WQ_HIGHPRI,
|
||||
+ WQ_UNBOUND_MAX_ACTIVE | WQ_SYSFS);
|
||||
+ BUG_ON(!napi_workq);
|
||||
+
|
||||
dev_boot_phase = 0;
|
||||
|
||||
/* The loopback device is special if any other network devices
|
||||
--- a/net/core/net-sysfs.c
|
||||
+++ b/net/core/net-sysfs.c
|
||||
@@ -442,6 +442,52 @@ static ssize_t proto_down_store(struct d
|
||||
}
|
||||
NETDEVICE_SHOW_RW(proto_down, fmt_dec);
|
||||
|
||||
+static int change_napi_threaded(struct net_device *dev, unsigned long val)
|
||||
+{
|
||||
+ struct napi_struct *napi;
|
||||
+
|
||||
+ if (list_empty(&dev->napi_list))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
|
||||
+ if (val)
|
||||
+ set_bit(NAPI_STATE_THREADED, &napi->state);
|
||||
+ else
|
||||
+ clear_bit(NAPI_STATE_THREADED, &napi->state);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t napi_threaded_store(struct device *dev,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return netdev_store(dev, attr, buf, len, change_napi_threaded);
|
||||
+}
|
||||
+
|
||||
+static ssize_t napi_threaded_show(struct device *dev,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_device *netdev = to_net_dev(dev);
|
||||
+ struct napi_struct *napi;
|
||||
+ bool enabled = false;
|
||||
+
|
||||
+ if (!rtnl_trylock())
|
||||
+ return restart_syscall();
|
||||
+
|
||||
+ list_for_each_entry(napi, &netdev->napi_list, dev_list) {
|
||||
+ if (test_bit(NAPI_STATE_THREADED, &napi->state))
|
||||
+ enabled = true;
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ return sprintf(buf, fmt_dec, enabled);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(napi_threaded);
|
||||
+
|
||||
static ssize_t phys_port_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -532,6 +578,7 @@ static struct attribute *net_class_attrs
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_tx_queue_len.attr,
|
||||
&dev_attr_gro_flush_timeout.attr,
|
||||
+ &dev_attr_napi_threaded.attr,
|
||||
&dev_attr_phys_port_id.attr,
|
||||
&dev_attr_phys_port_name.attr,
|
||||
&dev_attr_phys_switch_id.attr,
|
|
@ -1,57 +0,0 @@
|
|||
From 63e4b45c82ed1bde979da7052229a4229ce9cabf Mon Sep 17 00:00:00 2001
|
||||
From: Georgi Valkov <gvalkov@abv.bg>
|
||||
Date: Tue, 1 Feb 2022 08:16:18 +0100
|
||||
Subject: ipheth: fix EOVERFLOW in ipheth_rcvbulk_callback
|
||||
|
||||
When rx_buf is allocated we need to account for IPHETH_IP_ALIGN,
|
||||
which reduces the usable size by 2 bytes. Otherwise we have 1512
|
||||
bytes usable instead of 1514, and if we receive more than 1512
|
||||
bytes, ipheth_rcvbulk_callback is called with status -EOVERFLOW,
|
||||
after which the driver malfunctiones and all communication stops.
|
||||
|
||||
Resolves ipheth 2-1:4.2: ipheth_rcvbulk_callback: urb status: -75
|
||||
|
||||
Fixes: f33d9e2b48a3 ("usbnet: ipheth: fix connectivity with iOS 14")
|
||||
Signed-off-by: Georgi Valkov <gvalkov@abv.bg>
|
||||
Tested-by: Jan Kiszka <jan.kiszka@siemens.com>
|
||||
Link: https://lore.kernel.org/all/B60B8A4B-92A0-49B3-805D-809A2433B46C@abv.bg/
|
||||
Link: https://lore.kernel.org/all/24851bd2769434a5fc24730dce8e8a984c5a4505.1643699778.git.jan.kiszka@siemens.com/
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
drivers/net/usb/ipheth.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
|
||||
index cd33955df0b65f..6a769df0b4213c 100644
|
||||
--- a/drivers/net/usb/ipheth.c
|
||||
+++ b/drivers/net/usb/ipheth.c
|
||||
@@ -121,7 +121,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone)
|
||||
if (tx_buf == NULL)
|
||||
goto free_rx_urb;
|
||||
|
||||
- rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
|
||||
+ rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
|
||||
GFP_KERNEL, &rx_urb->transfer_dma);
|
||||
if (rx_buf == NULL)
|
||||
goto free_tx_buf;
|
||||
@@ -146,7 +146,7 @@ error_nomem:
|
||||
|
||||
static void ipheth_free_urbs(struct ipheth_device *iphone)
|
||||
{
|
||||
- usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
|
||||
+ usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf,
|
||||
iphone->rx_urb->transfer_dma);
|
||||
usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
|
||||
iphone->tx_urb->transfer_dma);
|
||||
@@ -317,7 +317,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
|
||||
|
||||
usb_fill_bulk_urb(dev->rx_urb, udev,
|
||||
usb_rcvbulkpipe(udev, dev->bulk_in),
|
||||
- dev->rx_buf, IPHETH_BUF_SIZE,
|
||||
+ dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN,
|
||||
ipheth_rcvbulk_callback,
|
||||
dev);
|
||||
dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
--
|
||||
cgit
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/sh /etc/rc.common
|
||||
# (C) 2013 openwrt.org
|
||||
|
||||
START=81
|
||||
|
||||
boot() {
|
||||
SHA_ALGS="sha1-neon sha224-neon sha256-neon sha384-neon sha512-neon md5-generic"
|
||||
|
||||
for alg in $SHA_ALGS; do
|
||||
crconf add driver "authenc(hmac($alg),cbc(aes-generic))" type 3
|
||||
crconf add driver "pcrypt(authenc(hmac($alg),cbc(aes-generic)))" type 3
|
||||
done
|
||||
|
||||
for alg in $SHA_ALGS; do
|
||||
crconf add driver "authenc(hmac($alg),cbc(des3_ede-generic))" type 3
|
||||
crconf add driver "pcrypt(authenc(hmac($alg),cbc(des3_ede-generic)))" type 3
|
||||
done
|
||||
}
|
||||
|
||||
start() {
|
||||
return 0
|
||||
}
|
||||
|
||||
restart() {
|
||||
return 0
|
||||
}
|
||||
|
||||
stop() {
|
||||
return 0
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
# Copyright (C) 2019 OpenWrt.org
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/system.sh
|
||||
|
||||
caldata_dd() {
|
||||
local source=$1
|
||||
local target=$2
|
||||
local count=$(($3))
|
||||
local offset=$(($4))
|
||||
|
||||
dd if=$source of=$target iflag=skip_bytes,fullblock bs=$count skip=$offset count=1 2>/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
caldata_die() {
|
||||
echo "caldata: " "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
caldata_extract() {
|
||||
local part=$1
|
||||
local offset=$(($2))
|
||||
local count=$(($3))
|
||||
local mtd
|
||||
|
||||
mtd=$(find_mtd_chardev $part)
|
||||
[ -n "$mtd" ] || caldata_die "no mtd device found for partition $part"
|
||||
|
||||
caldata_dd $mtd /lib/firmware/$FIRMWARE $count $offset || \
|
||||
caldata_die "failed to extract calibration data from $mtd"
|
||||
}
|
||||
|
||||
caldata_extract_ubi() {
|
||||
local part=$1
|
||||
local offset=$(($2))
|
||||
local count=$(($3))
|
||||
local ubidev
|
||||
local ubi
|
||||
|
||||
. /lib/upgrade/nand.sh
|
||||
|
||||
ubidev=$(nand_find_ubi $CI_UBIPART)
|
||||
ubi=$(nand_find_volume $ubidev $part)
|
||||
[ -n "$ubi" ] || caldata_die "no UBI volume found for $part"
|
||||
|
||||
caldata_dd /dev/$ubi /lib/firmware/$FIRMWARE $count $offset || \
|
||||
caldata_die "failed to extract calibration data from $ubi"
|
||||
}
|
||||
|
||||
caldata_extract_reverse() {
|
||||
local part=$1
|
||||
local offset=$2
|
||||
local count=$(($3))
|
||||
local mtd
|
||||
local reversed
|
||||
local caldata
|
||||
|
||||
mtd=$(find_mtd_chardev "$part")
|
||||
reversed=$(hexdump -v -s $offset -n $count -e '/1 "%02x "' $mtd)
|
||||
|
||||
for byte in $reversed; do
|
||||
caldata="\x${byte}${caldata}"
|
||||
done
|
||||
|
||||
printf "%b" "$caldata" > /lib/firmware/$FIRMWARE
|
||||
}
|
||||
|
||||
caldata_from_file() {
|
||||
local source=$1
|
||||
local offset=$(($2))
|
||||
local count=$(($3))
|
||||
local target=$4
|
||||
|
||||
[ -n "$target" ] || target=/lib/firmware/$FIRMWARE
|
||||
|
||||
caldata_dd $source $target $count $offset || \
|
||||
caldata_die "failed to extract calibration data from $source"
|
||||
}
|
||||
|
||||
caldata_sysfsload_from_file() {
|
||||
local source=$1
|
||||
local offset=$(($2))
|
||||
local count=$(($3))
|
||||
local target_dir="/sys/$DEVPATH"
|
||||
local target="$target_dir/data"
|
||||
|
||||
[ -d "$target_dir" ] || \
|
||||
caldata_die "no sysfs dir to write: $target"
|
||||
|
||||
echo 1 > "$target_dir/loading"
|
||||
caldata_dd $source $target $count $offset
|
||||
if [ $? != 0 ]; then
|
||||
echo 1 > "$target_dir/loading"
|
||||
caldata_die "failed to extract calibration data from $source"
|
||||
else
|
||||
echo 0 > "$target_dir/loading"
|
||||
fi
|
||||
}
|
||||
|
||||
caldata_valid() {
|
||||
local expected="$1"
|
||||
local target=$2
|
||||
|
||||
[ -n "$target" ] || target=/lib/firmware/$FIRMWARE
|
||||
|
||||
magic=$(hexdump -v -n 2 -e '1/1 "%02x"' $target)
|
||||
[ "$magic" = "$expected" ]
|
||||
return $?
|
||||
}
|
||||
|
||||
caldata_patch_chksum() {
|
||||
local mac=$1
|
||||
local mac_offset=$(($2))
|
||||
local chksum_offset=$(($3))
|
||||
local target=$4
|
||||
local xor_mac
|
||||
local xor_fw_mac
|
||||
local xor_fw_chksum
|
||||
|
||||
xor_mac=${mac//:/}
|
||||
xor_mac="${xor_mac:0:4} ${xor_mac:4:4} ${xor_mac:8:4}"
|
||||
|
||||
xor_fw_mac=$(hexdump -v -n 6 -s $mac_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE)
|
||||
xor_fw_mac="${xor_fw_mac:0:4} ${xor_fw_mac:4:4} ${xor_fw_mac:8:4}"
|
||||
|
||||
xor_fw_chksum=$(hexdump -v -n 2 -s $chksum_offset -e '/1 "%02x"' /lib/firmware/$FIRMWARE)
|
||||
xor_fw_chksum=$(xor $xor_fw_chksum $xor_fw_mac $xor_mac)
|
||||
|
||||
printf "%b" "\x${xor_fw_chksum:0:2}\x${xor_fw_chksum:2:2}" | \
|
||||
dd of=$target conv=notrunc bs=1 seek=$chksum_offset count=2
|
||||
}
|
||||
|
||||
caldata_patch_mac() {
|
||||
local mac=$1
|
||||
local mac_offset=$(($2))
|
||||
local chksum_offset=$3
|
||||
local target=$4
|
||||
|
||||
[ -z "$mac" -o -z "$mac_offset" ] && return
|
||||
|
||||
[ -n "$target" ] || target=/lib/firmware/$FIRMWARE
|
||||
|
||||
[ -n "$chksum_offset" ] && caldata_patch_chksum "$mac" "$mac_offset" "$chksum_offset" "$target"
|
||||
|
||||
macaddr_2bin $mac | dd of=$target conv=notrunc oflag=seek_bytes bs=6 seek=$mac_offset count=1 || \
|
||||
caldata_die "failed to write MAC address to eeprom file"
|
||||
}
|
||||
|
||||
ath9k_patch_mac() {
|
||||
local mac=$1
|
||||
local target=$2
|
||||
|
||||
caldata_patch_mac "$mac" 0x2 "" "$target"
|
||||
}
|
||||
|
||||
ath9k_patch_mac_crc() {
|
||||
local mac=$1
|
||||
local mac_offset=$2
|
||||
local chksum_offset=$((mac_offset - 10))
|
||||
local target=$4
|
||||
|
||||
caldata_patch_mac "$mac" "$mac_offset" "$chksum_offset" "$target"
|
||||
}
|
||||
|
||||
ath10k_patch_mac() {
|
||||
local mac=$1
|
||||
local target=$2
|
||||
|
||||
caldata_patch_mac "$mac" 0x6 0x2 "$target"
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
# Copyright (C) 2013 OpenWrt.org
|
||||
|
||||
get_dt_led_path() {
|
||||
local ledpath
|
||||
local basepath="/proc/device-tree"
|
||||
local nodepath="$basepath/aliases/led-$1"
|
||||
|
||||
[ -f "$nodepath" ] && ledpath=$(cat "$nodepath")
|
||||
[ -n "$ledpath" ] && ledpath="$basepath$ledpath"
|
||||
|
||||
echo "$ledpath"
|
||||
}
|
||||
|
||||
get_dt_led() {
|
||||
local label
|
||||
local ledpath=$(get_dt_led_path $1)
|
||||
|
||||
[ -n "$ledpath" ] && \
|
||||
label=$(cat "$ledpath/label" 2>/dev/null) || \
|
||||
label=$(cat "$ledpath/chan-name" 2>/dev/null) || \
|
||||
label=$(basename "$ledpath")
|
||||
|
||||
echo "$label"
|
||||
}
|
||||
|
||||
led_set_attr() {
|
||||
[ -f "/sys/class/leds/$1/$2" ] && echo "$3" > "/sys/class/leds/$1/$2"
|
||||
}
|
||||
|
||||
led_timer() {
|
||||
led_set_attr $1 "trigger" "timer"
|
||||
led_set_attr $1 "delay_on" "$2"
|
||||
led_set_attr $1 "delay_off" "$3"
|
||||
}
|
||||
|
||||
led_on() {
|
||||
led_set_attr $1 "trigger" "none"
|
||||
led_set_attr $1 "brightness" 255
|
||||
}
|
||||
|
||||
led_off() {
|
||||
led_set_attr $1 "trigger" "none"
|
||||
led_set_attr $1 "brightness" 0
|
||||
}
|
||||
|
||||
status_led_restore_trigger() {
|
||||
local trigger
|
||||
local ledpath=$(get_dt_led_path $1)
|
||||
|
||||
[ -n "$ledpath" ] && \
|
||||
trigger=$(cat "$ledpath/linux,default-trigger" 2>/dev/null)
|
||||
|
||||
[ -n "$trigger" ] && \
|
||||
led_set_attr "$(get_dt_led $1)" "trigger" "$trigger"
|
||||
}
|
||||
|
||||
status_led_set_timer() {
|
||||
led_timer $status_led "$1" "$2"
|
||||
[ -n "$status_led2" ] && led_timer $status_led2 "$1" "$2"
|
||||
}
|
||||
|
||||
status_led_set_heartbeat() {
|
||||
led_set_attr $status_led "trigger" "heartbeat"
|
||||
}
|
||||
|
||||
status_led_on() {
|
||||
led_on $status_led
|
||||
[ -n "$status_led2" ] && led_on $status_led2
|
||||
}
|
||||
|
||||
status_led_off() {
|
||||
led_off $status_led
|
||||
[ -n "$status_led2" ] && led_off $status_led2
|
||||
}
|
||||
|
||||
status_led_blink_slow() {
|
||||
led_timer $status_led 1000 1000
|
||||
}
|
||||
|
||||
status_led_blink_fast() {
|
||||
led_timer $status_led 100 100
|
||||
}
|
||||
|
||||
status_led_blink_preinit() {
|
||||
led_timer $status_led 100 100
|
||||
}
|
||||
|
||||
status_led_blink_failsafe() {
|
||||
led_timer $status_led 50 50
|
||||
}
|
||||
|
||||
status_led_blink_preinit_regular() {
|
||||
led_timer $status_led 200 200
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
. /lib/functions.sh
|
||||
|
||||
migrate_led_sysfs() {
|
||||
local cfg="$1"; shift
|
||||
local tuples="$@"
|
||||
local sysfs
|
||||
local name
|
||||
|
||||
config_get sysfs ${cfg} sysfs
|
||||
config_get name ${cfg} name
|
||||
|
||||
[ -z "${sysfs}" ] && return
|
||||
|
||||
for tuple in ${tuples}; do
|
||||
local old=${tuple%=*}
|
||||
local new=${tuple#*=}
|
||||
local new_sysfs
|
||||
|
||||
new_sysfs=$(echo ${sysfs} | sed "s/${old}/${new}/")
|
||||
|
||||
[ "${new_sysfs}" = "${sysfs}" ] && continue
|
||||
|
||||
uci set system.${cfg}.sysfs="${new_sysfs}"
|
||||
|
||||
logger -t led-migration "sysfs option of LED \"${name}\" updated to ${new_sysfs}"
|
||||
done;
|
||||
}
|
||||
|
||||
remove_devicename_led_sysfs() {
|
||||
local cfg="$1"; shift
|
||||
local exceptions="$@"
|
||||
local sysfs
|
||||
local name
|
||||
local new_sysfs
|
||||
|
||||
config_get sysfs ${cfg} sysfs
|
||||
config_get name ${cfg} name
|
||||
|
||||
# only continue if two or more colons are present
|
||||
echo "${sysfs}" | grep -q ":.*:" || return
|
||||
|
||||
for exception in ${exceptions}; do
|
||||
# no change if exceptions provided as argument are found for devicename
|
||||
echo "${sysfs}" | grep -q "^${exception}:" && return
|
||||
done
|
||||
|
||||
new_sysfs=$(echo ${sysfs} | sed "s/^[^:]*://")
|
||||
|
||||
uci set system.${cfg}.sysfs="${new_sysfs}"
|
||||
|
||||
logger -t led-migration "sysfs option of LED \"${name}\" updated to ${new_sysfs}"
|
||||
}
|
||||
|
||||
migrate_leds() {
|
||||
config_load system
|
||||
config_foreach migrate_led_sysfs led "$@"
|
||||
}
|
||||
|
||||
remove_devicename_leds() {
|
||||
config_load system
|
||||
config_foreach remove_devicename_led_sysfs led "$@"
|
||||
}
|
||||
|
||||
migrations_apply() {
|
||||
local realm="$1"
|
||||
[ -n "$(uci changes ${realm})" ] && uci -q commit ${realm}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
#Mobile configuration management lib
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
gsm_soft_reset() {
|
||||
gsmctl -n -A at+cfun=4
|
||||
sleep 2
|
||||
gsmctl -n -A at+cfun=1
|
||||
}
|
||||
|
||||
qmi_error_handle() {
|
||||
local error="$1"
|
||||
local modem_id="$2"
|
||||
|
||||
$(echo "$error" | grep -q "error") && {
|
||||
echo "$error"
|
||||
}
|
||||
|
||||
$(echo "$error" | grep -q "Client IDs exhausted") && {
|
||||
echo "ClientIdsExhausted! reseting counter..."
|
||||
proto_notify_error "$interface" NO_CID
|
||||
uqmi -s -d "$device" --sync
|
||||
return 1
|
||||
}
|
||||
|
||||
# Reik papildyt ERROR handlinima
|
||||
# $(echo "$error" | grep -q "multiple-connection-to-same-pdn-not-allowed") && {
|
||||
# echo "Reseting due dublicated connection..."
|
||||
# qmicli -p -d "$device" --uim-sim-power-off=1
|
||||
# qmicli -p -d "$device" --uim-sim-power-on=1
|
||||
# return 1
|
||||
# }
|
||||
|
||||
# $(echo "$error" | grep -q "Transaction timed out") && {
|
||||
# echo "Device not responding, restarting module"
|
||||
# gsmctl -O $modem_id -A at+cfun=1,1
|
||||
# }
|
||||
#
|
||||
# $(echo "$error" | grep -q 'verbose call end reason (2,236)') && {
|
||||
# echo "Failed to start network, clearing all cids"
|
||||
# qmicli -p -d "$device" --wds-noop --device-open-sync
|
||||
# return 1
|
||||
# }
|
||||
|
||||
$(echo "$error" | grep -q "Call Failed") && {
|
||||
echo "Device not responding, restarting module"
|
||||
sleep 10
|
||||
gsm_soft_reset
|
||||
return 1
|
||||
}
|
||||
|
||||
$(echo "$error" | grep -q "Policy Mismatch") && {
|
||||
echo "Reseting network..."
|
||||
gsm_soft_reset
|
||||
return 1
|
||||
}
|
||||
|
||||
$(echo "$error" | grep -q "Failed to connect to service") && {
|
||||
echo "Device not responding, restarting module"
|
||||
gsmctl -A at+cfun=1,1
|
||||
return 1
|
||||
}
|
||||
|
||||
$(echo "$error" | grep -q "error") && {
|
||||
echo "$error"
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
passthrough_mode=
|
||||
get_passthrough() {
|
||||
config_get primary "$1" primary
|
||||
[ "$primary" = "1" ] && {
|
||||
config_get sim "$1" position;
|
||||
passthrough_mode=$(uci -q get network.mob1s${sim}a1.passthrough_mode 2>/dev/null);
|
||||
}
|
||||
}
|
||||
|
||||
setup_bridge_v4() {
|
||||
local dev="$1"
|
||||
local dhcp_param_file="/tmp/dnsmasq.d/bridge"
|
||||
echo "$parameters4"
|
||||
|
||||
json_load "$parameters4"
|
||||
json_select "ipv4"
|
||||
json_get_var bridge_ipaddr ip
|
||||
json_get_var bridge_mask subnet
|
||||
json_get_var bridge_gateway gateway
|
||||
json_get_var bridge_dns1 dns1
|
||||
json_get_var bridge_dns2 dns2
|
||||
|
||||
json_init
|
||||
json_add_string name "${interface}_4"
|
||||
json_add_string ifname "$dev"
|
||||
json_add_string proto "none"
|
||||
json_add_object "data"
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
IFACE4="${interface}_4"
|
||||
|
||||
json_init
|
||||
json_add_string interface "${interface}_4"
|
||||
json_add_string zone "lan"
|
||||
ubus call network.interface set_data "$(json_dump)"
|
||||
|
||||
json_init
|
||||
json_add_string interface "${interface}"
|
||||
json_add_string bridge_ipaddr "$bridge_ipaddr"
|
||||
ubus call network.interface set_data "$(json_dump)"
|
||||
|
||||
json_init
|
||||
json_add_string modem "$modem"
|
||||
json_add_string sim "$sim"
|
||||
ubus call network.interface."${interface}_4" set_data "$(json_dump)"
|
||||
json_close_object
|
||||
|
||||
ip route add default dev "$dev" table 42
|
||||
ip route add default dev br-lan table 43
|
||||
ip route add "$bridge_ipaddr" dev br-lan
|
||||
|
||||
ip rule add pref 5042 from "$bridge_ipaddr" lookup 42
|
||||
ip rule add pref 5043 iif "$dev" lookup 43
|
||||
#sysctl -w net.ipv4.conf.br-lan.proxy_arp=1 #2>/dev/null
|
||||
ip neighbor add proxy "$bridge_gateway" dev br-lan
|
||||
|
||||
iptables -A postrouting_rule -m comment --comment "Bridge mode" -o "$dev" -j ACCEPT -tnat
|
||||
|
||||
config_load simcard
|
||||
config_foreach get_passthrough sim
|
||||
|
||||
> $dhcp_param_file
|
||||
[ -z "$mac" ] && mac="*:*:*:*:*:*"
|
||||
[ "$passthrough_mode" != "no_dhcp" ] && {
|
||||
echo "dhcp-range=tag:mobbridge,$bridge_ipaddr,static,$bridge_mask,${leasetime:-1h}" > "$dhcp_param_file"
|
||||
echo "shared-network=br-lan,$bridge_ipaddr" >> "$dhcp_param_file"
|
||||
echo "dhcp-host=$mac,set:mobbridge,$bridge_ipaddr" >> "$dhcp_param_file"
|
||||
echo "dhcp-option=tag:mobbridge,br-lan,3,$bridge_gateway" >> "$dhcp_param_file"
|
||||
echo "dhcp-option=tag:mobbridge,br-lan,6,$bridge_dns1,$bridge_dns2" >> "$dhcp_param_file"
|
||||
echo "server=$bridge_dns1" >> "$dhcp_param_file"
|
||||
echo "server=$bridge_dns2" >> "$dhcp_param_file"
|
||||
}
|
||||
/etc/init.d/dnsmasq reload
|
||||
swconfig dev 'switch0' set soft_reset 5 &
|
||||
}
|
||||
|
||||
setup_static_v4() {
|
||||
local dev="$1"
|
||||
echo "Setting up $dev V4 static"
|
||||
echo "$parameters4"
|
||||
|
||||
json_load "$parameters4"
|
||||
json_select "ipv4"
|
||||
json_get_var ip_4 ip
|
||||
json_get_var dns1_4 dns1
|
||||
json_get_var dns2_4 dns2
|
||||
|
||||
json_init
|
||||
json_add_string name "${interface}_4"
|
||||
json_add_string ifname "$dev"
|
||||
json_add_string proto static
|
||||
json_add_string gateway "0.0.0.0"
|
||||
|
||||
json_add_array ipaddr
|
||||
json_add_string "" "$ip_4"
|
||||
json_close_array
|
||||
|
||||
json_add_array dns
|
||||
[ -n "$dns1_4" ] && json_add_string "" "$dns1_4"
|
||||
[ -n "$dns2_4" ] && json_add_string "" "$dns2_4"
|
||||
json_close_array
|
||||
|
||||
[ -n "$ip4table" ] && json_add_string ip4table "$ip4table"
|
||||
proto_add_dynamic_defaults
|
||||
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
}
|
||||
|
||||
setup_dhcp_v4() {
|
||||
local dev="$1"
|
||||
echo "Setting up $dev V4 DCHP"
|
||||
json_init
|
||||
json_add_string name "${interface}_4"
|
||||
json_add_string ifname "$dev"
|
||||
json_add_string proto "dhcp"
|
||||
json_add_string script "/lib/netifd/dhcp_mobile.script"
|
||||
[ -n "$ip4table" ] && json_add_string ip4table "$ip4table"
|
||||
proto_add_dynamic_defaults
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
}
|
||||
|
||||
setup_dhcp_v6() {
|
||||
local dev="$1"
|
||||
echo "Setting up $dev V6 DHCP"
|
||||
json_init
|
||||
json_add_string name "${interface}_6"
|
||||
json_add_string ifname "$dev"
|
||||
json_add_string proto "dhcpv6"
|
||||
[ -n "$ip6table" ] && json_add_string ip6table "$ip6table"
|
||||
json_add_boolean ignore_valid 1
|
||||
proto_add_dynamic_defaults
|
||||
# RFC 7278: Extend an IPv6 /64 Prefix to LAN
|
||||
json_add_string extendprefix 1
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
}
|
||||
|
||||
setup_static_v6() {
|
||||
local dev="$1"
|
||||
echo "Setting up $dev V6 static"
|
||||
echo "$parameters6"
|
||||
|
||||
json_load "$parameters6"
|
||||
json_select "ipv6"
|
||||
json_get_var ip6_with_prefix ip
|
||||
ip_6="${ip6_with_prefix%/*}"
|
||||
ip_prefix_length="${ip6_with_prefix#*/}"
|
||||
json_get_var ip6_gateway_with_prefix gateway
|
||||
gateway_6="${ip6_gateway_with_prefix%/*}"
|
||||
json_get_var dns1_6 dns1
|
||||
json_get_var dns2_6 dns2
|
||||
|
||||
json_init
|
||||
json_add_string name "${interface}_6"
|
||||
json_add_string ifname "$dev"
|
||||
json_add_string proto static
|
||||
json_add_string ip6gw "$gateway_6"
|
||||
|
||||
json_add_array ip6prefix
|
||||
json_add_string "" "$ip6_with_prefix"
|
||||
json_close_array
|
||||
|
||||
json_add_array ip6addr
|
||||
json_add_string "" "$ip6_with_prefix"
|
||||
json_close_array
|
||||
|
||||
json_add_array dns
|
||||
[ -n "$dns1_6" ] && json_add_string "" "$dns1_6"
|
||||
[ -n "$dns2_6" ] && json_add_string "" "$dns2_6"
|
||||
json_close_array
|
||||
|
||||
[ -n "$ip6table" ] && json_add_string ip6table "$ip6table"
|
||||
proto_add_dynamic_defaults
|
||||
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
# Copyright (C) 2006-2013 OpenWrt.org
|
||||
# Copyright (C) 2010 Vertical Communications
|
||||
|
||||
boot_hook_splice_start() {
|
||||
export -n PI_HOOK_SPLICE=1
|
||||
}
|
||||
|
||||
boot_hook_splice_finish() {
|
||||
local hook
|
||||
for hook in $PI_STACK_LIST; do
|
||||
local v; eval "v=\${${hook}_splice:+\$${hook}_splice }$hook"
|
||||
export -n "${hook}=${v% }"
|
||||
export -n "${hook}_splice="
|
||||
done
|
||||
export -n PI_HOOK_SPLICE=
|
||||
}
|
||||
|
||||
boot_hook_init() {
|
||||
local hook="${1}_hook"
|
||||
export -n "PI_STACK_LIST=${PI_STACK_LIST:+$PI_STACK_LIST }$hook"
|
||||
export -n "$hook="
|
||||
}
|
||||
|
||||
boot_hook_add() {
|
||||
local hook="${1}_hook${PI_HOOK_SPLICE:+_splice}"
|
||||
local func="${2}"
|
||||
|
||||
[ -n "$func" ] && {
|
||||
local v; eval "v=\$$hook"
|
||||
export -n "$hook=${v:+$v }$func"
|
||||
}
|
||||
}
|
||||
|
||||
boot_hook_shift() {
|
||||
local hook="${1}_hook"
|
||||
local rvar="${2}"
|
||||
|
||||
local v; eval "v=\$$hook"
|
||||
[ -n "$v" ] && {
|
||||
local first="${v%% *}"
|
||||
|
||||
[ "$v" != "${v#* }" ] && \
|
||||
export -n "$hook=${v#* }" || \
|
||||
export -n "$hook="
|
||||
|
||||
export -n "$rvar=$first"
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
boot_run_hook() {
|
||||
local hook="$1"
|
||||
local func
|
||||
|
||||
while boot_hook_shift "$hook" func; do
|
||||
local ran; eval "ran=\$PI_RAN_$func"
|
||||
[ -n "$ran" ] || {
|
||||
export -n "PI_RAN_$func=1"
|
||||
$func "$1" "$2"
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
pivot() { # <new_root> <old_root>
|
||||
/bin/mount -o noatime,move /proc $1/proc && \
|
||||
pivot_root $1 $1$2 && {
|
||||
/bin/mount -o noatime,move $2/dev /dev
|
||||
/bin/mount -o noatime,move $2/tmp /tmp
|
||||
/bin/mount -o noatime,move $2/sys /sys 2>&-
|
||||
/bin/mount -o noatime,move $2/overlay /overlay 2>&-
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
fopivot() { # <rw_root> <work_dir> <ro_root> <dupe?>
|
||||
/bin/mount -o noatime,lowerdir=/,upperdir=$1,workdir=$2 -t overlay "overlayfs:$1" /mnt
|
||||
pivot /mnt $3
|
||||
}
|
||||
|
||||
ramoverlay() {
|
||||
mkdir -p /tmp/root
|
||||
/bin/mount -t tmpfs -o noatime,mode=0755 root /tmp/root
|
||||
mkdir -p /tmp/root/root /tmp/root/work
|
||||
fopivot /tmp/root/root /tmp/root/work /rom 1
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
#
|
||||
# service: simple wrapper around start-stop-daemon
|
||||
#
|
||||
# Usage: service ACTION EXEC ARGS...
|
||||
#
|
||||
# Action:
|
||||
# -C check if EXEC is alive
|
||||
# -S start EXEC, passing it ARGS as its arguments
|
||||
# -K kill EXEC, sending it a TERM signal if not specified otherwise
|
||||
#
|
||||
# Environment variables exposed:
|
||||
# SERVICE_DAEMONIZE run EXEC in background
|
||||
# SERVICE_WRITE_PID create a pid-file and use it for matching
|
||||
# SERVICE_MATCH_EXEC use EXEC command-line for matching (default)
|
||||
# SERVICE_MATCH_NAME use EXEC process name for matching
|
||||
# SERVICE_USE_PID assume EXEC create its own pid-file and use it for matching
|
||||
# SERVICE_NAME process name to use (default to EXEC file part)
|
||||
# SERVICE_PID_FILE pid file to use (default to /var/run/$SERVICE_NAME.pid)
|
||||
# SERVICE_SIG signal to send when using -K
|
||||
# SERVICE_SIG_RELOAD default signal used when reloading
|
||||
# SERVICE_SIG_STOP default signal used when stopping
|
||||
# SERVICE_STOP_TIME time to wait for a process to stop gracefully before killing it
|
||||
# SERVICE_UID user EXEC should be run as
|
||||
# SERVICE_GID group EXEC should be run as
|
||||
#
|
||||
# SERVICE_DEBUG don't do anything, but show what would be done
|
||||
# SERVICE_QUIET don't print anything
|
||||
#
|
||||
|
||||
SERVICE_QUIET=1
|
||||
SERVICE_SIG_RELOAD="HUP"
|
||||
SERVICE_SIG_STOP="TERM"
|
||||
SERVICE_STOP_TIME=5
|
||||
SERVICE_MATCH_EXEC=1
|
||||
|
||||
service() {
|
||||
local ssd
|
||||
local exec
|
||||
local name
|
||||
local start
|
||||
ssd="${SERVICE_DEBUG:+echo }start-stop-daemon${SERVICE_QUIET:+ -q}"
|
||||
case "$1" in
|
||||
-C)
|
||||
ssd="$ssd -K -t"
|
||||
;;
|
||||
-S)
|
||||
ssd="$ssd -S${SERVICE_DAEMONIZE:+ -b}${SERVICE_WRITE_PID:+ -m}"
|
||||
start=1
|
||||
;;
|
||||
-K)
|
||||
ssd="$ssd -K${SERVICE_SIG:+ -s $SERVICE_SIG}"
|
||||
;;
|
||||
*)
|
||||
echo "service: unknown ACTION '$1'" 1>&2
|
||||
return 1
|
||||
esac
|
||||
shift
|
||||
exec="$1"
|
||||
[ -n "$exec" ] || {
|
||||
echo "service: missing argument" 1>&2
|
||||
return 1
|
||||
}
|
||||
[ -x "$exec" ] || {
|
||||
echo "service: file '$exec' is not executable" 1>&2
|
||||
return 1
|
||||
}
|
||||
name="${SERVICE_NAME:-${exec##*/}}"
|
||||
[ -z "$SERVICE_USE_PID$SERVICE_WRITE_PID$SERVICE_PID_FILE" ] \
|
||||
|| ssd="$ssd -p ${SERVICE_PID_FILE:-/var/run/$name.pid}"
|
||||
[ -z "$SERVICE_MATCH_NAME" ] || ssd="$ssd -n $name"
|
||||
ssd="$ssd${SERVICE_UID:+ -c $SERVICE_UID${SERVICE_GID:+:$SERVICE_GID}}"
|
||||
[ -z "$SERVICE_MATCH_EXEC$start" ] || ssd="$ssd -x $exec"
|
||||
shift
|
||||
$ssd${1:+ -- "$@"}
|
||||
}
|
||||
|
||||
service_check() {
|
||||
service -C "$@"
|
||||
}
|
||||
|
||||
service_signal() {
|
||||
SERVICE_SIG="${SERVICE_SIG:-USR1}" service -K "$@"
|
||||
}
|
||||
|
||||
service_start() {
|
||||
service -S "$@"
|
||||
}
|
||||
|
||||
service_stop() {
|
||||
local try
|
||||
SERVICE_SIG="${SERVICE_SIG:-$SERVICE_SIG_STOP}" service -K "$@" || return 1
|
||||
while [ $((try++)) -lt $SERVICE_STOP_TIME ]; do
|
||||
service -C "$@" || return 0
|
||||
sleep 1
|
||||
done
|
||||
SERVICE_SIG="KILL" service -K "$@"
|
||||
sleep 1
|
||||
! service -C "$@"
|
||||
}
|
||||
|
||||
service_reload() {
|
||||
SERVICE_SIG="${SERVICE_SIG:-$SERVICE_SIG_RELOAD}" service -K "$@"
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
# Copyright (C) 2006-2013 OpenWrt.org
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
get_mac_binary() {
|
||||
local path="$1"
|
||||
local offset="$2"
|
||||
|
||||
if ! [ -e "$path" ]; then
|
||||
echo "get_mac_binary: file $path not found!" >&2
|
||||
return
|
||||
fi
|
||||
|
||||
hexdump -v -n 6 -s $offset -e '5/1 "%02x:" 1/1 "%02x"' $path 2>/dev/null
|
||||
}
|
||||
|
||||
get_mac_label_dt() {
|
||||
local basepath="/proc/device-tree"
|
||||
local macdevice="$(cat "$basepath/aliases/label-mac-device" 2>/dev/null)"
|
||||
local macaddr
|
||||
|
||||
[ -n "$macdevice" ] || return
|
||||
|
||||
macaddr=$(get_mac_binary "$basepath/$macdevice/mac-address" 0 2>/dev/null)
|
||||
[ -n "$macaddr" ] || macaddr=$(get_mac_binary "$basepath/$macdevice/local-mac-address" 0 2>/dev/null)
|
||||
|
||||
echo $macaddr
|
||||
}
|
||||
|
||||
get_mac_label_json() {
|
||||
local cfg="/etc/board.json"
|
||||
local macaddr
|
||||
|
||||
[ -s "$cfg" ] || return
|
||||
|
||||
json_init
|
||||
json_load "$(cat $cfg)"
|
||||
if json_is_a system object; then
|
||||
json_select system
|
||||
json_get_var macaddr label_macaddr
|
||||
json_select ..
|
||||
fi
|
||||
|
||||
echo $macaddr
|
||||
}
|
||||
|
||||
get_mac_label() {
|
||||
local macaddr=$(get_mac_label_dt)
|
||||
|
||||
[ -n "$macaddr" ] || macaddr=$(get_mac_label_json)
|
||||
|
||||
echo $macaddr
|
||||
}
|
||||
|
||||
find_mtd_chardev() {
|
||||
local INDEX=$(find_mtd_index "$1")
|
||||
local PREFIX=/dev/mtd
|
||||
|
||||
[ -d /dev/mtd ] && PREFIX=/dev/mtd/
|
||||
echo "${INDEX:+$PREFIX$INDEX}"
|
||||
}
|
||||
|
||||
mtd_get_mac_ascii() {
|
||||
local mtdname="$1"
|
||||
local key="$2"
|
||||
local part
|
||||
local mac_dirty
|
||||
|
||||
part=$(find_mtd_part "$mtdname")
|
||||
if [ -z "$part" ]; then
|
||||
echo "mtd_get_mac_ascii: partition $mtdname not found!" >&2
|
||||
return
|
||||
fi
|
||||
|
||||
mac_dirty=$(strings "$part" | sed -n 's/^'"$key"'=//p')
|
||||
|
||||
# "canonicalize" mac
|
||||
[ -n "$mac_dirty" ] && macaddr_canonicalize "$mac_dirty"
|
||||
}
|
||||
|
||||
mtd_get_mac_text() {
|
||||
local mtdname=$1
|
||||
local offset=$(($2))
|
||||
local part
|
||||
local mac_dirty
|
||||
|
||||
part=$(find_mtd_part "$mtdname")
|
||||
if [ -z "$part" ]; then
|
||||
echo "mtd_get_mac_text: partition $mtdname not found!" >&2
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$offset" ]; then
|
||||
echo "mtd_get_mac_text: offset missing!" >&2
|
||||
return
|
||||
fi
|
||||
|
||||
mac_dirty=$(dd if="$part" bs=1 skip="$offset" count=17 2>/dev/null)
|
||||
|
||||
# "canonicalize" mac
|
||||
[ -n "$mac_dirty" ] && macaddr_canonicalize "$mac_dirty"
|
||||
}
|
||||
|
||||
mtd_get_mac_binary() {
|
||||
local mtdname="$1"
|
||||
local offset="$2"
|
||||
local part
|
||||
|
||||
part=$(find_mtd_part "$mtdname")
|
||||
get_mac_binary "$part" "$offset"
|
||||
}
|
||||
|
||||
mtd_get_mac_binary_ubi() {
|
||||
local mtdname="$1"
|
||||
local offset="$2"
|
||||
|
||||
. /lib/upgrade/nand.sh
|
||||
|
||||
local ubidev=$(nand_find_ubi $CI_UBIPART)
|
||||
local part=$(nand_find_volume $ubidev $1)
|
||||
|
||||
get_mac_binary "/dev/$part" "$offset"
|
||||
}
|
||||
|
||||
mtd_get_part_size() {
|
||||
local part_name=$1
|
||||
local first dev size erasesize name
|
||||
while read dev size erasesize name; do
|
||||
name=${name#'"'}; name=${name%'"'}
|
||||
if [ "$name" = "$part_name" ]; then
|
||||
echo $((0x$size))
|
||||
break
|
||||
fi
|
||||
done < /proc/mtd
|
||||
}
|
||||
|
||||
macaddr_add() {
|
||||
local mac=$1
|
||||
local val=$2
|
||||
local oui=${mac%:*:*:*}
|
||||
local nic=${mac#*:*:*:}
|
||||
|
||||
nic=$(printf "%06x" $((0x${nic//:/} + val & 0xffffff)) | sed 's/^\(.\{2\}\)\(.\{2\}\)\(.\{2\}\)/\1:\2:\3/')
|
||||
echo $oui:$nic
|
||||
}
|
||||
|
||||
macaddr_geteui() {
|
||||
local mac=$1
|
||||
local sep=$2
|
||||
|
||||
echo ${mac:9:2}$sep${mac:12:2}$sep${mac:15:2}
|
||||
}
|
||||
|
||||
macaddr_setbit() {
|
||||
local mac=$1
|
||||
local bit=${2:-0}
|
||||
|
||||
[ $bit -gt 0 -a $bit -le 48 ] || return
|
||||
|
||||
printf "%012x" $(( 0x${mac//:/} | 2**(48-bit) )) | sed -e 's/\(.\{2\}\)/\1:/g' -e 's/:$//'
|
||||
}
|
||||
|
||||
macaddr_unsetbit() {
|
||||
local mac=$1
|
||||
local bit=${2:-0}
|
||||
|
||||
[ $bit -gt 0 -a $bit -le 48 ] || return
|
||||
|
||||
printf "%012x" $(( 0x${mac//:/} & ~(2**(48-bit)) )) | sed -e 's/\(.\{2\}\)/\1:/g' -e 's/:$//'
|
||||
}
|
||||
|
||||
macaddr_setbit_la() {
|
||||
macaddr_setbit $1 7
|
||||
}
|
||||
|
||||
macaddr_unsetbit_mc() {
|
||||
local mac=$1
|
||||
|
||||
printf "%02x:%s" $((0x${mac%%:*} & ~0x01)) ${mac#*:}
|
||||
}
|
||||
|
||||
macaddr_random() {
|
||||
local randsrc=$(get_mac_binary /dev/urandom 0)
|
||||
|
||||
echo "$(macaddr_unsetbit_mc "$(macaddr_setbit_la "${randsrc}")")"
|
||||
}
|
||||
|
||||
macaddr_2bin() {
|
||||
local mac=$1
|
||||
|
||||
echo -ne \\x${mac//:/\\x}
|
||||
}
|
||||
|
||||
macaddr_canonicalize() {
|
||||
local mac="$1"
|
||||
local canon=""
|
||||
|
||||
mac=$(echo -n $mac | tr -d \")
|
||||
[ ${#mac} -gt 17 ] && return
|
||||
[ -n "${mac//[a-fA-F0-9\.: -]/}" ] && return
|
||||
|
||||
for octet in ${mac//[\.:-]/ }; do
|
||||
case "${#octet}" in
|
||||
1)
|
||||
octet="0${octet}"
|
||||
;;
|
||||
2)
|
||||
;;
|
||||
4)
|
||||
octet="${octet:0:2} ${octet:2:2}"
|
||||
;;
|
||||
12)
|
||||
octet="${octet:0:2} ${octet:2:2} ${octet:4:2} ${octet:6:2} ${octet:8:2} ${octet:10:2}"
|
||||
;;
|
||||
*)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
canon=${canon}${canon:+ }${octet}
|
||||
done
|
||||
|
||||
[ ${#canon} -ne 17 ] && return
|
||||
|
||||
printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${canon// / 0x} 2>/dev/null
|
||||
}
|
|
@ -1,383 +0,0 @@
|
|||
find_mmc_part() {
|
||||
local DEVNAME PARTNAME
|
||||
|
||||
if grep -q "$1" /proc/mtd; then
|
||||
echo "" && return 0
|
||||
fi
|
||||
|
||||
for DEVNAME in /sys/block/mmcblk0/mmcblk*p*; do
|
||||
PARTNAME=$(grep PARTNAME ${DEVNAME}/uevent | cut -f2 -d'=')
|
||||
[ "$PARTNAME" = "$1" ] && echo "/dev/$(basename $DEVNAME)" && return 0
|
||||
done
|
||||
}
|
||||
|
||||
get_full_section_name() {
|
||||
local img=$1
|
||||
local sec=$2
|
||||
|
||||
dumpimage -l ${img} | grep "^ Image.*(${sec})" | \
|
||||
sed 's,^ Image.*(\(.*\)),\1,'
|
||||
}
|
||||
|
||||
image_contains() {
|
||||
local img=$1
|
||||
local sec=$2
|
||||
dumpimage -l ${img} | grep -q "^ Image.*(${sec}.*)" || return 1
|
||||
}
|
||||
|
||||
print_sections() {
|
||||
local img=$1
|
||||
|
||||
dumpimage -l ${img} | awk '/^ Image.*(.*)/ { print gensub(/Image .* \((.*)\)/,"\\1", $0) }'
|
||||
}
|
||||
|
||||
image_has_mandatory_section() {
|
||||
local img=$1
|
||||
local mandatory_sections=$2
|
||||
|
||||
for sec in ${mandatory_sections}; do
|
||||
image_contains $img ${sec} || {\
|
||||
return 1
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
image_demux() {
|
||||
local img=$1
|
||||
|
||||
for sec in $(print_sections ${img}); do
|
||||
local fullname=$(get_full_section_name ${img} ${sec})
|
||||
|
||||
local position=$(dumpimage -l ${img} | grep "(${fullname})" | awk '{print $2}')
|
||||
dumpimage -i ${img} -o /tmp/${fullname}.bin -T "flat_dt" -p "${position}" ${fullname} > /dev/null || { \
|
||||
echo "Error while extracting \"${sec}\" from ${img}"
|
||||
return 1
|
||||
}
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
image_is_FIT() {
|
||||
if ! dumpimage -l $1 > /dev/null 2>&1; then
|
||||
echo "$1 is not a valid FIT image"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
switch_layout() {
|
||||
local layout=$1
|
||||
local boot_layout=`find / -name boot_layout`
|
||||
|
||||
# Layout switching is only required as the boot images (up to u-boot)
|
||||
# use 512 user data bytes per code word, whereas Linux uses 516 bytes.
|
||||
# It's only applicable for NAND flash. So let's return if we don't have
|
||||
# one.
|
||||
|
||||
[ -n "$boot_layout" ] || return
|
||||
|
||||
case "${layout}" in
|
||||
boot|1) echo 1 > $boot_layout;;
|
||||
linux|0) echo 0 > $boot_layout;;
|
||||
*) echo "Unknown layout \"${layout}\"";;
|
||||
esac
|
||||
}
|
||||
|
||||
do_flash_mtd() {
|
||||
local bin=$1
|
||||
local mtdname=$2
|
||||
local append=""
|
||||
|
||||
local mtdpart=$(grep "\"${mtdname}\"" /proc/mtd | awk -F: '{print $1}')
|
||||
local pgsz=$(cat /sys/class/mtd/${mtdpart}/writesize)
|
||||
[ -f "$CONF_TAR" -a "$SAVE_CONFIG" -eq 1 -a "$2" == "rootfs" ] && append="-j $CONF_TAR"
|
||||
|
||||
dd if=/tmp/${bin}.bin bs=${pgsz} conv=sync | mtd $append -e "/dev/${mtdpart}" write - "/dev/${mtdpart}"
|
||||
}
|
||||
|
||||
do_flash_emmc() {
|
||||
local bin=$1
|
||||
local emmcblock=$2
|
||||
|
||||
dd if=/dev/zero of=${emmcblock}
|
||||
dd if=/tmp/${bin}.bin of=${emmcblock}
|
||||
}
|
||||
|
||||
do_flash_partition() {
|
||||
local bin=$1
|
||||
local mtdname=$2
|
||||
local emmcblock="$(find_mmc_part "$mtdname")"
|
||||
|
||||
if [ -e "$emmcblock" ]; then
|
||||
do_flash_emmc $bin $emmcblock
|
||||
else
|
||||
do_flash_mtd $bin $mtdname
|
||||
fi
|
||||
}
|
||||
|
||||
do_flash_bootconfig() {
|
||||
local bin=$1
|
||||
local mtdname=$2
|
||||
|
||||
# Fail safe upgrade
|
||||
if [ -f /proc/boot_info/getbinary_${bin} ]; then
|
||||
cat /proc/boot_info/getbinary_${bin} > /tmp/${bin}.bin
|
||||
do_flash_partition $bin $mtdname
|
||||
fi
|
||||
}
|
||||
|
||||
do_flash_failsafe_partition() {
|
||||
local bin=$1
|
||||
local mtdname=$2
|
||||
local emmcblock
|
||||
local primaryboot
|
||||
|
||||
# Fail safe upgrade
|
||||
[ -f /proc/boot_info/$mtdname/upgradepartition ] && {
|
||||
default_mtd=$mtdname
|
||||
mtdname=$(cat /proc/boot_info/$mtdname/upgradepartition)
|
||||
primaryboot=$(cat /proc/boot_info/$default_mtd/primaryboot)
|
||||
if [ $primaryboot -eq 0 ]; then
|
||||
echo 1 > /proc/boot_info/$default_mtd/primaryboot
|
||||
else
|
||||
echo 0 > /proc/boot_info/$default_mtd/primaryboot
|
||||
fi
|
||||
}
|
||||
|
||||
emmcblock="$(find_mmc_part "$mtdname")"
|
||||
|
||||
if [ -e "$emmcblock" ]; then
|
||||
do_flash_emmc $bin $emmcblock
|
||||
else
|
||||
do_flash_mtd $bin $mtdname
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
do_flash_ubi() {
|
||||
local bin=$1
|
||||
local mtdname=$2
|
||||
local mtdpart
|
||||
local primaryboot
|
||||
|
||||
mtdpart=$(grep "\"${mtdname}\"" /proc/mtd | awk -F: '{print $1}')
|
||||
ubidetach -p /dev/${mtdpart}
|
||||
|
||||
# Fail safe upgrade
|
||||
[ -f /proc/boot_info/$mtdname/upgradepartition ] && {
|
||||
primaryboot=$(cat /proc/boot_info/$mtdname/primaryboot)
|
||||
if [ $primaryboot -eq 0 ]; then
|
||||
echo 1 > /proc/boot_info/$mtdname/primaryboot
|
||||
else
|
||||
echo 0 > /proc/boot_info/$mtdname/primaryboot
|
||||
fi
|
||||
|
||||
mtdname=$(cat /proc/boot_info/$mtdname/upgradepartition)
|
||||
}
|
||||
|
||||
mtdpart=$(grep "\"${mtdname}\"" /proc/mtd | awk -F: '{print $1}')
|
||||
ubiformat /dev/${mtdpart} -y -f /tmp/${bin}.bin
|
||||
}
|
||||
|
||||
do_flash_tz() {
|
||||
local sec=$1
|
||||
local mtdpart=$(grep "\"0:QSEE\"" /proc/mtd | awk -F: '{print $1}')
|
||||
local emmcblock="$(find_mmc_part "0:QSEE")"
|
||||
|
||||
if [ -n "$mtdpart" -o -e "$emmcblock" ]; then
|
||||
do_flash_failsafe_partition ${sec} "0:QSEE"
|
||||
else
|
||||
do_flash_failsafe_partition ${sec} "0:TZ"
|
||||
fi
|
||||
}
|
||||
|
||||
do_flash_ddr() {
|
||||
local sec=$1
|
||||
local mtdpart=$(grep "\"0:CDT\"" /proc/mtd | awk -F: '{print $1}')
|
||||
local emmcblock="$(find_mmc_part "0:CDT")"
|
||||
|
||||
if [ -n "$mtdpart" -o -e "$emmcblock" ]; then
|
||||
do_flash_failsafe_partition ${sec} "0:CDT"
|
||||
else
|
||||
do_flash_failsafe_partition ${sec} "0:DDRPARAMS"
|
||||
fi
|
||||
}
|
||||
|
||||
to_upper () {
|
||||
echo $1 | awk '{print toupper($0)}'
|
||||
}
|
||||
|
||||
flash_section() {
|
||||
local sec=$1
|
||||
|
||||
local board=$(board_name)
|
||||
case "${sec}" in
|
||||
hlos*) switch_layout linux; do_flash_failsafe_partition ${sec} "0:HLOS";;
|
||||
rootfs*) switch_layout linux; do_flash_failsafe_partition ${sec} "rootfs";;
|
||||
fs*) switch_layout linux; do_flash_failsafe_partition ${sec} "rootfs";;
|
||||
ubi*) switch_layout linux; do_flash_ubi ${sec} "rootfs";;
|
||||
#sbl1*) switch_layout boot; do_flash_partition ${sec} "0:SBL1";;
|
||||
#sbl2*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:SBL2";;
|
||||
#sbl3*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:SBL3";;
|
||||
#mibib*) switch_layout boot; do_flash_partition ${sec} "0:MIBIB";;
|
||||
#dtb-$(to_upper $board)*) switch_layout boot; do_flash_partition ${sec} "0:DTB";;
|
||||
u-boot*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:APPSBL";;
|
||||
#ddr-$(to_upper $board)*) switch_layout boot; do_flash_ddr ${sec};;
|
||||
ddr-${board}-*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:CDT";;
|
||||
#ssd*) switch_layout boot; do_flash_partition ${sec} "0:SSD";;
|
||||
tz*) switch_layout boot; do_flash_tz ${sec};;
|
||||
#rpm*) switch_layout boot; do_flash_failsafe_partition ${sec} "0:RPM";;
|
||||
*) echo "Section ${sec} ignored"; return 1;;
|
||||
esac
|
||||
|
||||
echo "Flashed ${sec}"
|
||||
}
|
||||
|
||||
erase_emmc_config() {
|
||||
local emmcblock="$(find_mmc_part "rootfs_data")"
|
||||
if [ -e "$emmcblock" ]; then
|
||||
dd if=/dev/zero of=${emmcblock}
|
||||
mkfs.ext4 "$emmcblock"
|
||||
fi
|
||||
}
|
||||
|
||||
platform_pre_upgrade() {
|
||||
cp /sbin/upgraded /tmp
|
||||
ubus call system nandupgrade "{\"path\": \"$1\" }"
|
||||
}
|
||||
|
||||
platform_check_image_ipq() {
|
||||
local board=$(board_name)
|
||||
|
||||
local mandatory_nand="ubi"
|
||||
local mandatory_nor_emmc="hlos fs"
|
||||
local mandatory_nor="hlos"
|
||||
local mandatory_section_found=0
|
||||
local optional="sbl2 u-boot ddr-${board} ssd tz rpm"
|
||||
local ignored="mibib bootconfig sbl1"
|
||||
|
||||
image_is_FIT $1 || return 1
|
||||
|
||||
image_has_mandatory_section $1 ${mandatory_nand} && {\
|
||||
mandatory_section_found=1
|
||||
}
|
||||
|
||||
image_has_mandatory_section $1 ${mandatory_nor_emmc} && {\
|
||||
mandatory_section_found=1
|
||||
}
|
||||
|
||||
image_has_mandatory_section $1 ${mandatory_nor} && {\
|
||||
mandatory_section_found=1
|
||||
}
|
||||
|
||||
if [ $mandatory_section_found -eq 0 ]; then
|
||||
echo "Error: mandatory section(s) missing from \"$1\". Abort..."
|
||||
return 1
|
||||
fi
|
||||
|
||||
for sec in ${optional}; do
|
||||
image_contains $1 ${sec} || {\
|
||||
echo "Warning: optional section \"${sec}\" missing from \"$1\". Continue..."
|
||||
}
|
||||
done
|
||||
|
||||
for sec in ${ignored}; do
|
||||
image_contains $1 ${sec} && {\
|
||||
echo "Warning: section \"${sec}\" will be ignored from \"$1\". Continue..."
|
||||
}
|
||||
done
|
||||
|
||||
image_demux $1 || {\
|
||||
echo "Error: \"$1\" couldn't be extracted. Abort..."
|
||||
return 1
|
||||
}
|
||||
|
||||
[ -f /tmp/hlos_version ] && rm -f /tmp/*_version
|
||||
dumpimage -c $1 2>/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
platform_version_upgrade() {
|
||||
local version_files="appsbl_version sbl_version tz_version hlos_version rpm_version"
|
||||
local sys="/sys/devices/system/qfprom/qfprom0/"
|
||||
local tmp="/tmp/"
|
||||
|
||||
for file in $version_files; do
|
||||
[ -f "${tmp}${file}" ] && {
|
||||
echo "Updating "${sys}${file}" with `cat "${tmp}${file}"`"
|
||||
echo `cat "${tmp}${file}"` > "${sys}${file}"
|
||||
rm -f "${tmp}${file}"
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# The U-Boot loader of the OpenMesh devices requires image sizes and
|
||||
# checksums to be provided in the U-Boot environment.
|
||||
# The OpenMesh devices come with 2 main partitions - while one is active
|
||||
# sysupgrade will flash the other. The boot order is changed to boot the
|
||||
# newly flashed partition. If the new partition can't be booted due to
|
||||
# upgrade failures the previously used partition is loaded.
|
||||
|
||||
platform_do_upgrade_ipq() {
|
||||
local board=$(board_name)
|
||||
|
||||
# verify some things exist before erasing
|
||||
if [ ! -e $1 ]; then
|
||||
echo "Error: Can't find $1 after switching to ramfs, aborting upgrade!"
|
||||
reboot
|
||||
fi
|
||||
|
||||
for sec in $(print_sections $1); do
|
||||
if [ ! -e /tmp/${sec}.bin ]; then
|
||||
echo "Error: Cant' find ${sec} after switching to ramfs, aborting upgrade!"
|
||||
reboot
|
||||
fi
|
||||
done
|
||||
|
||||
case "$board" in
|
||||
teltonika,rutx)
|
||||
for sec in $(print_sections $1); do
|
||||
flash_section ${sec}
|
||||
done
|
||||
|
||||
switch_layout linux
|
||||
# update bootconfig to register that fw upgrade has been done
|
||||
do_flash_bootconfig bootconfig "0:BOOTCONFIG"
|
||||
do_flash_bootconfig bootconfig1 "0:BOOTCONFIG1"
|
||||
platform_version_upgrade
|
||||
|
||||
erase_emmc_config
|
||||
return 0;
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Upgrade failed!"
|
||||
return 1;
|
||||
}
|
||||
|
||||
platform_copy_config() {
|
||||
local emmcblock="$(find_mmc_part "rootfs_data")"
|
||||
mkdir -p /tmp/overlay
|
||||
|
||||
if [ -e "$emmcblock" ]; then
|
||||
mount -t ext4 "$emmcblock" /tmp/overlay
|
||||
cp /tmp/sysupgrade.tgz /tmp/overlay/
|
||||
sync
|
||||
umount /tmp/overlay
|
||||
else
|
||||
local mtdname=rootfs
|
||||
local mtdpart
|
||||
|
||||
[ -f /proc/boot_info/$mtdname/upgradepartition ] && {
|
||||
mtdname=$(cat /proc/boot_info/$mtdname/upgradepartition)
|
||||
}
|
||||
|
||||
mtdpart=$(grep "\"${mtdname}\"" /proc/mtd | awk -F: '{print $1}')
|
||||
ubiattach -p /dev/${mtdpart}
|
||||
mount -t ubifs ubi0:rootfs_data /tmp/overlay
|
||||
cp /tmp/sysupgrade.tgz /tmp/overlay/
|
||||
sync
|
||||
umount /tmp/overlay
|
||||
fi
|
||||
}
|
|
@ -185,7 +185,8 @@ platform_do_upgrade() {
|
|||
platform_do_upgrade_dualboot_datachk "$1"
|
||||
;;
|
||||
teltonika,rutx)
|
||||
platform_do_upgrade_ipq "$1"
|
||||
CI_UBIPART="rootfs"
|
||||
nand_do_upgrade "$1"
|
||||
;;
|
||||
zte,mf286d)
|
||||
CI_UBIPART="rootfs"
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <blogic@openwrt.org>
|
||||
Date: Tue, 12 Aug 2014 20:49:27 +0200
|
||||
Subject: [PATCH 24/53] GPIO: add named gpio exports
|
||||
|
||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||
---
|
||||
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/gpio/gpiolib-sysfs.c | 10 +++++-
|
||||
include/asm-generic/gpio.h | 6 ++++
|
||||
include/linux/gpio/consumer.h | 8 +++++
|
||||
4 files changed, 91 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpio/gpiolib-of.c
|
||||
+++ b/drivers/gpio/gpiolib-of.c
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-of.h"
|
||||
@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip
|
||||
{
|
||||
of_node_put(chip->of_node);
|
||||
}
|
||||
+
|
||||
+static struct of_device_id gpio_export_ids[] = {
|
||||
+ { .compatible = "gpio-export" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int of_gpio_export_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ struct device_node *cnp;
|
||||
+ u32 val;
|
||||
+ int nb = 0;
|
||||
+
|
||||
+ for_each_child_of_node(np, cnp) {
|
||||
+ const char *name = NULL;
|
||||
+ int gpio;
|
||||
+ bool dmc;
|
||||
+ int max_gpio = 1;
|
||||
+ int i;
|
||||
+
|
||||
+ of_property_read_string(cnp, "gpio-export,name", &name);
|
||||
+
|
||||
+ if (!name)
|
||||
+ max_gpio = of_gpio_count(cnp);
|
||||
+
|
||||
+ for (i = 0; i < max_gpio; i++) {
|
||||
+ unsigned flags = 0;
|
||||
+ enum of_gpio_flags of_flags;
|
||||
+
|
||||
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
|
||||
+ if (!gpio_is_valid(gpio))
|
||||
+ return gpio;
|
||||
+
|
||||
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
|
||||
+ flags |= GPIOF_ACTIVE_LOW;
|
||||
+
|
||||
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
|
||||
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ flags |= GPIOF_IN;
|
||||
+
|
||||
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
|
||||
+ continue;
|
||||
+
|
||||
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
|
||||
+ gpio_export_with_name(gpio, dmc, name);
|
||||
+ nb++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver gpio_export_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "gpio-export",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = of_match_ptr(gpio_export_ids),
|
||||
+ },
|
||||
+ .probe = of_gpio_export_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(gpio_export_driver);
|
||||
--- a/drivers/gpio/gpiolib-sysfs.c
|
||||
+++ b/drivers/gpio/gpiolib-sysfs.c
|
||||
@@ -571,7 +571,7 @@ static struct class gpio_class = {
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_device *gdev;
|
||||
@@ -633,6 +633,8 @@ int gpiod_export(struct gpio_desc *desc,
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
if (chip->names && chip->names[offset])
|
||||
ioname = chip->names[offset];
|
||||
+ if (name)
|
||||
+ ioname = name;
|
||||
|
||||
dev = device_create_with_groups(&gpio_class, &gdev->dev,
|
||||
MKDEV(0, 0), data, gpio_groups,
|
||||
@@ -654,6 +656,12 @@ err_unlock:
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(__gpiod_export);
|
||||
+
|
||||
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
+{
|
||||
+ return __gpiod_export(desc, direction_may_change, NULL);
|
||||
+}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export);
|
||||
|
||||
static int match_export(struct device *dev, const void *desc)
|
||||
--- a/include/asm-generic/gpio.h
|
||||
+++ b/include/asm-generic/gpio.h
|
||||
@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
|
||||
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
|
||||
}
|
||||
|
||||
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
|
||||
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
|
||||
+{
|
||||
+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
|
||||
+}
|
||||
+
|
||||
static inline int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
{
|
||||
--- a/include/linux/gpio/consumer.h
|
||||
+++ b/include/linux/gpio/consumer.h
|
||||
@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
|
||||
|
||||
+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc);
|
||||
@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de
|
||||
|
||||
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
|
||||
|
||||
+static inline int _gpiod_export(struct gpio_desc *desc,
|
||||
+ bool direction_may_change,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+
|
||||
static inline int gpiod_export(struct gpio_desc *desc,
|
||||
bool direction_may_change)
|
||||
{
|
|
@ -1,33 +0,0 @@
|
|||
Index: linux-5.4.137/drivers/usb/serial/option.c
|
||||
===================================================================
|
||||
--- linux-5.4.137.orig/drivers/usb/serial/option.c
|
||||
+++ linux-5.4.137/drivers/usb/serial/option.c
|
||||
@@ -241,6 +241,8 @@ static void option_instat_callback(struc
|
||||
#define UBLOX_PRODUCT_R6XX 0x90fa
|
||||
/* These Yuga products use Qualcomm's vendor ID */
|
||||
#define YUGA_PRODUCT_CLM920_NC5 0x9625
|
||||
+/* These Meiglink products use Qualcomm's vendor ID */
|
||||
+#define MEIGLINK_PRODUCT_SLM750 0xf601
|
||||
|
||||
#define QUECTEL_VENDOR_ID 0x2c7c
|
||||
/* These Quectel products use Quectel's vendor ID */
|
||||
@@ -1102,4 +1104,7 @@ static const struct usb_device_id option
|
||||
/* u-blox products using Qualcomm vendor ID */
|
||||
{ USB_DEVICE(QUALCOMM_VENDOR_ID, UBLOX_PRODUCT_R410M),
|
||||
.driver_info = RSVD(1) | RSVD(3) },
|
||||
+ /* Meiglink products using Qualcomm vendor ID */
|
||||
+ // Works OK in case of some issues check macros that are used by Quectel Products
|
||||
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750)},
|
||||
/* Quectel products using Quectel vendor ID */
|
||||
Index: linux-5.4.137/drivers/net/usb/qmi_wwan.c
|
||||
===================================================================
|
||||
--- linux-5.4.137.orig/drivers/net/usb/qmi_wwan.c
|
||||
+++ linux-5.4.137/drivers/net/usb/qmi_wwan.c
|
||||
@@ -1171,6 +1171,7 @@ static const struct usb_device_id produc
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9079, 6)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9079, 7)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9079, 8)},
|
||||
+ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* Meiglink SLM750 (in case of issues check if DTR flag setting is enough) */
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9080, 5)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9080, 6)},
|
||||
{QMI_FIXED_INTF(0x05c6, 0x9080, 7)},
|
Loading…
Reference in a new issue