Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea845f76ea | ||
|
|
9a599fee93 | ||
|
|
30de1b5031 | ||
|
|
fa4ec03993 | ||
|
|
a7fb589e8a | ||
|
|
5db6914f7c | ||
|
|
f7a43e4606 | ||
|
|
c1fcca50ba | ||
|
|
2050bc4f64 | ||
|
|
bc8e24c654 | ||
|
|
f1de43d0a0 | ||
|
|
a077c6da98 | ||
|
|
b6487c3ccc | ||
|
|
33457ebf0b | ||
|
|
cc8326443d | ||
|
|
1918404b1d | ||
|
|
07ea71c7b7 | ||
|
|
fb31038e1f | ||
|
|
329b1543f3 | ||
|
|
42c8610efc | ||
|
|
bb5d415b19 | ||
|
|
737ee934d2 | ||
|
|
a78fd5bbb6 | ||
|
|
0c21f06ef7 | ||
|
|
a2ce32579f | ||
|
|
c2d55b73d9 |
@@ -1,4 +1,4 @@
|
||||
src-git-full packages https://git.openwrt.org/feed/packages.git^088222c39da9c20f5c93769d009443d7bbf294c7
|
||||
src-git-full luci https://git.openwrt.org/project/luci.git^709d48b72657084a27db1fb6fc0a4a4e8939552f
|
||||
src-git-full packages https://git.openwrt.org/feed/packages.git^dba8a0102e5965cad58a871335002e9c964b6719
|
||||
src-git-full luci https://git.openwrt.org/project/luci.git^96ec0cd3ccfe954f13fd5a337efdd70374dde03f
|
||||
src-git-full routing https://git.openwrt.org/feed/routing.git^85028704f688a6768d3f10d5d3c10a799a121e0d
|
||||
src-git-full telephony https://git.openwrt.org/feed/telephony.git^1d2031a5c82816483c51bca15649e2957fbe2bc2
|
||||
|
||||
@@ -524,7 +524,7 @@ endif
|
||||
define Device/Build/compile
|
||||
$$(_COMPILE_TARGET): $(KDIR)/$(1)
|
||||
$(eval $(call Device/Export,$(KDIR)/$(1)))
|
||||
$(KDIR)/$(1):
|
||||
$(KDIR)/$(1): FORCE
|
||||
$$(call concat_cmd,$(COMPILE/$(1)))
|
||||
|
||||
endef
|
||||
|
||||
@@ -23,13 +23,13 @@ PKG_CONFIG_DEPENDS += \
|
||||
sanitize = $(call tolower,$(subst _,-,$(subst $(space),-,$(1))))
|
||||
|
||||
VERSION_NUMBER:=$(call qstrip,$(CONFIG_VERSION_NUMBER))
|
||||
VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),22.03.1)
|
||||
VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),22.03.2)
|
||||
|
||||
VERSION_CODE:=$(call qstrip,$(CONFIG_VERSION_CODE))
|
||||
VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),r19777-2853b6d652)
|
||||
VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),r19803-9a599fee93)
|
||||
|
||||
VERSION_REPO:=$(call qstrip,$(CONFIG_VERSION_REPO))
|
||||
VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://downloads.openwrt.org/releases/22.03.1)
|
||||
VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://downloads.openwrt.org/releases/22.03.2)
|
||||
|
||||
VERSION_DIST:=$(call qstrip,$(CONFIG_VERSION_DIST))
|
||||
VERSION_DIST:=$(if $(VERSION_DIST),$(VERSION_DIST),OpenWrt)
|
||||
|
||||
@@ -183,7 +183,7 @@ if VERSIONOPT
|
||||
config VERSION_REPO
|
||||
string
|
||||
prompt "Release repository"
|
||||
default "https://downloads.openwrt.org/releases/22.03.1"
|
||||
default "https://downloads.openwrt.org/releases/22.03.2"
|
||||
help
|
||||
This is the repository address embedded in the image, it defaults
|
||||
to the trunk snapshot repo; the url may contain the following placeholders:
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Mon, 20 Sep 2021 15:40:07 +0200
|
||||
Subject: [PATCH] mac80211: mesh: clean up rx_bcn_presp API
|
||||
|
||||
commit a5b983c6073140b624f64e79fea6d33c3e4315a0 upstream.
|
||||
|
||||
We currently pass the entire elements to the rx_bcn_presp()
|
||||
method, but only need mesh_config. Additionally, we use the
|
||||
length of the elements to calculate back the entire frame's
|
||||
length, but that's confusing - just pass the length of the
|
||||
frame instead.
|
||||
|
||||
Link: https://lore.kernel.org/r/20210920154009.a18ed3d2da6c.I1824b773a0fbae4453e1433c184678ca14e8df45@changeid
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -645,10 +645,9 @@ struct ieee80211_if_ocb {
|
||||
*/
|
||||
struct ieee802_11_elems;
|
||||
struct ieee80211_mesh_sync_ops {
|
||||
- void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata,
|
||||
- u16 stype,
|
||||
- struct ieee80211_mgmt *mgmt,
|
||||
- struct ieee802_11_elems *elems,
|
||||
+ void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype,
|
||||
+ struct ieee80211_mgmt *mgmt, unsigned int len,
|
||||
+ const struct ieee80211_meshconf_ie *mesh_cfg,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
|
||||
/* should be called with beacon_data under RCU read lock */
|
||||
--- a/net/mac80211/mesh.c
|
||||
+++ b/net/mac80211/mesh.c
|
||||
@@ -1354,8 +1354,8 @@ static void ieee80211_mesh_rx_bcn_presp(
|
||||
}
|
||||
|
||||
if (ifmsh->sync_ops)
|
||||
- ifmsh->sync_ops->rx_bcn_presp(sdata,
|
||||
- stype, mgmt, &elems, rx_status);
|
||||
+ ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
|
||||
+ elems.mesh_config, rx_status);
|
||||
}
|
||||
|
||||
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
|
||||
--- a/net/mac80211/mesh_sync.c
|
||||
+++ b/net/mac80211/mesh_sync.c
|
||||
@@ -3,6 +3,7 @@
|
||||
* Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
|
||||
* Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
|
||||
* Copyright 2011-2012, cozybit Inc.
|
||||
+ * Copyright (C) 2021 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
@@ -35,12 +36,12 @@ struct sync_method {
|
||||
/**
|
||||
* mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
|
||||
*
|
||||
- * @ie: information elements of a management frame from the mesh peer
|
||||
+ * @cfg: mesh config element from the mesh peer (or %NULL)
|
||||
*/
|
||||
-static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
|
||||
+static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg)
|
||||
{
|
||||
- return (ie->mesh_config->meshconf_cap &
|
||||
- IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
|
||||
+ return cfg &&
|
||||
+ (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING);
|
||||
}
|
||||
|
||||
void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
|
||||
@@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee802
|
||||
}
|
||||
}
|
||||
|
||||
-static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
||||
- u16 stype,
|
||||
- struct ieee80211_mgmt *mgmt,
|
||||
- struct ieee802_11_elems *elems,
|
||||
- struct ieee80211_rx_status *rx_status)
|
||||
+static void
|
||||
+mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
|
||||
+ struct ieee80211_mgmt *mgmt, unsigned int len,
|
||||
+ const struct ieee80211_meshconf_ie *mesh_cfg,
|
||||
+ struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_pres
|
||||
*/
|
||||
if (ieee80211_have_rx_timestamp(rx_status))
|
||||
t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
|
||||
- 24 + 12 +
|
||||
- elems->total_len +
|
||||
- FCS_LEN,
|
||||
- 24);
|
||||
+ len + FCS_LEN, 24);
|
||||
else
|
||||
t_r = drv_get_tsf(local, sdata);
|
||||
|
||||
@@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_pres
|
||||
* dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
|
||||
*/
|
||||
|
||||
- if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
|
||||
+ if (mesh_peer_tbtt_adjusting(mesh_cfg)) {
|
||||
msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
|
||||
sta->sta.addr);
|
||||
goto no_sync;
|
||||
@@ -0,0 +1,82 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Mon, 20 Sep 2021 15:40:08 +0200
|
||||
Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems
|
||||
|
||||
commit c6e37ed498f958254b5459253199e816b6bfc52f upstream.
|
||||
|
||||
We're currently returning this value, but to prepare for
|
||||
returning the allocated structure, move it into there.
|
||||
|
||||
Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1530,6 +1530,7 @@ struct ieee80211_csa_ie {
|
||||
struct ieee802_11_elems {
|
||||
const u8 *ie_start;
|
||||
size_t total_len;
|
||||
+ u32 crc;
|
||||
|
||||
/* pointers to IEs */
|
||||
const struct ieee80211_tdls_lnkie *lnk_id;
|
||||
@@ -2089,10 +2090,10 @@ static inline void ieee80211_tx_skb(stru
|
||||
ieee80211_tx_skb_tid(sdata, skb, 7);
|
||||
}
|
||||
|
||||
-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
- struct ieee802_11_elems *elems,
|
||||
- u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
- u8 *bss_bssid);
|
||||
+void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
+ struct ieee802_11_elems *elems,
|
||||
+ u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
+ u8 *bss_bssid);
|
||||
static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
bool action,
|
||||
struct ieee802_11_elems *elems,
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -4102,10 +4102,11 @@ static void ieee80211_rx_mgmt_beacon(str
|
||||
*/
|
||||
if (!ieee80211_is_s1g_beacon(hdr->frame_control))
|
||||
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
|
||||
- ncrc = ieee802_11_parse_elems_crc(variable,
|
||||
- len - baselen, false, &elems,
|
||||
- care_about_ies, ncrc,
|
||||
- mgmt->bssid, bssid);
|
||||
+ ieee802_11_parse_elems_crc(variable,
|
||||
+ len - baselen, false, &elems,
|
||||
+ care_about_ies, ncrc,
|
||||
+ mgmt->bssid, bssid);
|
||||
+ ncrc = elems.crc;
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1469,10 +1469,10 @@ static size_t ieee802_11_find_bssid_prof
|
||||
return found ? profile_len : 0;
|
||||
}
|
||||
|
||||
-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
- struct ieee802_11_elems *elems,
|
||||
- u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
- u8 *bss_bssid)
|
||||
+void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
+ struct ieee802_11_elems *elems,
|
||||
+ u64 filter, u32 crc, u8 *transmitter_bssid,
|
||||
+ u8 *bss_bssid)
|
||||
{
|
||||
const struct element *non_inherit = NULL;
|
||||
u8 *nontransmitted_profile;
|
||||
@@ -1524,7 +1524,7 @@ u32 ieee802_11_parse_elems_crc(const u8
|
||||
|
||||
kfree(nontransmitted_profile);
|
||||
|
||||
- return crc;
|
||||
+ elems->crc = crc;
|
||||
}
|
||||
|
||||
void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
|
||||
@@ -0,0 +1,80 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Mon, 20 Sep 2021 15:40:09 +0200
|
||||
Subject: [PATCH] mac80211: mlme: find auth challenge directly
|
||||
|
||||
commit 49a765d6785e99157ff5091cc37485732496864e upstream.
|
||||
|
||||
There's no need to parse all elements etc. just to find the
|
||||
authentication challenge - use cfg80211_find_elem() instead.
|
||||
This also allows us to remove WLAN_EID_CHALLENGE handling
|
||||
from the element parsing entirely.
|
||||
|
||||
Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1540,7 +1540,6 @@ struct ieee802_11_elems {
|
||||
const u8 *supp_rates;
|
||||
const u8 *ds_params;
|
||||
const struct ieee80211_tim_ie *tim;
|
||||
- const u8 *challenge;
|
||||
const u8 *rsn;
|
||||
const u8 *rsnx;
|
||||
const u8 *erp_info;
|
||||
@@ -1594,7 +1593,6 @@ struct ieee802_11_elems {
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
u8 tim_len;
|
||||
- u8 challenge_len;
|
||||
u8 rsn_len;
|
||||
u8 rsnx_len;
|
||||
u8 ext_supp_rates_len;
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -2889,17 +2889,17 @@ static void ieee80211_auth_challenge(str
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
|
||||
+ const struct element *challenge;
|
||||
u8 *pos;
|
||||
- struct ieee802_11_elems elems;
|
||||
u32 tx_flags = 0;
|
||||
struct ieee80211_prep_tx_info info = {
|
||||
.subtype = IEEE80211_STYPE_AUTH,
|
||||
};
|
||||
|
||||
pos = mgmt->u.auth.variable;
|
||||
- ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
|
||||
- mgmt->bssid, auth_data->bss->bssid);
|
||||
- if (!elems.challenge)
|
||||
+ challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos,
|
||||
+ len - (pos - (u8 *)mgmt));
|
||||
+ if (!challenge)
|
||||
return;
|
||||
auth_data->expected_transaction = 4;
|
||||
drv_mgd_prepare_tx(sdata->local, sdata, &info);
|
||||
@@ -2907,7 +2907,8 @@ static void ieee80211_auth_challenge(str
|
||||
tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||
IEEE80211_TX_INTFL_MLME_CONN_TX;
|
||||
ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
|
||||
- elems.challenge - 2, elems.challenge_len + 2,
|
||||
+ (void *)challenge,
|
||||
+ challenge->datalen + sizeof(*challenge),
|
||||
auth_data->bss->bssid, auth_data->bss->bssid,
|
||||
auth_data->key, auth_data->key_len,
|
||||
auth_data->key_idx, tx_flags);
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1120,10 +1120,6 @@ _ieee802_11_parse_elems_crc(const u8 *st
|
||||
} else
|
||||
elem_parse_failed = true;
|
||||
break;
|
||||
- case WLAN_EID_CHALLENGE:
|
||||
- elems->challenge = pos;
|
||||
- elems->challenge_len = elen;
|
||||
- break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
||||
pos[2] == 0xf2) {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 1 Oct 2021 21:11:08 +0200
|
||||
Subject: [PATCH] mac80211: fix memory leaks with element parsing
|
||||
|
||||
commit 8223ac199a3849257e86ec27865dc63f034b1cf1 upstream.
|
||||
|
||||
My previous commit 5d24828d05f3 ("mac80211: always allocate
|
||||
struct ieee802_11_elems") had a few bugs and leaked the new
|
||||
allocated struct in a few error cases, fix that.
|
||||
|
||||
Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/agg-rx.c
|
||||
+++ b/net/mac80211/agg-rx.c
|
||||
@@ -499,13 +499,14 @@ void ieee80211_process_addba_request(str
|
||||
elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
if (!elems || elems->parse_error)
|
||||
- return;
|
||||
+ goto free;
|
||||
}
|
||||
|
||||
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
|
||||
start_seq_num, ba_policy, tid,
|
||||
buf_size, true, false,
|
||||
elems ? elems->addba_ext_ie : NULL);
|
||||
+free:
|
||||
kfree(elems);
|
||||
}
|
||||
|
||||
--- a/net/mac80211/ibss.c
|
||||
+++ b/net/mac80211/ibss.c
|
||||
@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struc
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
- if (!elems || elems->parse_error)
|
||||
- break;
|
||||
-
|
||||
- ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
|
||||
- rx_status, elems);
|
||||
+ if (elems && !elems->parse_error)
|
||||
+ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
|
||||
+ skb->len,
|
||||
+ rx_status,
|
||||
+ elems);
|
||||
kfree(elems);
|
||||
break;
|
||||
}
|
||||
--- a/net/mac80211/mlme.c
|
||||
+++ b/net/mac80211/mlme.c
|
||||
@@ -3374,8 +3374,10 @@ static bool ieee80211_assoc_success(stru
|
||||
bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
|
||||
GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
- if (!bss_ies)
|
||||
- return false;
|
||||
+ if (!bss_ies) {
|
||||
+ ret = false;
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
|
||||
false, mgmt->bssid,
|
||||
@@ -4358,13 +4360,11 @@ void ieee80211_sta_rx_queued_mgmt(struct
|
||||
mgmt->u.action.u.chan_switch.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
- if (!elems || elems->parse_error)
|
||||
- break;
|
||||
-
|
||||
- ieee80211_sta_process_chanswitch(sdata,
|
||||
- rx_status->mactime,
|
||||
- rx_status->device_timestamp,
|
||||
- elems, false);
|
||||
+ if (elems && !elems->parse_error)
|
||||
+ ieee80211_sta_process_chanswitch(sdata,
|
||||
+ rx_status->mactime,
|
||||
+ rx_status->device_timestamp,
|
||||
+ elems, false);
|
||||
kfree(elems);
|
||||
} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
|
||||
struct ieee802_11_elems *elems;
|
||||
@@ -4384,17 +4384,17 @@ void ieee80211_sta_rx_queued_mgmt(struct
|
||||
mgmt->u.action.u.ext_chan_switch.variable,
|
||||
ies_len, true, mgmt->bssid, NULL);
|
||||
|
||||
- if (!elems || elems->parse_error)
|
||||
- break;
|
||||
+ if (elems && !elems->parse_error) {
|
||||
+ /* for the handling code pretend it was an IE */
|
||||
+ elems->ext_chansw_ie =
|
||||
+ &mgmt->u.action.u.ext_chan_switch.data;
|
||||
+
|
||||
+ ieee80211_sta_process_chanswitch(sdata,
|
||||
+ rx_status->mactime,
|
||||
+ rx_status->device_timestamp,
|
||||
+ elems, false);
|
||||
+ }
|
||||
|
||||
- /* for the handling code pretend this was also an IE */
|
||||
- elems->ext_chansw_ie =
|
||||
- &mgmt->u.action.u.ext_chan_switch.data;
|
||||
-
|
||||
- ieee80211_sta_process_chanswitch(sdata,
|
||||
- rx_status->mactime,
|
||||
- rx_status->device_timestamp,
|
||||
- elems, false);
|
||||
kfree(elems);
|
||||
}
|
||||
break;
|
||||
@@ -0,0 +1,41 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 28 Sep 2022 21:56:15 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: fix u8 overflow in
|
||||
cfg80211_update_notlisted_nontrans()
|
||||
|
||||
commit aebe9f4639b13a1f4e9a6b42cdd2e38c617b442d upstream.
|
||||
|
||||
In the copy code of the elements, we do the following calculation
|
||||
to reach the end of the MBSSID element:
|
||||
|
||||
/* copy the IEs after MBSSID */
|
||||
cpy_len = mbssid[1] + 2;
|
||||
|
||||
This looks fine, however, cpy_len is a u8, the same as mbssid[1],
|
||||
so the addition of two can overflow. In this case the subsequent
|
||||
memcpy() will overflow the allocated buffer, since it copies 256
|
||||
bytes too much due to the way the allocation and memcpy() sizes
|
||||
are calculated.
|
||||
|
||||
Fix this by using size_t for the cpy_len variable.
|
||||
|
||||
This fixes CVE-2022-41674.
|
||||
|
||||
Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Tested-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
|
||||
Reviewed-by: Kees Cook <keescook@chromium.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -2238,7 +2238,7 @@ cfg80211_update_notlisted_nontrans(struc
|
||||
size_t new_ie_len;
|
||||
struct cfg80211_bss_ies *new_ies;
|
||||
const struct cfg80211_bss_ies *old;
|
||||
- u8 cpy_len;
|
||||
+ size_t cpy_len;
|
||||
|
||||
lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 28 Sep 2022 22:01:37 +0200
|
||||
Subject: [PATCH] wifi: cfg80211/mac80211: reject bad MBSSID elements
|
||||
|
||||
commit 8f033d2becc24aa6bfd2a5c104407963560caabc upstream
|
||||
|
||||
Per spec, the maximum value for the MaxBSSID ('n') indicator is 8,
|
||||
and the minimum is 1 since a multiple BSSID set with just one BSSID
|
||||
doesn't make sense (the # of BSSIDs is limited by 2^n).
|
||||
|
||||
Limit this in the parsing in both cfg80211 and mac80211, rejecting
|
||||
any elements with an invalid value.
|
||||
|
||||
This fixes potentially bad shifts in the processing of these inside
|
||||
the cfg80211_gen_new_bssid() function later.
|
||||
|
||||
I found this during the investigation of CVE-2022-41674 fixed by the
|
||||
previous patch.
|
||||
|
||||
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
|
||||
Fixes: 78ac51f81532 ("mac80211: support multi-bssid")
|
||||
Reviewed-by: Kees Cook <keescook@chromium.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1413,6 +1413,8 @@ static size_t ieee802_11_find_bssid_prof
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
|
||||
if (elem->datalen < 2)
|
||||
continue;
|
||||
+ if (elem->data[0] < 1 || elem->data[0] > 8)
|
||||
+ continue;
|
||||
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
u8 new_bssid[ETH_ALEN];
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -2103,6 +2103,8 @@ static void cfg80211_parse_mbssid_data(s
|
||||
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
|
||||
if (elem->datalen < 4)
|
||||
continue;
|
||||
+ if (elem->data[0] < 1 || (int)elem->data[0] > 8)
|
||||
+ continue;
|
||||
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
|
||||
u8 profile_len;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 28 Sep 2022 22:07:15 +0200
|
||||
Subject: [PATCH] wifi: mac80211: fix MBSSID parsing use-after-free
|
||||
|
||||
commit ff05d4b45dd89b922578dac497dcabf57cf771c6
|
||||
|
||||
When we parse a multi-BSSID element, we might point some
|
||||
element pointers into the allocated nontransmitted_profile.
|
||||
However, we free this before returning, causing UAF when the
|
||||
relevant pointers in the parsed elements are accessed.
|
||||
|
||||
Fix this by not allocating the scratch buffer separately but
|
||||
as part of the returned structure instead, that way, there
|
||||
are no lifetime issues with it.
|
||||
|
||||
The scratch buffer introduction as part of the returned data
|
||||
here is taken from MLO feature work done by Ilan.
|
||||
|
||||
This fixes CVE-2022-42719.
|
||||
|
||||
Fixes: 5023b14cf4df ("mac80211: support profile split between elements")
|
||||
Co-developed-by: Ilan Peer <ilan.peer@intel.com>
|
||||
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
|
||||
Reviewed-by: Kees Cook <keescook@chromium.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1611,6 +1611,14 @@ struct ieee802_11_elems {
|
||||
|
||||
/* whether a parse error occurred while retrieving these elements */
|
||||
bool parse_error;
|
||||
+
|
||||
+ /*
|
||||
+ * scratch buffer that can be used for various element parsing related
|
||||
+ * tasks, e.g., element de-fragmentation etc.
|
||||
+ */
|
||||
+ size_t scratch_len;
|
||||
+ u8 *scratch_pos;
|
||||
+ u8 scratch[];
|
||||
};
|
||||
|
||||
static inline struct ieee80211_local *hw_to_local(
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1478,24 +1478,25 @@ struct ieee802_11_elems *ieee802_11_pars
|
||||
u8 *nontransmitted_profile;
|
||||
int nontransmitted_profile_len = 0;
|
||||
|
||||
- elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
|
||||
+ elems = kzalloc(sizeof(*elems) + len, GFP_ATOMIC);
|
||||
if (!elems)
|
||||
return NULL;
|
||||
elems->ie_start = start;
|
||||
elems->total_len = len;
|
||||
|
||||
- nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
|
||||
- if (nontransmitted_profile) {
|
||||
- nontransmitted_profile_len =
|
||||
- ieee802_11_find_bssid_profile(start, len, elems,
|
||||
- transmitter_bssid,
|
||||
- bss_bssid,
|
||||
- nontransmitted_profile);
|
||||
- non_inherit =
|
||||
- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
|
||||
- nontransmitted_profile,
|
||||
- nontransmitted_profile_len);
|
||||
- }
|
||||
+ elems->scratch_len = len;
|
||||
+ elems->scratch_pos = elems->scratch;
|
||||
+
|
||||
+ nontransmitted_profile = elems->scratch_pos;
|
||||
+ nontransmitted_profile_len =
|
||||
+ ieee802_11_find_bssid_profile(start, len, elems,
|
||||
+ transmitter_bssid,
|
||||
+ bss_bssid,
|
||||
+ nontransmitted_profile);
|
||||
+ non_inherit =
|
||||
+ cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
|
||||
+ nontransmitted_profile,
|
||||
+ nontransmitted_profile_len);
|
||||
|
||||
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
|
||||
crc, non_inherit);
|
||||
@@ -1524,8 +1525,6 @@ struct ieee802_11_elems *ieee802_11_pars
|
||||
offsetofend(struct ieee80211_bssid_index, dtim_count))
|
||||
elems->dtim_count = elems->bssid_index->dtim_count;
|
||||
|
||||
- kfree(nontransmitted_profile);
|
||||
-
|
||||
elems->crc = crc;
|
||||
|
||||
return elems;
|
||||
@@ -0,0 +1,41 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Thu, 29 Sep 2022 21:50:44 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: ensure length byte is present before
|
||||
access
|
||||
|
||||
commit 567e14e39e8f8c6997a1378bc3be615afca86063 upstream.
|
||||
|
||||
When iterating the elements here, ensure the length byte is
|
||||
present before checking it to see if the entire element will
|
||||
fit into the buffer.
|
||||
|
||||
Longer term, we should rewrite this code using the type-safe
|
||||
element iteration macros that check all of this.
|
||||
|
||||
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
|
||||
Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -304,7 +304,8 @@ static size_t cfg80211_gen_new_ie(const
|
||||
tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
|
||||
tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
|
||||
|
||||
- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
+ while (tmp_old + 2 - ie <= ielen &&
|
||||
+ tmp_old + tmp_old[1] + 2 - ie <= ielen) {
|
||||
if (tmp_old[0] == 0) {
|
||||
tmp_old++;
|
||||
continue;
|
||||
@@ -364,7 +365,8 @@ static size_t cfg80211_gen_new_ie(const
|
||||
* copied to new ie, skip ssid, capability, bssid-index ie
|
||||
*/
|
||||
tmp_new = sub_copy;
|
||||
- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
+ while (tmp_new + 2 - sub_copy <= subie_len &&
|
||||
+ tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
|
||||
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
|
||||
tmp_new[0] == WLAN_EID_SSID)) {
|
||||
memcpy(pos, tmp_new, tmp_new[1] + 2);
|
||||
@@ -0,0 +1,87 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Fri, 30 Sep 2022 23:44:23 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream.
|
||||
|
||||
There are multiple refcounting bugs related to multi-BSSID:
|
||||
- In bss_ref_get(), if the BSS has a hidden_beacon_bss, then
|
||||
the bss pointer is overwritten before checking for the
|
||||
transmitted BSS, which is clearly wrong. Fix this by using
|
||||
the bss_from_pub() macro.
|
||||
|
||||
- In cfg80211_bss_update() we copy the transmitted_bss pointer
|
||||
from tmp into new, but then if we release new, we'll unref
|
||||
it erroneously. We already set the pointer and ref it, but
|
||||
need to NULL it since it was copied from the tmp data.
|
||||
|
||||
- In cfg80211_inform_single_bss_data(), if adding to the non-
|
||||
transmitted list fails, we unlink the BSS and yet still we
|
||||
return it, but this results in returning an entry without
|
||||
a reference. We shouldn't return it anyway if it was broken
|
||||
enough to not get added there.
|
||||
|
||||
This fixes CVE-2022-42720.
|
||||
|
||||
Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf
|
||||
lockdep_assert_held(&rdev->bss_lock);
|
||||
|
||||
bss->refcount++;
|
||||
- if (bss->pub.hidden_beacon_bss) {
|
||||
- bss = container_of(bss->pub.hidden_beacon_bss,
|
||||
- struct cfg80211_internal_bss,
|
||||
- pub);
|
||||
- bss->refcount++;
|
||||
- }
|
||||
- if (bss->pub.transmitted_bss) {
|
||||
- bss = container_of(bss->pub.transmitted_bss,
|
||||
- struct cfg80211_internal_bss,
|
||||
- pub);
|
||||
- bss->refcount++;
|
||||
- }
|
||||
+
|
||||
+ if (bss->pub.hidden_beacon_bss)
|
||||
+ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
|
||||
+
|
||||
+ if (bss->pub.transmitted_bss)
|
||||
+ bss_from_pub(bss->pub.transmitted_bss)->refcount++;
|
||||
}
|
||||
|
||||
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
|
||||
@@ -1743,6 +1737,8 @@ cfg80211_bss_update(struct cfg80211_regi
|
||||
new->refcount = 1;
|
||||
INIT_LIST_HEAD(&new->hidden_list);
|
||||
INIT_LIST_HEAD(&new->pub.nontrans_list);
|
||||
+ /* we'll set this later if it was non-NULL */
|
||||
+ new->pub.transmitted_bss = NULL;
|
||||
|
||||
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
|
||||
hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
|
||||
@@ -1983,10 +1979,15 @@ cfg80211_inform_single_bss_data(struct w
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
|
||||
&res->pub)) {
|
||||
- if (__cfg80211_unlink_bss(rdev, res))
|
||||
+ if (__cfg80211_unlink_bss(rdev, res)) {
|
||||
rdev->bss_generation++;
|
||||
+ res = NULL;
|
||||
+ }
|
||||
}
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
+
|
||||
+ if (!res)
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
@@ -0,0 +1,48 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Sat, 1 Oct 2022 00:01:44 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list
|
||||
corruption
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit bcca852027e5878aec911a347407ecc88d6fff7f upstream.
|
||||
|
||||
If a non-transmitted BSS shares enough information (both
|
||||
SSID and BSSID!) with another non-transmitted BSS of a
|
||||
different AP, then we can find and update it, and then
|
||||
try to add it to the non-transmitted BSS list. We do a
|
||||
search for it on the transmitted BSS, but if it's not
|
||||
there (but belongs to another transmitted BSS), the list
|
||||
gets corrupted.
|
||||
|
||||
Since this is an erroneous situation, simply fail the
|
||||
list insertion in this case and free the non-transmitted
|
||||
BSS.
|
||||
|
||||
This fixes CVE-2022-42721.
|
||||
|
||||
Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -425,6 +425,15 @@ cfg80211_add_nontrans_list(struct cfg802
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
+ /*
|
||||
+ * This is a bit weird - it's not on the list, but already on another
|
||||
+ * one! The only way that could happen is if there's some BSSID/SSID
|
||||
+ * shared by multiple APs in their multi-BSSID profiles, potentially
|
||||
+ * with hidden SSID mixed in ... ignore it.
|
||||
+ */
|
||||
+ if (!list_empty(&nontrans_bss->nontrans_list))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
/* add to the list */
|
||||
list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
|
||||
return 0;
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 5 Oct 2022 15:10:09 +0200
|
||||
Subject: [PATCH] wifi: mac80211_hwsim: avoid mac80211 warning on bad
|
||||
rate
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit 1833b6f46d7e2830251a063935ab464256defe22 upstream.
|
||||
|
||||
If the tool on the other side (e.g. wmediumd) gets confused
|
||||
about the rate, we hit a warning in mac80211. Silence that
|
||||
by effectively duplicating the check here and dropping the
|
||||
frame silently (in mac80211 it's dropped with the warning).
|
||||
|
||||
Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/drivers/net/wireless/mac80211_hwsim.c
|
||||
+++ b/drivers/net/wireless/mac80211_hwsim.c
|
||||
@@ -3760,6 +3760,8 @@ static int hwsim_cloned_frame_received_n
|
||||
|
||||
rx_status.band = channel->band;
|
||||
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
||||
+ if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
|
||||
+ goto out;
|
||||
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
@@ -0,0 +1,52 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 5 Oct 2022 21:24:10 +0200
|
||||
Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for
|
||||
P2P-device
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream.
|
||||
|
||||
If beacon protection is active but the beacon cannot be
|
||||
decrypted or is otherwise malformed, we call the cfg80211
|
||||
API to report this to userspace, but that uses a netdev
|
||||
pointer, which isn't present for P2P-Device. Fix this to
|
||||
call it only conditionally to ensure cfg80211 won't crash
|
||||
in the case of P2P-Device.
|
||||
|
||||
This fixes CVE-2022-42722.
|
||||
|
||||
Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -1986,10 +1986,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_
|
||||
|
||||
if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
|
||||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
|
||||
- NUM_DEFAULT_BEACON_KEYS) {
|
||||
- cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
- skb->data,
|
||||
- skb->len);
|
||||
+ NUM_DEFAULT_BEACON_KEYS) {
|
||||
+ if (rx->sdata->dev)
|
||||
+ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
+ skb->data,
|
||||
+ skb->len);
|
||||
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
|
||||
}
|
||||
|
||||
@@ -2137,7 +2138,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_
|
||||
/* either the frame has been decrypted or will be dropped */
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
- if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
|
||||
+ if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
|
||||
+ rx->sdata->dev))
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data, skb->len);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
From: Johannes Berg <johannes.berg@intel.com>
|
||||
Date: Wed, 5 Oct 2022 23:11:43 +0200
|
||||
Subject: [PATCH] wifi: cfg80211: update hidden BSSes to avoid WARN_ON
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream.
|
||||
|
||||
When updating beacon elements in a non-transmitted BSS,
|
||||
also update the hidden sub-entries to the same beacon
|
||||
elements, so that a future update through other paths
|
||||
won't trigger a WARN_ON().
|
||||
|
||||
The warning is triggered because the beacon elements in
|
||||
the hidden BSSes that are children of the BSS should
|
||||
always be the same as in the parent.
|
||||
|
||||
Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
|
||||
Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/wireless/scan.c
|
||||
+++ b/net/wireless/scan.c
|
||||
@@ -1609,6 +1609,23 @@ struct cfg80211_non_tx_bss {
|
||||
u8 bssid_index;
|
||||
};
|
||||
|
||||
+static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
|
||||
+ const struct cfg80211_bss_ies *new_ies,
|
||||
+ const struct cfg80211_bss_ies *old_ies)
|
||||
+{
|
||||
+ struct cfg80211_internal_bss *bss;
|
||||
+
|
||||
+ /* Assign beacon IEs to all sub entries */
|
||||
+ list_for_each_entry(bss, &known->hidden_list, hidden_list) {
|
||||
+ const struct cfg80211_bss_ies *ies;
|
||||
+
|
||||
+ ies = rcu_access_pointer(bss->pub.beacon_ies);
|
||||
+ WARN_ON(ies != old_ies);
|
||||
+
|
||||
+ rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
|
||||
struct cfg80211_internal_bss *known,
|
||||
@@ -1632,7 +1649,6 @@ cfg80211_update_known_bss(struct cfg8021
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
} else if (rcu_access_pointer(new->pub.beacon_ies)) {
|
||||
const struct cfg80211_bss_ies *old;
|
||||
- struct cfg80211_internal_bss *bss;
|
||||
|
||||
if (known->pub.hidden_beacon_bss &&
|
||||
!list_empty(&known->hidden_list)) {
|
||||
@@ -1660,16 +1676,7 @@ cfg80211_update_known_bss(struct cfg8021
|
||||
if (old == rcu_access_pointer(known->pub.ies))
|
||||
rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
|
||||
|
||||
- /* Assign beacon IEs to all sub entries */
|
||||
- list_for_each_entry(bss, &known->hidden_list, hidden_list) {
|
||||
- const struct cfg80211_bss_ies *ies;
|
||||
-
|
||||
- ies = rcu_access_pointer(bss->pub.beacon_ies);
|
||||
- WARN_ON(ies != old);
|
||||
-
|
||||
- rcu_assign_pointer(bss->pub.beacon_ies,
|
||||
- new->pub.beacon_ies);
|
||||
- }
|
||||
+ cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
|
||||
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
@@ -2319,6 +2326,8 @@ cfg80211_update_notlisted_nontrans(struc
|
||||
} else {
|
||||
old = rcu_access_pointer(nontrans_bss->beacon_ies);
|
||||
rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
|
||||
+ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
|
||||
+ new_ies, old);
|
||||
rcu_assign_pointer(nontrans_bss->ies, new_ies);
|
||||
if (old)
|
||||
kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
|
||||
@@ -0,0 +1,77 @@
|
||||
From 4db561ae4a90c2d0e15996634567559e292dc9e5 Mon Sep 17 00:00:00 2001
|
||||
From: Ahmed Zaki <anzaki@gmail.com>
|
||||
Date: Sat, 2 Oct 2021 08:53:29 -0600
|
||||
Subject: [PATCH] mac80211: fix a memory leak where sta_info is not freed
|
||||
|
||||
commit 8f9dcc29566626f683843ccac6113a12208315ca upstream.
|
||||
|
||||
The following is from a system that went OOM due to a memory leak:
|
||||
|
||||
wlan0: Allocated STA 74:83:c2:64:0b:87
|
||||
wlan0: Allocated STA 74:83:c2:64:0b:87
|
||||
wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta)
|
||||
wlan0: Adding new IBSS station 74:83:c2:64:0b:87
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 2
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 3
|
||||
wlan0: Inserted STA 74:83:c2:64:0b:87
|
||||
wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work)
|
||||
wlan0: Adding new IBSS station 74:83:c2:64:0b:87
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 2
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 3
|
||||
.
|
||||
.
|
||||
wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 2
|
||||
wlan0: moving STA 74:83:c2:64:0b:87 to state 1
|
||||
wlan0: Removed STA 74:83:c2:64:0b:87
|
||||
wlan0: Destroyed STA 74:83:c2:64:0b:87
|
||||
|
||||
The ieee80211_ibss_finish_sta() is called twice on the same STA from 2
|
||||
different locations. On the second attempt, the allocated STA is not
|
||||
destroyed creating a kernel memory leak.
|
||||
|
||||
This is happening because sta_info_insert_finish() does not call
|
||||
sta_info_free() the second time when the STA already exists (returns
|
||||
-EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is
|
||||
destroyed upon errors.
|
||||
|
||||
Same fix is applied to -ENOMEM.
|
||||
|
||||
Signed-off-by: Ahmed Zaki <anzaki@gmail.com>
|
||||
Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com
|
||||
[change the error path label to use the existing code]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Signed-off-by: Viacheslav Sablin <sablin@ispras.ru>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
net/mac80211/sta_info.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -646,13 +646,13 @@ static int sta_info_insert_finish(struct
|
||||
/* check if STA exists already */
|
||||
if (sta_info_get_bss(sdata, sta->sta.addr)) {
|
||||
err = -EEXIST;
|
||||
- goto out_err;
|
||||
+ goto out_cleanup;
|
||||
}
|
||||
|
||||
sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
|
||||
if (!sinfo) {
|
||||
err = -ENOMEM;
|
||||
- goto out_err;
|
||||
+ goto out_cleanup;
|
||||
}
|
||||
|
||||
local->num_sta++;
|
||||
@@ -708,8 +708,8 @@ static int sta_info_insert_finish(struct
|
||||
out_drop_sta:
|
||||
local->num_sta--;
|
||||
synchronize_net();
|
||||
+ out_cleanup:
|
||||
cleanup_single_sta(sta);
|
||||
- out_err:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
kfree(sinfo);
|
||||
rcu_read_lock();
|
||||
@@ -0,0 +1,47 @@
|
||||
From 552ba102a6898630a7d16887f29e606d6fabe508 Mon Sep 17 00:00:00 2001
|
||||
From: Siddh Raman Pant <code@siddh.me>
|
||||
Date: Sun, 14 Aug 2022 20:45:12 +0530
|
||||
Subject: [PATCH] wifi: mac80211: Don't finalize CSA in IBSS mode if state is
|
||||
disconnected
|
||||
|
||||
commit 15bc8966b6d3a5b9bfe4c9facfa02f2b69b1e5f0 upstream.
|
||||
|
||||
When we are not connected to a channel, sending channel "switch"
|
||||
announcement doesn't make any sense.
|
||||
|
||||
The BSS list is empty in that case. This causes the for loop in
|
||||
cfg80211_get_bss() to be bypassed, so the function returns NULL
|
||||
(check line 1424 of net/wireless/scan.c), causing the WARN_ON()
|
||||
in ieee80211_ibss_csa_beacon() to get triggered (check line 500
|
||||
of net/mac80211/ibss.c), which was consequently reported on the
|
||||
syzkaller dashboard.
|
||||
|
||||
Thus, check if we have an existing connection before generating
|
||||
the CSA beacon in ieee80211_ibss_finish_csa().
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Fixes: cd7760e62c2a ("mac80211: add support for CSA in IBSS mode")
|
||||
Link: https://syzkaller.appspot.com/bug?id=05603ef4ae8926761b678d2939a3b2ad28ab9ca6
|
||||
Reported-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
|
||||
Signed-off-by: Siddh Raman Pant <code@siddh.me>
|
||||
Tested-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
|
||||
Link: https://lore.kernel.org/r/20220814151512.9985-1-code@siddh.me
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
net/mac80211/ibss.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/net/mac80211/ibss.c
|
||||
+++ b/net/mac80211/ibss.c
|
||||
@@ -534,6 +534,10 @@ int ieee80211_ibss_finish_csa(struct iee
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
+ /* When not connected/joined, sending CSA doesn't make sense. */
|
||||
+ if (ifibss->state != IEEE80211_IBSS_MLME_JOINED)
|
||||
+ return -ENOLINK;
|
||||
+
|
||||
/* update cfg80211 bss information with the new channel */
|
||||
if (!is_zero_ether_addr(ifibss->bssid)) {
|
||||
cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
|
||||
@@ -0,0 +1,55 @@
|
||||
From 5d20c6f932f2758078d0454729129c894fe353e7 Mon Sep 17 00:00:00 2001
|
||||
From: Siddh Raman Pant <code@siddh.me>
|
||||
Date: Sat, 20 Aug 2022 01:33:40 +0530
|
||||
Subject: [PATCH] wifi: mac80211: Fix UAF in ieee80211_scan_rx()
|
||||
|
||||
commit 60deb9f10eec5c6a20252ed36238b55d8b614a2c upstream.
|
||||
|
||||
ieee80211_scan_rx() tries to access scan_req->flags after a
|
||||
null check, but a UAF is observed when the scan is completed
|
||||
and __ieee80211_scan_completed() executes, which then calls
|
||||
cfg80211_scan_done() leading to the freeing of scan_req.
|
||||
|
||||
Since scan_req is rcu_dereference()'d, prevent the racing in
|
||||
__ieee80211_scan_completed() by ensuring that from mac80211's
|
||||
POV it is no longer accessed from an RCU read critical section
|
||||
before we call cfg80211_scan_done().
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Link: https://syzkaller.appspot.com/bug?extid=f9acff9bf08a845f225d
|
||||
Reported-by: syzbot+f9acff9bf08a845f225d@syzkaller.appspotmail.com
|
||||
Suggested-by: Johannes Berg <johannes@sipsolutions.net>
|
||||
Signed-off-by: Siddh Raman Pant <code@siddh.me>
|
||||
Link: https://lore.kernel.org/r/20220819200340.34826-1-code@siddh.me
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
---
|
||||
net/mac80211/scan.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/net/mac80211/scan.c
|
||||
+++ b/net/mac80211/scan.c
|
||||
@@ -465,16 +465,19 @@ static void __ieee80211_scan_completed(s
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
- if (scan_req != local->int_scan_req) {
|
||||
- local->scan_info.aborted = aborted;
|
||||
- cfg80211_scan_done(scan_req, &local->scan_info);
|
||||
- }
|
||||
RCU_INIT_POINTER(local->scan_req, NULL);
|
||||
RCU_INIT_POINTER(local->scan_sdata, NULL);
|
||||
|
||||
local->scanning = 0;
|
||||
local->scan_chandef.chan = NULL;
|
||||
|
||||
+ synchronize_rcu();
|
||||
+
|
||||
+ if (scan_req != local->int_scan_req) {
|
||||
+ local->scan_info.aborted = aborted;
|
||||
+ cfg80211_scan_done(scan_req, &local->scan_info);
|
||||
+ }
|
||||
+
|
||||
/* Set power back to normal operating levels. */
|
||||
ieee80211_hw_config(local, 0);
|
||||
|
||||
@@ -9,9 +9,9 @@ PKG_RELEASE:=$(AUTORELEASE)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall4.git
|
||||
PKG_SOURCE_DATE:=2022-09-01
|
||||
PKG_SOURCE_VERSION:=f5fcdcf2c51f6f0a4b116c352000c4fe0523be77
|
||||
PKG_MIRROR_HASH:=57ef6f161abdd323019c026c959ab875fdfd3c972b8dc7767623634b1c259138
|
||||
PKG_SOURCE_DATE:=2022-10-14
|
||||
PKG_SOURCE_VERSION:=4fbf6d75a4a9e523d1848a28d8a3ea095e870195
|
||||
PKG_MIRROR_HASH:=d8ffb01baf0c8412962aaaf504ad05387f3fef5bd709f7b7840ddd4e8311b4bb
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/rpcd.git
|
||||
PKG_MIRROR_HASH:=52ca9beab4b18afec9717a5f05c5232ef6160c3ece82a020851ac3aeaa52a29a
|
||||
PKG_SOURCE_DATE:=2022-08-24
|
||||
PKG_SOURCE_VERSION:=82904bd4f92e5928d047db6396cc14ca2b07d89f
|
||||
PKG_MIRROR_HASH:=18137fa6904b1a7aec03a16a4c25fd9b9689b24ee14d431bacdda9f093339071
|
||||
PKG_SOURCE_DATE:=2022-09-21
|
||||
PKG_SOURCE_VERSION:=8c852b656bf1622dee1ae2cfa4c083f730c1c539
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
From: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Date: Sat, 8 Oct 2022 19:22:52 +0200
|
||||
Subject: [PATCH] nslookup: ensure unique transaction IDs for the DNS queries
|
||||
|
||||
The transaction IDs generated by res_mkquery() for both glibc and musl only
|
||||
depends on the state of the monotonic clock.
|
||||
For some machines (here: a TP-Link RE200 powered by a MediaTek MT7620A)
|
||||
the monotonic clock has a coarse resolution (here: 20 µs) and it can happen
|
||||
that the requests for A and AAAA share the same transaction ID.
|
||||
|
||||
In that case the mapping from received responses to the sent queries
|
||||
doesn't work and name resolution fails as follows:
|
||||
|
||||
# /bin/busybox nslookup heise.de
|
||||
Server: 127.0.0.1
|
||||
Address: 127.0.0.1:53
|
||||
|
||||
Non-authoritative answer:
|
||||
Name: heise.de
|
||||
Address: 193.99.144.80
|
||||
|
||||
*** Can't find heise.de: No answer
|
||||
|
||||
because the AAAA reply is dropped as a duplicate reply to the A query.
|
||||
|
||||
To prevent this make sure the transaction IDs are unique.
|
||||
|
||||
Forwarded: http://lists.busybox.net/pipermail/busybox/2022-October/089911.html
|
||||
---
|
||||
--- a/networking/nslookup.c
|
||||
+++ b/networking/nslookup.c
|
||||
@@ -978,6 +978,10 @@ int nslookup_main(int argc UNUSED_PARAM,
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Ensure the Transaction IDs are unique */
|
||||
+ for (rc = 1; rc < G.query_count; rc++)
|
||||
+ G.query[rc].query[1] = G.query[rc - 1].query[1] + 1;
|
||||
+
|
||||
for (rc = 0; rc < G.serv_count;) {
|
||||
int c;
|
||||
|
||||
@@ -12,9 +12,9 @@ PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=https://github.com/jow-/ucode.git
|
||||
PKG_SOURCE_DATE:=2022-08-29
|
||||
PKG_SOURCE_VERSION:=344fa9e69da43ecdc4d8f7768d85d42639352405
|
||||
PKG_MIRROR_HASH:=94e1ae6779536b2bd8957db8c2922ec32dcef75258401707505b1d34b6f16d0b
|
||||
PKG_SOURCE_DATE:=2022-10-07
|
||||
PKG_SOURCE_VERSION:=4ae70721aae5f974538928cadc71fa3269e5ad20
|
||||
PKG_MIRROR_HASH:=97339d563e988d57ed02f5fd27722c908d616c2cec8b1f0479f42bc53dfd0aa1
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
|
||||
38
package/utils/zyxel-bootconfig/Makefile
Normal file
38
package/utils/zyxel-bootconfig/Makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# Copyright (C) 2022 David Bauer <mail@david-bauer.net>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=zyxel-bootconfig
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/zyxel-bootconfig
|
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
TITLE:=Utility for handling ZyXEL Bootconfig settings
|
||||
MAINTAINER:=David Bauer <mail@david-bauer.net>
|
||||
endef
|
||||
|
||||
define Package/zyxel-bootconfig/description
|
||||
This package contains an utility that allows handling ZyXEL Bootconfig settings.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
CC="$(TARGET_CC)" \
|
||||
CFLAGS="$(TARGET_CFLAGS) -Wall"
|
||||
endef
|
||||
|
||||
define Package/zyxel-bootconfig/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin $(1)/lib/preinit
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/zyxel-bootconfig $(1)/usr/bin/
|
||||
$(CP) ./files/95_apply_bootconfig $(1)/lib/preinit/95_apply_bootconfig
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,zyxel-bootconfig))
|
||||
16
package/utils/zyxel-bootconfig/files/95_apply_bootconfig
Normal file
16
package/utils/zyxel-bootconfig/files/95_apply_bootconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
apply_bootconfig() {
|
||||
. /lib/functions.sh
|
||||
|
||||
local part
|
||||
|
||||
case $(board_name) in
|
||||
zyxel,nwa50ax|\
|
||||
zyxel,nwa55axe)
|
||||
mtd_idx=$(find_mtd_index "bootconfig")
|
||||
zyxel-bootconfig "/dev/mtd$mtd_idx" set-image-status 0 valid
|
||||
zyxel-bootconfig "/dev/mtd$mtd_idx" set-active-image 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
[ "$INITRAMFS" = "1" ] || boot_hook_add preinit_main apply_bootconfig
|
||||
7
package/utils/zyxel-bootconfig/src/Makefile
Normal file
7
package/utils/zyxel-bootconfig/src/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
all: zyxel-bootconfig
|
||||
|
||||
zyxel-bootconfig:
|
||||
$(CC) $(CFLAGS) -Wall zyxel-bootconfig.c -o zyxel-bootconfig
|
||||
|
||||
clean:
|
||||
rm -f zyxel-bootconfig
|
||||
331
package/utils/zyxel-bootconfig/src/zyxel-bootconfig.c
Normal file
331
package/utils/zyxel-bootconfig/src/zyxel-bootconfig.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Copyright (C) 2022 David Bauer <mail@david-bauer.net> */
|
||||
|
||||
/*
|
||||
* First byte: Image status
|
||||
*
|
||||
* Possible status-codes:
|
||||
* 0x0: none
|
||||
* 0x1: new
|
||||
* 0x2: valid
|
||||
* 0x3: invalid
|
||||
*
|
||||
* Example: Image 0 valid; Image 1 invalid
|
||||
* 11001000
|
||||
* || ||
|
||||
* img1||
|
||||
* img0
|
||||
*
|
||||
* Second byte: Active Image
|
||||
* Possible values:
|
||||
* 0x0: Image0 active
|
||||
* 0x1: Image1 active
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
|
||||
#define BOOTCONFIG_SIZE 0x20
|
||||
#define BOOTCONFIG_IMAGE_STATUS 0x0
|
||||
#define BOOTCONFIG_ACTIVE_IMAGE 0x1
|
||||
|
||||
#define IMAGE_0_SHIFT 2
|
||||
#define IMAGE_0_MASK 0x0c
|
||||
#define IMAGE_1_SHIFT 6
|
||||
#define IMAGE_1_MASK 0xc0
|
||||
|
||||
#define IMAGE_STATUS(img0, img1) (((img0 << IMAGE_0_SHIFT) & IMAGE_0_MASK) | ((img1 << IMAGE_1_SHIFT) & IMAGE_1_MASK))
|
||||
|
||||
#define ACTIVE_IMAGE_MASK 0x1
|
||||
#define ACTIVE_IMAGE(img) (img & ACTIVE_IMAGE_MASK)
|
||||
|
||||
enum zyxel_bootconfig_image_status {
|
||||
IMAGE_STATUS_NONE = 0x0,
|
||||
IMAGE_STATUS_NEW = 0x1,
|
||||
IMAGE_STATUS_VALID = 0x2,
|
||||
IMAGE_STATUS_INVALID = 0x3,
|
||||
__IMAGE_STATUS_EINVAL,
|
||||
};
|
||||
|
||||
struct zyxel_bootconfig {
|
||||
enum zyxel_bootconfig_image_status image0_status;
|
||||
enum zyxel_bootconfig_image_status image1_status;
|
||||
unsigned int active_image;
|
||||
};
|
||||
|
||||
struct zyxel_bootconfig_mtd {
|
||||
struct mtd_info_user mtd_info;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct zyxel_image_status {
|
||||
enum zyxel_bootconfig_image_status code;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct zyxel_image_status image_status_codes[] = {
|
||||
{ .code = IMAGE_STATUS_NONE, .name = "none" },
|
||||
{ .code = IMAGE_STATUS_NEW, .name = "new" },
|
||||
{ .code = IMAGE_STATUS_VALID, .name = "valid" },
|
||||
{ .code = IMAGE_STATUS_INVALID, .name = "invalid" },
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
static enum zyxel_bootconfig_image_status zyxel_bootconfig_image_status_parse(const char *status) {
|
||||
struct zyxel_image_status* s;
|
||||
|
||||
for (s = image_status_codes; s->name; s++) {
|
||||
if (!strcmp(status, s->name)) {
|
||||
return s->code;
|
||||
}
|
||||
}
|
||||
|
||||
return __IMAGE_STATUS_EINVAL;
|
||||
}
|
||||
|
||||
const char *zyxel_bootconfig_image_status_name(const enum zyxel_bootconfig_image_status bootconfig) {
|
||||
struct zyxel_image_status* s;
|
||||
|
||||
for (s = image_status_codes; s->name; s++) {
|
||||
if (bootconfig == s->code) {
|
||||
return s->name;
|
||||
}
|
||||
}
|
||||
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
static void zyxel_bootconfig_mtd_close(struct zyxel_bootconfig_mtd *mtd) {
|
||||
close(mtd->fd);
|
||||
}
|
||||
|
||||
|
||||
static int zyxel_bootconfig_mtd_open(struct zyxel_bootconfig_mtd *mtd, const char *mtd_name) {
|
||||
int ret = 0;
|
||||
|
||||
mtd->fd = open(mtd_name, O_RDWR | O_SYNC);
|
||||
if (mtd->fd < 0) {
|
||||
fprintf(stderr, "Could not open mtd device: %s\n", mtd_name);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(mtd->fd, MEMGETINFO, &mtd->mtd_info)) {
|
||||
fprintf(stderr, "Could not get MTD device info from %s\n", mtd_name);
|
||||
ret = -1;
|
||||
zyxel_bootconfig_mtd_close(mtd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int zyxel_bootconfig_read(struct zyxel_bootconfig *config, struct zyxel_bootconfig_mtd *mtd) {
|
||||
char *args = NULL;
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate memory for reading boot-config partition */
|
||||
args = calloc(1, mtd->mtd_info.erasesize);
|
||||
if (!args) {
|
||||
fprintf(stderr, "Could not allocate memory!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read bootconfig partition */
|
||||
pread(mtd->fd, args, mtd->mtd_info.erasesize, 0);
|
||||
|
||||
/* Parse config */
|
||||
memset(config, 0, sizeof(*config));
|
||||
|
||||
config->image0_status = (args[BOOTCONFIG_IMAGE_STATUS] & IMAGE_0_MASK) >> IMAGE_0_SHIFT;
|
||||
config->image1_status = (args[BOOTCONFIG_IMAGE_STATUS] & IMAGE_1_MASK) >> IMAGE_1_SHIFT;
|
||||
config->active_image = (args[BOOTCONFIG_ACTIVE_IMAGE] & ACTIVE_IMAGE_MASK);
|
||||
|
||||
out:
|
||||
if (args)
|
||||
free(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int zyxel_bootconfig_write(struct zyxel_bootconfig *config, struct zyxel_bootconfig_mtd *mtd)
|
||||
{
|
||||
struct erase_info_user erase_info;
|
||||
char img_status, img_active;
|
||||
char *args = NULL;
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate memory for reading boot-config partition */
|
||||
args = calloc(1, mtd->mtd_info.erasesize);
|
||||
if (!args) {
|
||||
fprintf(stderr, "Could not allocate memory!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read bootconfig partition */
|
||||
pread(mtd->fd, args, mtd->mtd_info.erasesize, 0);
|
||||
|
||||
img_status = IMAGE_STATUS(config->image0_status, config->image1_status);
|
||||
img_active = ACTIVE_IMAGE(config->active_image);
|
||||
|
||||
/* Check if bootconfig has to be written */
|
||||
if (args[BOOTCONFIG_IMAGE_STATUS] == img_status && args[BOOTCONFIG_ACTIVE_IMAGE] == img_active) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Erase first block (containing the magic) */
|
||||
erase_info.start = 0;
|
||||
erase_info.length = mtd->mtd_info.erasesize;
|
||||
ret = ioctl(mtd->fd, MEMERASE, &erase_info);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to erase block: %i\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
/* Write bootconfig */
|
||||
args[BOOTCONFIG_IMAGE_STATUS] = img_status;
|
||||
args[BOOTCONFIG_ACTIVE_IMAGE] = img_active;
|
||||
|
||||
if (pwrite(mtd->fd, args, mtd->mtd_info.erasesize, 0) != mtd->mtd_info.erasesize) {
|
||||
fprintf(stderr, "Error writing bootconfig!\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (args)
|
||||
free(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void zyxel_bootconfig_print_usage(char *programm)
|
||||
{
|
||||
struct zyxel_image_status* s = image_status_codes;
|
||||
|
||||
printf("Usage: %s <mtd-device> <command> [args]\n", programm);
|
||||
printf("Available commands:\n");
|
||||
printf(" get-status\n");
|
||||
printf(" set-image-status [0/1] [");
|
||||
|
||||
while (s->name) {
|
||||
printf("%s", s->name);
|
||||
s++;
|
||||
|
||||
if (s->name)
|
||||
printf(",");
|
||||
}
|
||||
|
||||
printf("]\n");
|
||||
printf(" set-active-image [0/1]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
enum zyxel_bootconfig_image_status image_status;
|
||||
struct zyxel_bootconfig_mtd mtd;
|
||||
struct zyxel_bootconfig config;
|
||||
const char *mtd_name, *command;
|
||||
bool writeback = false;
|
||||
int image_idx;
|
||||
|
||||
if (argc < 3) {
|
||||
zyxel_bootconfig_print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
mtd_name = argv[1];
|
||||
command = argv[2];
|
||||
|
||||
if (zyxel_bootconfig_mtd_open(&mtd, mtd_name)) {
|
||||
fprintf(stderr, "Error opening %s!\n", mtd_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (zyxel_bootconfig_read(&config, &mtd)) {
|
||||
fprintf(stderr, "Error reading bootconfig!\n");
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(command, "set-image-status")) {
|
||||
if (argc < 5) {
|
||||
zyxel_bootconfig_print_usage(argv[0]);
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
image_idx = atoi(argv[3]);
|
||||
if (image_idx > 1 || image_idx < 0) {
|
||||
fprintf(stderr, "Invalid image-slot set!\n");
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
image_status = zyxel_bootconfig_image_status_parse(argv[4]);
|
||||
if (image_status == __IMAGE_STATUS_EINVAL) {
|
||||
fprintf(stderr, "Invalid image-status!\n");
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (image_idx == 0) {
|
||||
config.image0_status = image_status;
|
||||
} else {
|
||||
config.image1_status = image_status;
|
||||
}
|
||||
|
||||
writeback = true;
|
||||
} else if (!strcmp(command, "set-active-image")) {
|
||||
if (argc < 4) {
|
||||
zyxel_bootconfig_print_usage(argv[0]);
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
image_idx = atoi(argv[3]);
|
||||
if (image_idx > 1 || image_idx < 0) {
|
||||
fprintf(stderr, "Invalid image-slot set!\n");
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
config.active_image = image_idx;
|
||||
|
||||
writeback = true;
|
||||
} else if (!strcmp(command, "get-status")) {
|
||||
printf("Active Image: %d\n", config.active_image);
|
||||
printf("Image 0 Status: %s\n", zyxel_bootconfig_image_status_name(config.image0_status));
|
||||
printf("Image 1 Status: %s\n", zyxel_bootconfig_image_status_name(config.image1_status));
|
||||
|
||||
writeback = false;
|
||||
}
|
||||
|
||||
if (writeback) {
|
||||
if (zyxel_bootconfig_write(&config, &mtd)) {
|
||||
fprintf(stderr, "Error writing bootconfig!\n");
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
zyxel_bootconfig_mtd_close(&mtd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
scripts/mkits-zyxel-fit.sh
Executable file
38
scripts/mkits-zyxel-fit.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Licensed under the terms of the GNU GPL License version 2 or later.
|
||||
# Author: David Bauer <mail@david-bauer.net>, based on mkits-zyxel-factory.sh.
|
||||
|
||||
usage() {
|
||||
echo "Usage: `basename $0` output file compat-models"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# We need at least 3 arguments
|
||||
[ "$#" -lt 3 ] && usage
|
||||
|
||||
# Target output file
|
||||
OUTPUT="$1"; shift
|
||||
FILE="$1"; shift
|
||||
MODELS="$1"; shift
|
||||
|
||||
# Create a default, fully populated DTS file
|
||||
echo "\
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
description = \"Zyxel FIT (Flattened Image Tree)\";
|
||||
compat-models = [${MODELS}];
|
||||
#address-cells = <1>;
|
||||
|
||||
images {
|
||||
firmware {
|
||||
data = /incbin/(\"${FILE}\");
|
||||
type = \"firmware\";
|
||||
compression = \"none\";
|
||||
hash@1 {
|
||||
algo = \"sha1\";
|
||||
};
|
||||
};
|
||||
};
|
||||
};" > ${OUTPUT}
|
||||
@@ -256,9 +256,11 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
* last external data refernced.
|
||||
*/
|
||||
if (fit_size > 0x1000) {
|
||||
enum mtdsplit_part_type type;
|
||||
|
||||
/* Search for the rootfs partition after the FIT image */
|
||||
ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size,
|
||||
&rootfs_offset, NULL);
|
||||
&rootfs_offset, &type);
|
||||
if (ret) {
|
||||
pr_info("no rootfs found after FIT image in \"%s\"\n",
|
||||
mtd->name);
|
||||
@@ -275,7 +277,10 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
parts[0].offset = fit_offset;
|
||||
parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize;
|
||||
|
||||
parts[1].name = ROOTFS_PART_NAME;
|
||||
if (type == MTDSPLIT_PART_TYPE_UBI)
|
||||
parts[1].name = UBI_PART_NAME;
|
||||
else
|
||||
parts[1].name = ROOTFS_PART_NAME;
|
||||
parts[1].offset = rootfs_offset;
|
||||
parts[1].size = rootfs_size;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
131
target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h
Normal file
131
target/linux/generic/files/drivers/mtd/nand/mtk_bmt.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifndef __MTK_BMT_PRIV_H
|
||||
#define __MTK_BMT_PRIV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/mtk_bmt.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#define MAIN_SIGNATURE_OFFSET 0
|
||||
#define OOB_SIGNATURE_OFFSET 1
|
||||
|
||||
#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
struct mtk_bmt_ops {
|
||||
char *sig;
|
||||
unsigned int sig_len;
|
||||
int (*init)(struct device_node *np);
|
||||
bool (*remap_block)(u16 block, u16 mapped_block, int copy_len);
|
||||
void (*unmap_block)(u16 block);
|
||||
int (*get_mapping_block)(int block);
|
||||
int (*debug)(void *data, u64 val);
|
||||
};
|
||||
|
||||
struct bbbt;
|
||||
struct nmbm_instance;
|
||||
|
||||
struct bmt_desc {
|
||||
struct mtd_info *mtd;
|
||||
unsigned char *bbt_buf;
|
||||
unsigned char *data_buf;
|
||||
|
||||
int (*_read_oob) (struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*_write_oob) (struct mtd_info *mtd, loff_t to,
|
||||
struct mtd_oob_ops *ops);
|
||||
int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
|
||||
int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
|
||||
|
||||
const struct mtk_bmt_ops *ops;
|
||||
|
||||
union {
|
||||
struct bbbt *bbt;
|
||||
struct nmbm_instance *ni;
|
||||
};
|
||||
|
||||
struct dentry *debugfs_dir;
|
||||
|
||||
u32 table_size;
|
||||
u32 pg_size;
|
||||
u32 blk_size;
|
||||
u16 pg_shift;
|
||||
u16 blk_shift;
|
||||
/* bbt logical address */
|
||||
u16 pool_lba;
|
||||
/* bbt physical address */
|
||||
u16 pool_pba;
|
||||
/* Maximum count of bad blocks that the vendor guaranteed */
|
||||
u16 bb_max;
|
||||
/* Total blocks of the Nand Chip */
|
||||
u16 total_blks;
|
||||
/* The block(n) BMT is located at (bmt_tbl[n]) */
|
||||
u16 bmt_blk_idx;
|
||||
/* How many pages needs to store 'struct bbbt' */
|
||||
u32 bmt_pgs;
|
||||
|
||||
const __be32 *remap_range;
|
||||
int remap_range_len;
|
||||
|
||||
/* to compensate for driver level remapping */
|
||||
u8 oob_offset;
|
||||
};
|
||||
|
||||
extern struct bmt_desc bmtd;
|
||||
extern const struct mtk_bmt_ops mtk_bmt_v2_ops;
|
||||
extern const struct mtk_bmt_ops mtk_bmt_bbt_ops;
|
||||
extern const struct mtk_bmt_ops mtk_bmt_nmbm_ops;
|
||||
|
||||
static inline u32 blk_pg(u16 block)
|
||||
{
|
||||
return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift));
|
||||
}
|
||||
|
||||
static inline int
|
||||
bbt_nand_read(u32 page, unsigned char *dat, int dat_len,
|
||||
unsigned char *fdm, int fdm_len)
|
||||
{
|
||||
struct mtd_oob_ops ops = {
|
||||
.mode = MTD_OPS_PLACE_OOB,
|
||||
.ooboffs = bmtd.oob_offset,
|
||||
.oobbuf = fdm,
|
||||
.ooblen = fdm_len,
|
||||
.datbuf = dat,
|
||||
.len = dat_len,
|
||||
};
|
||||
|
||||
return bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops);
|
||||
}
|
||||
|
||||
static inline int bbt_nand_erase(u16 block)
|
||||
{
|
||||
struct mtd_info *mtd = bmtd.mtd;
|
||||
struct erase_info instr = {
|
||||
.addr = (loff_t)block << bmtd.blk_shift,
|
||||
.len = bmtd.blk_size,
|
||||
};
|
||||
|
||||
return bmtd._erase(mtd, &instr);
|
||||
}
|
||||
|
||||
static inline int write_bmt(u16 block, unsigned char *dat)
|
||||
{
|
||||
struct mtd_oob_ops ops = {
|
||||
.mode = MTD_OPS_PLACE_OOB,
|
||||
.ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset,
|
||||
.oobbuf = bmtd.ops->sig,
|
||||
.ooblen = bmtd.ops->sig_len,
|
||||
.datbuf = dat,
|
||||
.len = bmtd.bmt_pgs << bmtd.pg_shift,
|
||||
};
|
||||
loff_t addr = (loff_t)block << bmtd.blk_shift;
|
||||
|
||||
return bmtd._write_oob(bmtd.mtd, addr, &ops);
|
||||
}
|
||||
|
||||
int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset);
|
||||
bool mapping_block_in_range(int block, int *start, int *end);
|
||||
|
||||
#endif
|
||||
203
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_bbt.c
Normal file
203
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_bbt.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2017 MediaTek Inc.
|
||||
* Author: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
|
||||
* Copyright (c) 2020-2022 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "mtk_bmt.h"
|
||||
|
||||
static bool
|
||||
bbt_block_is_bad(u16 block)
|
||||
{
|
||||
u8 cur = bmtd.bbt_buf[block / 4];
|
||||
|
||||
return cur & (3 << ((block % 4) * 2));
|
||||
}
|
||||
|
||||
static void
|
||||
bbt_set_block_state(u16 block, bool bad)
|
||||
{
|
||||
u8 mask = (3 << ((block % 4) * 2));
|
||||
|
||||
if (bad)
|
||||
bmtd.bbt_buf[block / 4] |= mask;
|
||||
else
|
||||
bmtd.bbt_buf[block / 4] &= ~mask;
|
||||
|
||||
bbt_nand_erase(bmtd.bmt_blk_idx);
|
||||
write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf);
|
||||
}
|
||||
|
||||
static int
|
||||
get_mapping_block_index_bbt(int block)
|
||||
{
|
||||
int start, end, ofs;
|
||||
int bad_blocks = 0;
|
||||
int i;
|
||||
|
||||
if (!mapping_block_in_range(block, &start, &end))
|
||||
return block;
|
||||
|
||||
start >>= bmtd.blk_shift;
|
||||
end >>= bmtd.blk_shift;
|
||||
/* skip bad blocks within the mapping range */
|
||||
ofs = block - start;
|
||||
for (i = start; i < end; i++) {
|
||||
if (bbt_block_is_bad(i))
|
||||
bad_blocks++;
|
||||
else if (ofs)
|
||||
ofs--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < end)
|
||||
return i;
|
||||
|
||||
/* when overflowing, remap remaining blocks to bad ones */
|
||||
for (i = end - 1; bad_blocks > 0; i--) {
|
||||
if (!bbt_block_is_bad(i))
|
||||
continue;
|
||||
|
||||
bad_blocks--;
|
||||
if (bad_blocks <= ofs)
|
||||
return i;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static bool remap_block_bbt(u16 block, u16 mapped_blk, int copy_len)
|
||||
{
|
||||
int start, end;
|
||||
u16 new_blk;
|
||||
|
||||
if (!mapping_block_in_range(block, &start, &end))
|
||||
return false;
|
||||
|
||||
bbt_set_block_state(mapped_blk, true);
|
||||
|
||||
new_blk = get_mapping_block_index_bbt(block);
|
||||
bbt_nand_erase(new_blk);
|
||||
if (copy_len > 0)
|
||||
bbt_nand_copy(new_blk, mapped_blk, copy_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_block_bbt(u16 block)
|
||||
{
|
||||
bbt_set_block_state(block, false);
|
||||
}
|
||||
|
||||
static int
|
||||
mtk_bmt_read_bbt(void)
|
||||
{
|
||||
u8 oob_buf[8];
|
||||
int i;
|
||||
|
||||
for (i = bmtd.total_blks - 1; i >= bmtd.total_blks - 5; i--) {
|
||||
u32 page = i << (bmtd.blk_shift - bmtd.pg_shift);
|
||||
|
||||
if (bbt_nand_read(page, bmtd.bbt_buf, bmtd.pg_size,
|
||||
oob_buf, sizeof(oob_buf))) {
|
||||
pr_info("read_bbt: could not read block %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oob_buf[0] != 0xff) {
|
||||
pr_info("read_bbt: bad block at %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(&oob_buf[1], "mtknand", 7) != 0) {
|
||||
pr_info("read_bbt: signature mismatch in block %d\n", i);
|
||||
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, oob_buf, 8, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
pr_info("read_bbt: found bbt at block %d\n", i);
|
||||
bmtd.bmt_blk_idx = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mtk_bmt_init_bbt(struct device_node *np)
|
||||
{
|
||||
int buf_size = round_up(bmtd.total_blks >> 2, bmtd.blk_size);
|
||||
int ret;
|
||||
|
||||
bmtd.bbt_buf = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!bmtd.bbt_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(bmtd.bbt_buf, 0xff, buf_size);
|
||||
bmtd.mtd->size -= 4 * bmtd.mtd->erasesize;
|
||||
|
||||
ret = mtk_bmt_read_bbt();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bmtd.bmt_pgs = buf_size / bmtd.pg_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_bmt_debug_bbt(void *data, u64 val)
|
||||
{
|
||||
char buf[5];
|
||||
int i, k;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
for (i = 0; i < bmtd.total_blks; i += 4) {
|
||||
u8 cur = bmtd.bbt_buf[i / 4];
|
||||
|
||||
for (k = 0; k < 4; k++, cur >>= 2)
|
||||
buf[k] = (cur & 3) ? 'B' : '.';
|
||||
|
||||
buf[4] = 0;
|
||||
printk("[%06x] %s\n", i * bmtd.blk_size, buf);
|
||||
}
|
||||
break;
|
||||
case 100:
|
||||
#if 0
|
||||
for (i = bmtd.bmt_blk_idx; i < bmtd.total_blks - 1; i++)
|
||||
bbt_nand_erase(bmtd.bmt_blk_idx);
|
||||
#endif
|
||||
|
||||
bmtd.bmt_blk_idx = bmtd.total_blks - 1;
|
||||
bbt_nand_erase(bmtd.bmt_blk_idx);
|
||||
write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct mtk_bmt_ops mtk_bmt_bbt_ops = {
|
||||
.sig = "mtknand",
|
||||
.sig_len = 7,
|
||||
.init = mtk_bmt_init_bbt,
|
||||
.remap_block = remap_block_bbt,
|
||||
.unmap_block = unmap_block_bbt,
|
||||
.get_mapping_block = get_mapping_block_index_bbt,
|
||||
.debug = mtk_bmt_debug_bbt,
|
||||
};
|
||||
2348
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_nmbm.c
Normal file
2348
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_nmbm.c
Normal file
File diff suppressed because it is too large
Load Diff
513
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c
Normal file
513
target/linux/generic/files/drivers/mtd/nand/mtk_bmt_v2.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (c) 2017 MediaTek Inc.
|
||||
* Author: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
|
||||
* Copyright (c) 2020-2022 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "mtk_bmt.h"
|
||||
|
||||
struct bbbt {
|
||||
char signature[3];
|
||||
/* This version is used to distinguish the legacy and new algorithm */
|
||||
#define BBMT_VERSION 2
|
||||
unsigned char version;
|
||||
/* Below 2 tables will be written in SLC */
|
||||
u16 bb_tbl[];
|
||||
};
|
||||
|
||||
struct bbmt {
|
||||
u16 block;
|
||||
#define NO_MAPPED 0
|
||||
#define NORMAL_MAPPED 1
|
||||
#define BMT_MAPPED 2
|
||||
u16 mapped;
|
||||
};
|
||||
|
||||
/* Maximum 8k blocks */
|
||||
#define BBPOOL_RATIO 2
|
||||
#define BB_TABLE_MAX bmtd.table_size
|
||||
#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100)
|
||||
#define BMT_TBL_DEF_VAL 0x0
|
||||
|
||||
static inline struct bbmt *bmt_tbl(struct bbbt *bbbt)
|
||||
{
|
||||
return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size];
|
||||
}
|
||||
|
||||
static u16 find_valid_block(u16 block)
|
||||
{
|
||||
u8 fdm[4];
|
||||
int ret;
|
||||
int loop = 0;
|
||||
|
||||
retry:
|
||||
if (block >= bmtd.total_blks)
|
||||
return 0;
|
||||
|
||||
ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size,
|
||||
fdm, sizeof(fdm));
|
||||
/* Read the 1st byte of FDM to judge whether it's a bad
|
||||
* or not
|
||||
*/
|
||||
if (ret || fdm[0] != 0xff) {
|
||||
pr_info("nand: found bad block 0x%x\n", block);
|
||||
if (loop >= bmtd.bb_max) {
|
||||
pr_info("nand: FATAL ERR: too many bad blocks!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
loop++;
|
||||
block++;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/* Find out all bad blocks, and fill in the mapping table */
|
||||
static int scan_bad_blocks(struct bbbt *bbt)
|
||||
{
|
||||
int i;
|
||||
u16 block = 0;
|
||||
|
||||
/* First time download, the block0 MUST NOT be a bad block,
|
||||
* this is guaranteed by vendor
|
||||
*/
|
||||
bbt->bb_tbl[0] = 0;
|
||||
|
||||
/*
|
||||
* Construct the mapping table of Normal data area(non-PMT/BMTPOOL)
|
||||
* G - Good block; B - Bad block
|
||||
* ---------------------------
|
||||
* physical |G|G|B|G|B|B|G|G|G|G|B|G|B|
|
||||
* ---------------------------
|
||||
* What bb_tbl[i] looks like:
|
||||
* physical block(i):
|
||||
* 0 1 2 3 4 5 6 7 8 9 a b c
|
||||
* mapped block(bb_tbl[i]):
|
||||
* 0 1 3 6 7 8 9 b ......
|
||||
* ATTENTION:
|
||||
* If new bad block ocurred(n), search bmt_tbl to find
|
||||
* a available block(x), and fill in the bb_tbl[n] = x;
|
||||
*/
|
||||
for (i = 1; i < bmtd.pool_lba; i++) {
|
||||
bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1);
|
||||
BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]);
|
||||
if (bbt->bb_tbl[i] == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Physical Block start Address of BMT pool */
|
||||
bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1;
|
||||
if (bmtd.pool_pba >= bmtd.total_blks - 2) {
|
||||
pr_info("nand: FATAL ERR: Too many bad blocks!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
BBT_LOG("pool_pba=0x%x", bmtd.pool_pba);
|
||||
i = 0;
|
||||
block = bmtd.pool_pba;
|
||||
/*
|
||||
* The bmt table is used for runtime bad block mapping
|
||||
* G - Good block; B - Bad block
|
||||
* ---------------------------
|
||||
* physical |G|G|B|G|B|B|G|G|G|G|B|G|B|
|
||||
* ---------------------------
|
||||
* block: 0 1 2 3 4 5 6 7 8 9 a b c
|
||||
* What bmt_tbl[i] looks like in initial state:
|
||||
* i:
|
||||
* 0 1 2 3 4 5 6 7
|
||||
* bmt_tbl[i].block:
|
||||
* 0 1 3 6 7 8 9 b
|
||||
* bmt_tbl[i].mapped:
|
||||
* N N N N N N N B
|
||||
* N - Not mapped(Available)
|
||||
* M - Mapped
|
||||
* B - BMT
|
||||
* ATTENTION:
|
||||
* BMT always in the last valid block in pool
|
||||
*/
|
||||
while ((block = find_valid_block(block)) != 0) {
|
||||
bmt_tbl(bbt)[i].block = block;
|
||||
bmt_tbl(bbt)[i].mapped = NO_MAPPED;
|
||||
BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block);
|
||||
block++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* i - How many available blocks in pool, which is the length of bmt_tbl[]
|
||||
* bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block
|
||||
*/
|
||||
bmtd.bmt_blk_idx = i - 1;
|
||||
bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED;
|
||||
|
||||
if (i < 1) {
|
||||
pr_info("nand: FATAL ERR: no space to store BMT!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_info("[BBT] %d available blocks in BMT pool\n", i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm)
|
||||
{
|
||||
struct bbbt *bbt = (struct bbbt *)buf;
|
||||
u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET;
|
||||
|
||||
|
||||
if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 &&
|
||||
memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) {
|
||||
if (bbt->version == BBMT_VERSION)
|
||||
return true;
|
||||
}
|
||||
BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x",
|
||||
sig[0], sig[1], sig[2],
|
||||
fdm[1], fdm[2], fdm[3]);
|
||||
return false;
|
||||
}
|
||||
|
||||
static u16 get_bmt_index(struct bbmt *bmt)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (bmt[i].block != BMT_TBL_DEF_VAL) {
|
||||
if (bmt[i].mapped == BMT_MAPPED)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len)
|
||||
{
|
||||
u32 len = bmtd.bmt_pgs << bmtd.pg_shift;
|
||||
|
||||
return bbt_nand_read(blk_pg(block), dat, len, fdm, fdm_len);
|
||||
}
|
||||
|
||||
static struct bbbt *scan_bmt(u16 block)
|
||||
{
|
||||
u8 fdm[4];
|
||||
|
||||
if (block < bmtd.pool_lba)
|
||||
return NULL;
|
||||
|
||||
if (read_bmt(block, bmtd.bbt_buf, fdm, sizeof(fdm)))
|
||||
return scan_bmt(block - 1);
|
||||
|
||||
if (is_valid_bmt(bmtd.bbt_buf, fdm)) {
|
||||
bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)bmtd.bbt_buf));
|
||||
if (bmtd.bmt_blk_idx == 0) {
|
||||
pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n");
|
||||
return NULL;
|
||||
}
|
||||
pr_info("[BBT] BMT.v2 is found at 0x%x\n", block);
|
||||
return (struct bbbt *)bmtd.bbt_buf;
|
||||
} else
|
||||
return scan_bmt(block - 1);
|
||||
}
|
||||
|
||||
/* Write the Burner Bad Block Table to Nand Flash
|
||||
* n - write BMT to bmt_tbl[n]
|
||||
*/
|
||||
static u16 upload_bmt(struct bbbt *bbt, int n)
|
||||
{
|
||||
u16 block;
|
||||
|
||||
retry:
|
||||
if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) {
|
||||
pr_info("nand: FATAL ERR: no space to store BMT!\n");
|
||||
return (u16)-1;
|
||||
}
|
||||
|
||||
block = bmt_tbl(bbt)[n].block;
|
||||
BBT_LOG("n = 0x%x, block = 0x%x", n, block);
|
||||
if (bbt_nand_erase(block)) {
|
||||
bmt_tbl(bbt)[n].block = 0;
|
||||
/* erase failed, try the previous block: bmt_tbl[n - 1].block */
|
||||
n--;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* The signature offset is fixed set to 0,
|
||||
* oob signature offset is fixed set to 1
|
||||
*/
|
||||
memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3);
|
||||
bbt->version = BBMT_VERSION;
|
||||
|
||||
if (write_bmt(block, (unsigned char *)bbt)) {
|
||||
bmt_tbl(bbt)[n].block = 0;
|
||||
|
||||
/* write failed, try the previous block in bmt_tbl[n - 1] */
|
||||
n--;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Return the current index(n) of BMT pool (bmt_tbl[n]) */
|
||||
return n;
|
||||
}
|
||||
|
||||
static u16 find_valid_block_in_pool(struct bbbt *bbt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bmtd.bmt_blk_idx == 0)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < bmtd.bmt_blk_idx; i++) {
|
||||
if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) {
|
||||
bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED;
|
||||
return bmt_tbl(bbt)[i].block;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
pr_info("nand: FATAL ERR: BMT pool is run out!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We met a bad block, mark it as bad and map it to a valid block in pool,
|
||||
* if it's a write failure, we need to write the data to mapped block
|
||||
*/
|
||||
static bool remap_block_v2(u16 block, u16 mapped_block, int copy_len)
|
||||
{
|
||||
u16 new_block;
|
||||
struct bbbt *bbt;
|
||||
|
||||
bbt = bmtd.bbt;
|
||||
new_block = find_valid_block_in_pool(bbt);
|
||||
if (new_block == 0)
|
||||
return false;
|
||||
|
||||
/* Map new bad block to available block in pool */
|
||||
bbt->bb_tbl[block] = new_block;
|
||||
|
||||
/* Erase new block */
|
||||
bbt_nand_erase(new_block);
|
||||
if (copy_len > 0)
|
||||
bbt_nand_copy(new_block, mapped_block, copy_len);
|
||||
|
||||
bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int get_mapping_block_index_v2(int block)
|
||||
{
|
||||
int start, end;
|
||||
|
||||
if (block >= bmtd.pool_lba)
|
||||
return block;
|
||||
|
||||
if (!mapping_block_in_range(block, &start, &end))
|
||||
return block;
|
||||
|
||||
return bmtd.bbt->bb_tbl[block];
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_block_v2(u16 block)
|
||||
{
|
||||
bmtd.bbt->bb_tbl[block] = block;
|
||||
bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx);
|
||||
}
|
||||
|
||||
static unsigned long *
|
||||
mtk_bmt_get_mapping_mask(void)
|
||||
{
|
||||
struct bbmt *bbmt = bmt_tbl(bmtd.bbt);
|
||||
int main_blocks = bmtd.mtd->size >> bmtd.blk_shift;
|
||||
unsigned long *used;
|
||||
int i, k;
|
||||
|
||||
used = kcalloc(sizeof(unsigned long), BIT_WORD(bmtd.bmt_blk_idx) + 1, GFP_KERNEL);
|
||||
if (!used)
|
||||
return NULL;
|
||||
|
||||
for (i = 1; i < main_blocks; i++) {
|
||||
if (bmtd.bbt->bb_tbl[i] == i)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < bmtd.bmt_blk_idx; k++) {
|
||||
if (bmtd.bbt->bb_tbl[i] != bbmt[k].block)
|
||||
continue;
|
||||
|
||||
set_bit(k, used);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
static int mtk_bmt_debug_v2(void *data, u64 val)
|
||||
{
|
||||
struct bbmt *bbmt = bmt_tbl(bmtd.bbt);
|
||||
struct mtd_info *mtd = bmtd.mtd;
|
||||
unsigned long *used;
|
||||
int main_blocks = mtd->size >> bmtd.blk_shift;
|
||||
int n_remap = 0;
|
||||
int i;
|
||||
|
||||
used = mtk_bmt_get_mapping_mask();
|
||||
if (!used)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
for (i = 1; i < main_blocks; i++) {
|
||||
if (bmtd.bbt->bb_tbl[i] == i)
|
||||
continue;
|
||||
|
||||
printk("remap [%x->%x]\n", i, bmtd.bbt->bb_tbl[i]);
|
||||
n_remap++;
|
||||
}
|
||||
for (i = 0; i <= bmtd.bmt_blk_idx; i++) {
|
||||
char c;
|
||||
|
||||
switch (bbmt[i].mapped) {
|
||||
case NO_MAPPED:
|
||||
continue;
|
||||
case NORMAL_MAPPED:
|
||||
c = 'm';
|
||||
if (test_bit(i, used))
|
||||
c = 'M';
|
||||
break;
|
||||
case BMT_MAPPED:
|
||||
c = 'B';
|
||||
break;
|
||||
default:
|
||||
c = 'X';
|
||||
break;
|
||||
}
|
||||
printk("[%x:%c] = 0x%x\n", i, c, bbmt[i].block);
|
||||
}
|
||||
break;
|
||||
case 100:
|
||||
for (i = 0; i <= bmtd.bmt_blk_idx; i++) {
|
||||
if (bbmt[i].mapped != NORMAL_MAPPED)
|
||||
continue;
|
||||
|
||||
if (test_bit(i, used))
|
||||
continue;
|
||||
|
||||
n_remap++;
|
||||
bbmt[i].mapped = NO_MAPPED;
|
||||
printk("free block [%d:%x]\n", i, bbmt[i].block);
|
||||
}
|
||||
if (n_remap)
|
||||
bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(used);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_bmt_init_v2(struct device_node *np)
|
||||
{
|
||||
u32 bmt_pool_size, bmt_table_size;
|
||||
u32 bufsz, block;
|
||||
u16 pmt_block;
|
||||
|
||||
if (of_property_read_u32(np, "mediatek,bmt-pool-size",
|
||||
&bmt_pool_size) != 0)
|
||||
bmt_pool_size = 80;
|
||||
|
||||
if (of_property_read_u8(np, "mediatek,bmt-oob-offset",
|
||||
&bmtd.oob_offset) != 0)
|
||||
bmtd.oob_offset = 0;
|
||||
|
||||
if (of_property_read_u32(np, "mediatek,bmt-table-size",
|
||||
&bmt_table_size) != 0)
|
||||
bmt_table_size = 0x2000U;
|
||||
|
||||
bmtd.table_size = bmt_table_size;
|
||||
|
||||
pmt_block = bmtd.total_blks - bmt_pool_size - 2;
|
||||
|
||||
bmtd.mtd->size = pmt_block << bmtd.blk_shift;
|
||||
|
||||
/*
|
||||
* ---------------------------------------
|
||||
* | PMT(2blks) | BMT POOL(totalblks * 2%) |
|
||||
* ---------------------------------------
|
||||
* ^ ^
|
||||
* | |
|
||||
* pmt_block pmt_block + 2blocks(pool_lba)
|
||||
*
|
||||
* ATTETION!!!!!!
|
||||
* The blocks ahead of the boundary block are stored in bb_tbl
|
||||
* and blocks behind are stored in bmt_tbl
|
||||
*/
|
||||
|
||||
bmtd.pool_lba = (u16)(pmt_block + 2);
|
||||
bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100;
|
||||
|
||||
bufsz = round_up(sizeof(struct bbbt) +
|
||||
bmt_table_size * sizeof(struct bbmt), bmtd.pg_size);
|
||||
bmtd.bmt_pgs = bufsz >> bmtd.pg_shift;
|
||||
|
||||
bmtd.bbt_buf = kzalloc(bufsz, GFP_KERNEL);
|
||||
if (!bmtd.bbt_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(bmtd.bbt_buf, 0xff, bufsz);
|
||||
|
||||
/* Scanning start from the first page of the last block
|
||||
* of whole flash
|
||||
*/
|
||||
bmtd.bbt = scan_bmt(bmtd.total_blks - 1);
|
||||
if (!bmtd.bbt) {
|
||||
/* BMT not found */
|
||||
if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) {
|
||||
pr_info("nand: FATAL: Too many blocks, can not support!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bmtd.bbt = (struct bbbt *)bmtd.bbt_buf;
|
||||
memset(bmt_tbl(bmtd.bbt), BMT_TBL_DEF_VAL,
|
||||
bmtd.table_size * sizeof(struct bbmt));
|
||||
|
||||
if (scan_bad_blocks(bmtd.bbt))
|
||||
return -1;
|
||||
|
||||
/* BMT always in the last valid block in pool */
|
||||
bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx);
|
||||
block = bmt_tbl(bmtd.bbt)[bmtd.bmt_blk_idx].block;
|
||||
pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block);
|
||||
|
||||
if (bmtd.bmt_blk_idx == 0)
|
||||
pr_info("nand: Warning: no available block in BMT pool!\n");
|
||||
else if (bmtd.bmt_blk_idx == (u16)-1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const struct mtk_bmt_ops mtk_bmt_v2_ops = {
|
||||
.sig = "bmt",
|
||||
.sig_len = 3,
|
||||
.init = mtk_bmt_init_v2,
|
||||
.remap_block = remap_block_v2,
|
||||
.unmap_block = unmap_block_v2,
|
||||
.get_mapping_block = get_mapping_block_index_v2,
|
||||
.debug = mtk_bmt_debug_v2,
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
nandcore-objs := core.o bbt.o
|
||||
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
|
||||
+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o
|
||||
+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
|
||||
|
||||
obj-y += onenand/
|
||||
obj-y += raw/
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
DEVICE_VARS += TPLINK_HWID TPLINK_HWREV TPLINK_FLASHLAYOUT TPLINK_HEADER_VERSION
|
||||
|
||||
define Build/spi-loader-okli-compile
|
||||
rm -rf $@.spi-loader-okli
|
||||
$(CP) spi-loader $@.spi-loader-okli
|
||||
$(MAKE) -C $@.spi-loader-okli \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" CONFIG="$(DEVICE_NAME)"
|
||||
cp "$@.spi-loader-okli/out/uImage" "$@"
|
||||
rm -rf $@.spi-loader-okli
|
||||
endef
|
||||
|
||||
define Build/spi-loader-okli
|
||||
cat $(KDIR)/loader-$(1) "$@" > "$@.new"
|
||||
mv "$@.new" "$@"
|
||||
endef
|
||||
|
||||
define Device/tplink_tl-wdr4900-v1
|
||||
DEVICE_VENDOR := TP-Link
|
||||
DEVICE_MODEL := TL-WDR4900
|
||||
@@ -8,19 +22,19 @@ define Device/tplink_tl-wdr4900-v1
|
||||
TPLINK_HWID := 0x49000001
|
||||
TPLINK_HWREV := 1
|
||||
TPLINK_FLASHLAYOUT := 16Mppc
|
||||
KERNEL_SIZE := 2684k
|
||||
KERNEL_NAME := simpleImage.tl-wdr4900-v1
|
||||
KERNEL_INITRAMFS :=
|
||||
KERNEL := kernel-bin | uImage none
|
||||
KERNEL := kernel-bin | uImage none -M 0x4f4b4c49 | spi-loader-okli $(1)
|
||||
KERNEL_ENTRY := 0x1000000
|
||||
KERNEL_LOADADDR := 0x1000000
|
||||
SUPPORTED_DEVICES += tl-wdr4900-v1
|
||||
COMPILE := loader-$(1)
|
||||
COMPILE/loader-$(1) := spi-loader-okli-compile
|
||||
ARTIFACTS := fdt.bin
|
||||
ARTIFACT/fdt.bin := append-dtb
|
||||
IMAGES := factory.bin sysupgrade.bin
|
||||
IMAGE/sysupgrade.bin := tplink-v1-image sysupgrade | append-metadata
|
||||
IMAGE/factory.bin := tplink-v1-image factory
|
||||
DEFAULT := n
|
||||
endef
|
||||
TARGET_DEVICES += tplink_tl-wdr4900-v1
|
||||
|
||||
|
||||
1
target/linux/mpc85xx/image/spi-loader/.gitignore
vendored
Normal file
1
target/linux/mpc85xx/image/spi-loader/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/out
|
||||
60
target/linux/mpc85xx/image/spi-loader/Makefile
Normal file
60
target/linux/mpc85xx/image/spi-loader/Makefile
Normal file
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (C) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
|
||||
CONFIG ?= $(error No configuration set)
|
||||
|
||||
include config/$(CONFIG).mk
|
||||
|
||||
MKIMAGE := mkimage
|
||||
KARCH := powerpc
|
||||
CC := $(CROSS_COMPILE)gcc
|
||||
LD := $(CROSS_COMPILE)ld
|
||||
OBJCOPY := $(CROSS_COMPILE)objcopy
|
||||
|
||||
PROGRAM_NAME := MPC85xx SPI loader
|
||||
|
||||
BIN_FLAGS := -O binary --pad-to=$(PAD_TO)
|
||||
|
||||
CFLAGS += -std=gnu17 -Os -Wall -Wstrict-prototypes \
|
||||
-fomit-frame-pointer -ffreestanding \
|
||||
-ffunction-sections -fno-pic \
|
||||
-Iinclude -include ../config/$(CONFIG).h \
|
||||
-DCONFIG_PROGRAM_NAME='"$(PROGRAM_NAME)"' \
|
||||
-DCONFIG_IMAGE_OFFSET=$(IMAGE_OFFSET)
|
||||
ASFLAGS := $(CFLAGS)
|
||||
|
||||
LDS := loader.lds
|
||||
LDFLAGS := -static --gc-sections -T $(LDS) -Ttext $(TEXT_START)
|
||||
|
||||
OBJECTS := head.o loader.o string.o stdio.o drivers/serial/ns16550.o \
|
||||
drivers/spi/fsl_espi.o drivers/spi/spi-nor.o
|
||||
|
||||
OUTDIR := out
|
||||
|
||||
all: $(OUTDIR)/uImage
|
||||
|
||||
-include $(OBJECTS:%.o=$(OUTDIR)/%.d)
|
||||
|
||||
$(OUTDIR)/%.o: %.c Makefile config/$(CONFIG).mk
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c -o $@ -MD -MP $<
|
||||
|
||||
$(OUTDIR)/%.o: %.S Makefile config/$(CONFIG).mk
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(ASFLAGS) -c -o $@ -MD -MP $<
|
||||
|
||||
$(OUTDIR)/loader.elf: $(OBJECTS:%=$(OUTDIR)/%) $(LDS)
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJECTS:%=$(OUTDIR)/%)
|
||||
|
||||
$(OUTDIR)/loader.bin: $(OUTDIR)/loader.elf
|
||||
$(OBJCOPY) $(BIN_FLAGS) $< $@
|
||||
|
||||
$(OUTDIR)/uImage: $(OUTDIR)/loader.bin
|
||||
$(MKIMAGE) -A $(KARCH) -O linux -T kernel -C none \
|
||||
-a $(TEXT_START) -e $(TEXT_START) -n '$(PROGRAM_NAME)' -d $< $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OUTDIR)
|
||||
|
||||
.PHONY: all clean
|
||||
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#define CONFIG_FREQ_SYSTEMBUS 399999996
|
||||
#define CONFIG_SPI_MAX_HZ 25000000
|
||||
|
||||
#define CONFIG_SERIAL_NS16550_REG_BASE 0xffe04500
|
||||
#define CONFIG_SERIAL_NS16550_REG_SHIFT 0
|
||||
|
||||
#define CONFIG_SPI_FSL_ESPI_REG_BASE 0xffe07000
|
||||
@@ -0,0 +1,13 @@
|
||||
TEXT_START := 0x800000
|
||||
|
||||
# It seems that the TP-Link TL-WDR4900 U-Boot does not flush the cache before
|
||||
# jumping into the uImage. Padding the image to 32k seems make the boot work
|
||||
# reliably.
|
||||
#
|
||||
# We leave 0x40 for the uImage header, which allows us to append the kernel
|
||||
# uImage after the loader and read with an added offset 0x8000 from the
|
||||
# SPI flash.
|
||||
PAD_TO := 0x807fc0
|
||||
|
||||
# Kernel begins at 0x60200 in flash, loader adds 0x8000
|
||||
IMAGE_OFFSET := 0x68200
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 16550 serial console support.
|
||||
*
|
||||
* Original copied from <file:arch/ppc/boot/common/ns16550.c>
|
||||
* (which had no copyright)
|
||||
* Modifications: 2006 (c) MontaVista Software, Inc.
|
||||
*
|
||||
* Modified by: Mark A. Greer <mgreer@mvista.com>
|
||||
*
|
||||
* Adapted by:
|
||||
*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#include <io.h>
|
||||
#include <serial.h>
|
||||
|
||||
#define UART_DLL 0 /* Out: Divisor Latch Low */
|
||||
#define UART_DLM 1 /* Out: Divisor Latch High */
|
||||
#define UART_FCR 2 /* Out: FIFO Control Register */
|
||||
#define UART_LCR 3 /* Out: Line Control Register */
|
||||
#define UART_MCR 4 /* Out: Modem Control Register */
|
||||
#define UART_LSR 5 /* In: Line Status Register */
|
||||
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
||||
#define UART_LSR_DR 0x01 /* Receiver data ready */
|
||||
#define UART_MSR 6 /* In: Modem Status Register */
|
||||
#define UART_SCR 7 /* I/O: Scratch Register */
|
||||
|
||||
static uint8_t *const reg_base = (uint8_t *)CONFIG_SERIAL_NS16550_REG_BASE;
|
||||
static const int reg_shift = CONFIG_SERIAL_NS16550_REG_SHIFT;
|
||||
|
||||
void serial_console_putchar(char c)
|
||||
{
|
||||
while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0);
|
||||
out_8(reg_base, c);
|
||||
}
|
||||
|
||||
int serial_console_getc(void)
|
||||
{
|
||||
while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0);
|
||||
return in_8(reg_base);
|
||||
}
|
||||
|
||||
int serial_console_tstc(void)
|
||||
{
|
||||
return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0);
|
||||
}
|
||||
|
||||
void serial_console_init(void)
|
||||
{
|
||||
out_8(reg_base + (UART_FCR << reg_shift), 0x06);
|
||||
}
|
||||
232
target/linux/mpc85xx/image/spi-loader/drivers/spi/fsl_espi.c
Normal file
232
target/linux/mpc85xx/image/spi-loader/drivers/spi/fsl_espi.c
Normal file
@@ -0,0 +1,232 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* eSPI controller driver.
|
||||
*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*
|
||||
* Based on U-Boot code:
|
||||
*
|
||||
* Copyright 2010-2011 Freescale Semiconductor, Inc.
|
||||
* Copyright 2020 NXP
|
||||
* Author: Mingkai Hu (Mingkai.hu@freescale.com)
|
||||
* Chuanhua Han (chuanhua.han@nxp.com)
|
||||
*/
|
||||
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <spi.h>
|
||||
|
||||
/* eSPI Registers */
|
||||
typedef struct ccsr_espi {
|
||||
uint32_t mode; /* eSPI mode */
|
||||
uint32_t event; /* eSPI event */
|
||||
uint32_t mask; /* eSPI mask */
|
||||
uint32_t com; /* eSPI command */
|
||||
uint32_t tx; /* eSPI transmit FIFO access */
|
||||
uint32_t rx; /* eSPI receive FIFO access */
|
||||
uint8_t res1[8]; /* reserved */
|
||||
uint32_t csmode[4]; /* 0x2c: sSPI CS0/1/2/3 mode */
|
||||
uint8_t res2[4048]; /* fill up to 0x1000 */
|
||||
} ccsr_espi_t;
|
||||
|
||||
struct fsl_spi {
|
||||
ccsr_espi_t *espi;
|
||||
uint32_t cs;
|
||||
uint32_t div16;
|
||||
uint32_t pm;
|
||||
uint32_t mode;
|
||||
};
|
||||
|
||||
#define ESPI_MAX_CS_NUM 4
|
||||
#define ESPI_FIFO_WIDTH_BIT 32
|
||||
|
||||
#define ESPI_EV_RNE BIT(9)
|
||||
#define ESPI_EV_TNF BIT(8)
|
||||
#define ESPI_EV_DON BIT(14)
|
||||
#define ESPI_EV_TXE BIT(15)
|
||||
#define ESPI_EV_RFCNT_SHIFT 24
|
||||
#define ESPI_EV_RFCNT_MASK (0x3f << ESPI_EV_RFCNT_SHIFT)
|
||||
|
||||
#define ESPI_MODE_EN BIT(31) /* Enable interface */
|
||||
#define ESPI_MODE_TXTHR(x) ((x) << 8) /* Tx FIFO threshold */
|
||||
#define ESPI_MODE_RXTHR(x) ((x) << 0) /* Rx FIFO threshold */
|
||||
|
||||
#define ESPI_COM_CS(x) ((x) << 30)
|
||||
#define ESPI_COM_TRANLEN(x) ((x) << 0)
|
||||
|
||||
#define ESPI_CSMODE_CI_INACTIVEHIGH BIT(31)
|
||||
#define ESPI_CSMODE_CP_BEGIN_EDGCLK BIT(30)
|
||||
#define ESPI_CSMODE_REV_MSB_FIRST BIT(29)
|
||||
#define ESPI_CSMODE_DIV16 BIT(28)
|
||||
#define ESPI_CSMODE_PM(x) ((x) << 24)
|
||||
#define ESPI_CSMODE_POL_ASSERTED_LOW BIT(20)
|
||||
#define ESPI_CSMODE_LEN(x) ((x) << 16)
|
||||
#define ESPI_CSMODE_CSBEF(x) ((x) << 12)
|
||||
#define ESPI_CSMODE_CSAFT(x) ((x) << 8)
|
||||
#define ESPI_CSMODE_CSCG(x) ((x) << 3)
|
||||
|
||||
#define ESPI_CSMODE_INIT_VAL (ESPI_CSMODE_POL_ASSERTED_LOW | \
|
||||
ESPI_CSMODE_CSBEF(0) | ESPI_CSMODE_CSAFT(0) | \
|
||||
ESPI_CSMODE_CSCG(1))
|
||||
|
||||
#define ESPI_MAX_DATA_TRANSFER_LEN 0x10000
|
||||
|
||||
static int espi_xfer(struct fsl_spi *fsl, const struct spi_transfer *msg, int n)
|
||||
{
|
||||
ccsr_espi_t *espi = fsl->espi;
|
||||
size_t len = spi_message_len(msg, n);
|
||||
|
||||
if (len > ESPI_MAX_DATA_TRANSFER_LEN)
|
||||
return -1;
|
||||
|
||||
/* clear the RXCNT and TXCNT */
|
||||
out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN));
|
||||
out_be32(&espi->mode, in_be32(&espi->mode) | ESPI_MODE_EN);
|
||||
out_be32(&espi->com, ESPI_COM_CS(fsl->cs) | ESPI_COM_TRANLEN(len - 1));
|
||||
|
||||
int last_msg = n - 1;
|
||||
int tx_msg = -1, rx_msg = -1;
|
||||
size_t tx_len = 0, rx_len = 0, tx_pos = 0, rx_pos = 0;
|
||||
|
||||
while (true) {
|
||||
if (tx_pos == tx_len && tx_msg < last_msg) {
|
||||
tx_msg++;
|
||||
tx_pos = 0;
|
||||
tx_len = msg[tx_msg].len;
|
||||
}
|
||||
if (rx_pos == rx_len && rx_msg < last_msg) {
|
||||
rx_msg++;
|
||||
rx_pos = 0;
|
||||
rx_len = msg[rx_msg].len;
|
||||
}
|
||||
if (rx_pos == rx_len)
|
||||
break;
|
||||
|
||||
const uint8_t *tx_buf = msg[tx_msg].tx_buf;
|
||||
uint8_t *rx_buf = msg[rx_msg].rx_buf;
|
||||
|
||||
uint32_t event = in_be32(&espi->event);
|
||||
|
||||
/* TX */
|
||||
if ((event & ESPI_EV_TNF) && tx_len > 0) {
|
||||
uint8_t v = 0;
|
||||
if (tx_buf)
|
||||
v = tx_buf[tx_pos];
|
||||
out_8((uint8_t *)&espi->tx, v);
|
||||
tx_pos++;
|
||||
}
|
||||
|
||||
/* RX */
|
||||
if (event & ESPI_EV_RNE) {
|
||||
uint8_t v = in_8((uint8_t *)&espi->rx);
|
||||
if (rx_buf)
|
||||
rx_buf[rx_pos] = v;
|
||||
rx_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void espi_claim_bus(struct fsl_spi *fsl)
|
||||
{
|
||||
ccsr_espi_t *espi = fsl->espi;
|
||||
uint32_t csmode;
|
||||
int i;
|
||||
|
||||
/* Enable eSPI interface */
|
||||
out_be32(&espi->mode, ESPI_MODE_RXTHR(3)
|
||||
| ESPI_MODE_TXTHR(4) | ESPI_MODE_EN);
|
||||
|
||||
out_be32(&espi->mask, 0x00000000); /* Mask all eSPI interrupts */
|
||||
|
||||
/* Init CS mode interface */
|
||||
for (i = 0; i < ESPI_MAX_CS_NUM; i++)
|
||||
out_be32(&espi->csmode[i], ESPI_CSMODE_INIT_VAL);
|
||||
|
||||
csmode = ESPI_CSMODE_INIT_VAL;
|
||||
|
||||
/* Set eSPI BRG clock source */
|
||||
csmode |= ESPI_CSMODE_PM(fsl->pm) | fsl->div16;
|
||||
|
||||
/* Set eSPI mode */
|
||||
if (fsl->mode & SPI_CPHA)
|
||||
csmode |= ESPI_CSMODE_CP_BEGIN_EDGCLK;
|
||||
if (fsl->mode & SPI_CPOL)
|
||||
csmode |= ESPI_CSMODE_CI_INACTIVEHIGH;
|
||||
|
||||
/* Character bit order: msb first */
|
||||
csmode |= ESPI_CSMODE_REV_MSB_FIRST;
|
||||
|
||||
/* Character length in bits, between 0x3~0xf, i.e. 4bits~16bits */
|
||||
csmode |= ESPI_CSMODE_LEN(7);
|
||||
|
||||
out_be32(&espi->csmode[fsl->cs], csmode);
|
||||
}
|
||||
|
||||
static void espi_release_bus(struct fsl_spi *fsl)
|
||||
{
|
||||
/* Disable the SPI hardware */
|
||||
out_be32(&fsl->espi->mode,
|
||||
in_be32(&fsl->espi->mode) & (~ESPI_MODE_EN));
|
||||
}
|
||||
|
||||
static void espi_setup_spi(struct fsl_spi *fsl, unsigned int max_hz)
|
||||
{
|
||||
unsigned long spibrg;
|
||||
uint32_t pm;
|
||||
|
||||
spibrg = CONFIG_FREQ_SYSTEMBUS / 2;
|
||||
fsl->div16 = 0;
|
||||
if ((spibrg / max_hz) > 32) {
|
||||
fsl->div16 = ESPI_CSMODE_DIV16;
|
||||
pm = spibrg / (max_hz * 16 * 2);
|
||||
if (pm > 16) {
|
||||
/* max_hz too low */
|
||||
pm = 16;
|
||||
}
|
||||
} else {
|
||||
pm = spibrg / (max_hz * 2);
|
||||
}
|
||||
if (pm)
|
||||
pm--;
|
||||
fsl->pm = pm;
|
||||
}
|
||||
|
||||
static struct fsl_spi spi;
|
||||
|
||||
int spi_init(unsigned int cs, unsigned int max_hz, unsigned int mode)
|
||||
{
|
||||
if (cs >= ESPI_MAX_CS_NUM)
|
||||
return -1;
|
||||
|
||||
spi.espi = (ccsr_espi_t *)CONFIG_SPI_FSL_ESPI_REG_BASE;
|
||||
spi.cs = cs;
|
||||
spi.mode = mode;
|
||||
|
||||
espi_setup_spi(&spi, max_hz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_claim_bus(void)
|
||||
{
|
||||
espi_claim_bus(&spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_release_bus(void)
|
||||
{
|
||||
espi_release_bus(&spi);
|
||||
}
|
||||
|
||||
int spi_xfer(const struct spi_transfer *msg, int n)
|
||||
{
|
||||
return espi_xfer(&spi, msg, n);
|
||||
}
|
||||
|
||||
size_t spi_max_xfer(void)
|
||||
{
|
||||
return ESPI_MAX_DATA_TRANSFER_LEN;
|
||||
}
|
||||
72
target/linux/mpc85xx/image/spi-loader/drivers/spi/spi-nor.c
Normal file
72
target/linux/mpc85xx/image/spi-loader/drivers/spi/spi-nor.c
Normal file
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#include <spi.h>
|
||||
#include <spi-nor.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CMD_READ 0x03
|
||||
#define CMD_READ_ID 0x9F
|
||||
|
||||
int spi_nor_read_id(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const uint8_t tx_buf[1] = {CMD_READ_ID};
|
||||
uint8_t rx_buf[3] = {};
|
||||
struct spi_transfer t[2] = {{
|
||||
.tx_buf = tx_buf,
|
||||
.rx_buf = NULL,
|
||||
.len = sizeof(tx_buf),
|
||||
}, {
|
||||
.tx_buf = NULL,
|
||||
.rx_buf = rx_buf,
|
||||
.len = sizeof(rx_buf),
|
||||
}};
|
||||
|
||||
ret = spi_xfer(t, ARRAY_SIZE(t));
|
||||
if (ret) {
|
||||
puts("SPI transfer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
puts("Flash JECED ID: ");
|
||||
put_array(rx_buf, sizeof(rx_buf));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_nor_read_data(void *dest, size_t pos, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
uint8_t cmd[4] = {CMD_READ, pos >> 16, pos >> 8, pos};
|
||||
size_t block_len = min(len, spi_max_xfer() - sizeof(cmd));
|
||||
|
||||
struct spi_transfer t[2] = {{
|
||||
.tx_buf = cmd,
|
||||
.rx_buf = NULL,
|
||||
.len = sizeof(cmd),
|
||||
}, {
|
||||
.tx_buf = NULL,
|
||||
.rx_buf = dest,
|
||||
.len = block_len,
|
||||
}};
|
||||
|
||||
ret = spi_xfer(t, ARRAY_SIZE(t));
|
||||
if (ret) {
|
||||
puts("SPI transfer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pos += block_len;
|
||||
dest += block_len;
|
||||
len -= block_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
36
target/linux/mpc85xx/image/spi-loader/head.S
Normal file
36
target/linux/mpc85xx/image/spi-loader/head.S
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*
|
||||
* Based on Linux arch/powerpc/boot/crt0.S, which is:
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*/
|
||||
|
||||
#include <ppc_asm.h>
|
||||
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
/* Do a cache flush for our text, in case the loader didn't */
|
||||
lis r3,_text_start@ha
|
||||
addi r3,r3,_text_start@l
|
||||
li r4,_text_len
|
||||
bl flush_cache
|
||||
|
||||
/* Clear the BSS */
|
||||
lis r3,_bss_start@ha
|
||||
addi r3,r3,_bss_start@l
|
||||
li r4,0
|
||||
li r5,_bss_len
|
||||
bl memset
|
||||
|
||||
/* Set up stack */
|
||||
lis r1,_stack_top@ha
|
||||
addi r1,r1,_stack_top@l
|
||||
/* Establish a stack frame */
|
||||
li r0,0
|
||||
stwu r0,-16(r1)
|
||||
|
||||
/* Call start */
|
||||
b start
|
||||
61
target/linux/mpc85xx/image/spi-loader/include/image.h
Normal file
61
target/linux/mpc85xx/image/spi-loader/include/image.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Derived from U-Boot include/image.h:
|
||||
*
|
||||
* (C) Copyright 2008 Semihalf
|
||||
*
|
||||
* (C) Copyright 2000-2005
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
********************************************************************
|
||||
* NOTE: This header file defines an interface to U-Boot. Including
|
||||
* this (unmodified) header file in another file is considered normal
|
||||
* use of U-Boot, and does *not* fall under the heading of "derived
|
||||
* work".
|
||||
********************************************************************
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/*
|
||||
* Compression Types
|
||||
*
|
||||
* The following are exposed to uImage header.
|
||||
* New IDs *MUST* be appended at the end of the list and *NEVER*
|
||||
* inserted for backward compatibility.
|
||||
*/
|
||||
enum {
|
||||
IH_COMP_NONE = 0, /* No Compression Used */
|
||||
IH_COMP_GZIP, /* gzip Compression Used */
|
||||
IH_COMP_BZIP2, /* bzip2 Compression Used */
|
||||
IH_COMP_LZMA, /* lzma Compression Used */
|
||||
IH_COMP_LZO, /* lzo Compression Used */
|
||||
IH_COMP_LZ4, /* lz4 Compression Used */
|
||||
IH_COMP_ZSTD, /* zstd Compression Used */
|
||||
|
||||
IH_COMP_COUNT,
|
||||
};
|
||||
|
||||
#define IH_MAGIC 0x27051956 /* Image Magic Number */
|
||||
#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' Magic Number */
|
||||
#define IH_NMLEN 32 /* Image Name Length */
|
||||
|
||||
/*
|
||||
* Legacy format image header,
|
||||
* all data in network byte order (aka natural aka bigendian).
|
||||
*/
|
||||
typedef struct image_header {
|
||||
uint32_t ih_magic; /* Image Header Magic Number */
|
||||
uint32_t ih_hcrc; /* Image Header CRC Checksum */
|
||||
uint32_t ih_time; /* Image Creation Timestamp */
|
||||
uint32_t ih_size; /* Image Data Size */
|
||||
uint32_t ih_load; /* Data Load Address */
|
||||
uint32_t ih_ep; /* Entry Point Address */
|
||||
uint32_t ih_dcrc; /* Image Data CRC Checksum */
|
||||
uint8_t ih_os; /* Operating System */
|
||||
uint8_t ih_arch; /* CPU architecture */
|
||||
uint8_t ih_type; /* Image Type */
|
||||
uint8_t ih_comp; /* Compression Type */
|
||||
uint8_t ih_name[IH_NMLEN]; /* Image Name */
|
||||
} image_header_t;
|
||||
8
target/linux/mpc85xx/image/spi-loader/include/init.h
Normal file
8
target/linux/mpc85xx/image/spi-loader/include/init.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void start(void);
|
||||
101
target/linux/mpc85xx/image/spi-loader/include/io.h
Normal file
101
target/linux/mpc85xx/image/spi-loader/include/io.h
Normal file
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Low-level I/O routines.
|
||||
*
|
||||
* Copied from <file:arch/powerpc/include/asm/io.h> (which has no copyright)
|
||||
*/
|
||||
static inline uint8_t in_8(const volatile uint8_t *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
|
||||
: "=r" (ret) : "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void out_8(volatile uint8_t *addr, uint8_t val)
|
||||
{
|
||||
__asm__ __volatile__("stb%U0%X0 %1,%0; sync"
|
||||
: "=m" (*addr) : "r" (val));
|
||||
}
|
||||
|
||||
static inline uint16_t in_le16(const volatile uint16_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
__asm__ __volatile__("lhbrx %0,0,%1; twi 0,%0,0; isync"
|
||||
: "=r" (ret) : "r" (addr), "m" (*addr));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint16_t in_be16(const volatile uint16_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
__asm__ __volatile__("lhz%U1%X1 %0,%1; twi 0,%0,0; isync"
|
||||
: "=r" (ret) : "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void out_le16(volatile uint16_t *addr, uint16_t val)
|
||||
{
|
||||
__asm__ __volatile__("sthbrx %1,0,%2; sync" : "=m" (*addr)
|
||||
: "r" (val), "r" (addr));
|
||||
}
|
||||
|
||||
static inline void out_be16(volatile uint16_t *addr, uint16_t val)
|
||||
{
|
||||
__asm__ __volatile__("sth%U0%X0 %1,%0; sync"
|
||||
: "=m" (*addr) : "r" (val));
|
||||
}
|
||||
|
||||
static inline uint32_t in_le32(const volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
__asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync"
|
||||
: "=r" (ret) : "r" (addr), "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t in_be32(const volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
__asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
|
||||
: "=r" (ret) : "m" (*addr));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void out_le32(volatile uint32_t *addr, uint32_t val)
|
||||
{
|
||||
__asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr)
|
||||
: "r" (val), "r" (addr));
|
||||
}
|
||||
|
||||
static inline void out_be32(volatile uint32_t *addr, uint32_t val)
|
||||
{
|
||||
__asm__ __volatile__("stw%U0%X0 %1,%0; sync"
|
||||
: "=m" (*addr) : "r" (val));
|
||||
}
|
||||
|
||||
static inline void sync(void)
|
||||
{
|
||||
asm volatile("sync" : : : "memory");
|
||||
}
|
||||
|
||||
static inline void eieio(void)
|
||||
{
|
||||
asm volatile("eieio" : : : "memory");
|
||||
}
|
||||
|
||||
static inline void barrier(void)
|
||||
{
|
||||
asm volatile("" : : : "memory");
|
||||
}
|
||||
55
target/linux/mpc85xx/image/spi-loader/include/ppc_asm.h
Normal file
55
target/linux/mpc85xx/image/spi-loader/include/ppc_asm.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
/*
|
||||
*
|
||||
* Definitions used by various bits of low-level assembly code on PowerPC.
|
||||
*
|
||||
* Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
|
||||
*/
|
||||
|
||||
/* Condition Register Bit Fields */
|
||||
|
||||
#define cr0 0
|
||||
#define cr1 1
|
||||
#define cr2 2
|
||||
#define cr3 3
|
||||
#define cr4 4
|
||||
#define cr5 5
|
||||
#define cr6 6
|
||||
#define cr7 7
|
||||
|
||||
/* General Purpose Registers (GPRs) */
|
||||
|
||||
#define r0 0
|
||||
#define r1 1
|
||||
#define r2 2
|
||||
#define r3 3
|
||||
#define r4 4
|
||||
#define r5 5
|
||||
#define r6 6
|
||||
#define r7 7
|
||||
#define r8 8
|
||||
#define r9 9
|
||||
#define r10 10
|
||||
#define r11 11
|
||||
#define r12 12
|
||||
#define r13 13
|
||||
#define r14 14
|
||||
#define r15 15
|
||||
#define r16 16
|
||||
#define r17 17
|
||||
#define r18 18
|
||||
#define r19 19
|
||||
#define r20 20
|
||||
#define r21 21
|
||||
#define r22 22
|
||||
#define r23 23
|
||||
#define r24 24
|
||||
#define r25 25
|
||||
#define r26 26
|
||||
#define r27 27
|
||||
#define r28 28
|
||||
#define r29 29
|
||||
#define r30 30
|
||||
#define r31 31
|
||||
9
target/linux/mpc85xx/image/spi-loader/include/serial.h
Normal file
9
target/linux/mpc85xx/image/spi-loader/include/serial.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
#pragma once
|
||||
|
||||
int serial_console_getchar(void);
|
||||
int serial_console_tstc(void);
|
||||
void serial_console_putchar(char c);
|
||||
void serial_console_init(void);
|
||||
|
||||
11
target/linux/mpc85xx/image/spi-loader/include/spi-nor.h
Normal file
11
target/linux/mpc85xx/image/spi-loader/include/spi-nor.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
int spi_nor_read_id(void);
|
||||
int spi_nor_read_data(void *dest, size_t pos, size_t len);
|
||||
43
target/linux/mpc85xx/image/spi-loader/include/spi.h
Normal file
43
target/linux/mpc85xx/image/spi-loader/include/spi.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Common SPI Interface: Controller-specific definitions
|
||||
*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*
|
||||
* Based on U-boot's spi.h:
|
||||
*
|
||||
* (C) Copyright 2001
|
||||
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/* SPI mode flags */
|
||||
#define SPI_CPHA BIT(0) /* clock phase (1 = SPI_CLOCK_PHASE_SECOND) */
|
||||
#define SPI_CPOL BIT(1) /* clock polarity (1 = SPI_POLARITY_HIGH) */
|
||||
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
|
||||
#define SPI_MODE_1 (0|SPI_CPHA)
|
||||
#define SPI_MODE_2 (SPI_CPOL|0)
|
||||
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
|
||||
|
||||
struct spi_transfer {
|
||||
const void *tx_buf;
|
||||
void *rx_buf;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline size_t spi_message_len(const struct spi_transfer *msg, int n) {
|
||||
size_t total = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
total += msg[i].len;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int spi_init(unsigned int cs, unsigned int max_hz, unsigned int mode);
|
||||
int spi_claim_bus(void);
|
||||
void spi_release_bus(void);
|
||||
int spi_xfer(const struct spi_transfer *msg, int n);
|
||||
size_t spi_max_xfer(void);
|
||||
43
target/linux/mpc85xx/image/spi-loader/include/stdio.h
Normal file
43
target/linux/mpc85xx/image/spi-loader/include/stdio.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <serial.h>
|
||||
#include <types.h>
|
||||
|
||||
static inline int getchar(void)
|
||||
{
|
||||
return serial_console_getchar();
|
||||
}
|
||||
|
||||
static inline int tstc(void)
|
||||
{
|
||||
return serial_console_tstc();
|
||||
}
|
||||
|
||||
static inline int putchar(char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
serial_console_putchar('\r');
|
||||
serial_console_putchar(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int puts(const char *s);
|
||||
|
||||
/* Utility functions */
|
||||
void put_u4(uint8_t v);
|
||||
void put_u8(uint8_t v);
|
||||
void put_u16(uint16_t v);
|
||||
void put_u32(uint32_t v);
|
||||
void put_ptr(const void *p);
|
||||
void put_array(const void *p, size_t l);
|
||||
|
||||
#define put_with_label(label, put, value) do { \
|
||||
puts(label); \
|
||||
put(value); \
|
||||
puts("\n"); \
|
||||
} while (0)
|
||||
23
target/linux/mpc85xx/image/spi-loader/include/string.h
Normal file
23
target/linux/mpc85xx/image/spi-loader/include/string.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern char *strcpy(char *dest, const char *src);
|
||||
extern char *strncpy(char *dest, const char *src, size_t n);
|
||||
extern char *strcat(char *dest, const char *src);
|
||||
extern char *strchr(const char *s, int c);
|
||||
extern char *strrchr(const char *s, int c);
|
||||
extern int strcmp(const char *s1, const char *s2);
|
||||
extern int strncmp(const char *s1, const char *s2, size_t n);
|
||||
extern size_t strlen(const char *s);
|
||||
extern size_t strnlen(const char *s, size_t count);
|
||||
|
||||
extern void *memset(void *s, int c, size_t n);
|
||||
extern void *memmove(void *dest, const void *src, unsigned long n);
|
||||
extern void *memcpy(void *dest, const void *src, unsigned long n);
|
||||
extern void *memchr(const void *s, int c, size_t n);
|
||||
extern int memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
||||
extern void flush_cache(void *, unsigned long);
|
||||
72
target/linux/mpc85xx/image/spi-loader/include/types.h
Normal file
72
target/linux/mpc85xx/image/spi-loader/include/types.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Code originates from Linux kernel arch/powerpc/boot
|
||||
* (types.h, swab.h, of.h)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#define BIT(nr) (1UL << (nr))
|
||||
|
||||
#define min(x,y) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
typeof(y) _y = (y); \
|
||||
(void) (&_x == &_y); \
|
||||
_x < _y ? _x : _y; })
|
||||
|
||||
#define max(x,y) ({ \
|
||||
typeof(x) _x = (x); \
|
||||
typeof(y) _y = (y); \
|
||||
(void) (&_x == &_y); \
|
||||
_x > _y ? _x : _y; })
|
||||
|
||||
#define min_t(type, a, b) min(((type) a), ((type) b))
|
||||
#define max_t(type, a, b) max(((type) a), ((type) b))
|
||||
|
||||
static inline uint16_t swab16(uint16_t x)
|
||||
{
|
||||
return ((x & (uint16_t)0x00ffU) << 8) |
|
||||
((x & (uint16_t)0xff00U) >> 8);
|
||||
}
|
||||
|
||||
static inline uint32_t swab32(uint32_t x)
|
||||
{
|
||||
return ((x & (uint32_t)0x000000ffUL) << 24) |
|
||||
((x & (uint32_t)0x0000ff00UL) << 8) |
|
||||
((x & (uint32_t)0x00ff0000UL) >> 8) |
|
||||
((x & (uint32_t)0xff000000UL) >> 24);
|
||||
}
|
||||
|
||||
static inline uint64_t swab64(uint64_t x)
|
||||
{
|
||||
return (uint64_t)((x & (uint64_t)0x00000000000000ffULL) << 56) |
|
||||
(uint64_t)((x & (uint64_t)0x000000000000ff00ULL) << 40) |
|
||||
(uint64_t)((x & (uint64_t)0x0000000000ff0000ULL) << 24) |
|
||||
(uint64_t)((x & (uint64_t)0x00000000ff000000ULL) << 8) |
|
||||
(uint64_t)((x & (uint64_t)0x000000ff00000000ULL) >> 8) |
|
||||
(uint64_t)((x & (uint64_t)0x0000ff0000000000ULL) >> 24) |
|
||||
(uint64_t)((x & (uint64_t)0x00ff000000000000ULL) >> 40) |
|
||||
(uint64_t)((x & (uint64_t)0xff00000000000000ULL) >> 56);
|
||||
}
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#define cpu_to_be16(x) swab16(x)
|
||||
#define be16_to_cpu(x) swab16(x)
|
||||
#define cpu_to_be32(x) swab32(x)
|
||||
#define be32_to_cpu(x) swab32(x)
|
||||
#define cpu_to_be64(x) swab64(x)
|
||||
#define be64_to_cpu(x) swab64(x)
|
||||
#else
|
||||
#define cpu_to_be16(x) (x)
|
||||
#define be16_to_cpu(x) (x)
|
||||
#define cpu_to_be32(x) (x)
|
||||
#define be32_to_cpu(x) (x)
|
||||
#define cpu_to_be64(x) (x)
|
||||
#define be64_to_cpu(x) (x)
|
||||
#endif
|
||||
107
target/linux/mpc85xx/image/spi-loader/loader.c
Normal file
107
target/linux/mpc85xx/image/spi-loader/loader.c
Normal file
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#include <image.h>
|
||||
#include <init.h>
|
||||
#include <spi.h>
|
||||
#include <spi-nor.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool check_image_header(const image_header_t *header)
|
||||
{
|
||||
if (header->ih_magic != cpu_to_be32(IH_MAGIC_OKLI)) {
|
||||
puts("Invalid image magic\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->ih_comp != cpu_to_be32(IH_COMP_NONE)) {
|
||||
puts("Unsupported compressed image\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t do_load(void)
|
||||
{
|
||||
image_header_t header;
|
||||
uint32_t ih_size, ih_load, ih_ep;
|
||||
|
||||
if (spi_nor_read_id())
|
||||
return UINT32_MAX;
|
||||
|
||||
puts("Reading image header...\n");
|
||||
if (spi_nor_read_data(&header, CONFIG_IMAGE_OFFSET, sizeof(header)))
|
||||
return UINT32_MAX;
|
||||
|
||||
if (!check_image_header(&header))
|
||||
return UINT32_MAX;
|
||||
|
||||
header.ih_name[sizeof(header.ih_name) - 1] = 0;
|
||||
ih_size = be32_to_cpu(header.ih_size);
|
||||
ih_load = be32_to_cpu(header.ih_load);
|
||||
ih_ep = be32_to_cpu(header.ih_ep);
|
||||
|
||||
put_with_label("Image Name: ", puts, (const char *)header.ih_name);
|
||||
put_with_label("Data Size: ", put_u32, ih_size);
|
||||
put_with_label("Load Address: ", put_u32, ih_load);
|
||||
put_with_label("Entry Point: ", put_u32, ih_ep);
|
||||
|
||||
puts("Reading image data...\n");
|
||||
void *loadaddr = (void *)ih_load;
|
||||
if (spi_nor_read_data(loadaddr, CONFIG_IMAGE_OFFSET + sizeof(header),
|
||||
ih_size))
|
||||
return false;
|
||||
|
||||
flush_cache(loadaddr, ih_size);
|
||||
|
||||
return ih_ep;
|
||||
}
|
||||
|
||||
static void enter_image(uint32_t addr)
|
||||
{
|
||||
typedef void (*entry_t)(void);
|
||||
entry_t entry = (entry_t)addr;
|
||||
|
||||
puts("Starting image...\n");
|
||||
entry();
|
||||
}
|
||||
|
||||
static void load(void)
|
||||
{
|
||||
uint32_t addr;
|
||||
int ret;
|
||||
|
||||
ret = spi_init(0, CONFIG_SPI_MAX_HZ, SPI_MODE_0);
|
||||
if (ret) {
|
||||
puts("Failed to initialize SPI controller\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = spi_claim_bus();
|
||||
if (ret) {
|
||||
puts("Failed to enable SPI controller\n");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = do_load();
|
||||
|
||||
spi_release_bus();
|
||||
|
||||
if (addr != UINT32_MAX)
|
||||
enter_image(addr);
|
||||
}
|
||||
|
||||
void start(void)
|
||||
{
|
||||
serial_console_init();
|
||||
puts("=== " CONFIG_PROGRAM_NAME " ===\n");
|
||||
|
||||
load();
|
||||
|
||||
puts("Halting execution.\n");
|
||||
while (true) {}
|
||||
}
|
||||
31
target/linux/mpc85xx/image/spi-loader/loader.lds
Normal file
31
target/linux/mpc85xx/image/spi-loader/loader.lds
Normal file
@@ -0,0 +1,31 @@
|
||||
OUTPUT_ARCH(powerpc:common)
|
||||
ENTRY(_start)
|
||||
EXTERN(_start)
|
||||
SECTIONS {
|
||||
.text :
|
||||
{
|
||||
_text_start = .;
|
||||
*(.text*)
|
||||
_text_len = ABSOLUTE(. - _text_start);
|
||||
}
|
||||
.data :
|
||||
{
|
||||
_data_start = .;
|
||||
*(.rodata*)
|
||||
*(.data*)
|
||||
*(.sdata*)
|
||||
_data_len = ABSOLUTE(. - _data_start);
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.bss :
|
||||
{
|
||||
_bss_start = .;
|
||||
. += 4K;
|
||||
_stack_top = .;
|
||||
*(.bss*)
|
||||
*(.sbss*)
|
||||
_bss_len = ABSOLUTE(. - _bss_start);
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
_end = .;
|
||||
}
|
||||
59
target/linux/mpc85xx/image/spi-loader/stdio.c
Normal file
59
target/linux/mpc85xx/image/spi-loader/stdio.c
Normal file
@@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (c) 2022 Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
while (*s)
|
||||
putchar(*s++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void put_u4(uint8_t v)
|
||||
{
|
||||
v &= 0xf;
|
||||
switch (v) {
|
||||
case 0x0 ... 0x9:
|
||||
putchar('0' + v);
|
||||
break;
|
||||
case 0xa ... 0xf:
|
||||
putchar('a' + (v - 0xa));
|
||||
}
|
||||
}
|
||||
|
||||
void put_u8(uint8_t v)
|
||||
{
|
||||
put_u4(v >> 4);
|
||||
put_u4(v);
|
||||
}
|
||||
|
||||
void put_u16(uint16_t v)
|
||||
{
|
||||
put_u8(v >> 8);
|
||||
put_u8(v);
|
||||
}
|
||||
|
||||
void put_u32(uint32_t v)
|
||||
{
|
||||
put_u16(v >> 16);
|
||||
put_u16(v);
|
||||
}
|
||||
|
||||
void put_ptr(const void *p)
|
||||
{
|
||||
put_u32((uint32_t)p);
|
||||
}
|
||||
|
||||
void put_array(const void *p, size_t l)
|
||||
{
|
||||
const uint8_t *c = p;
|
||||
size_t i;
|
||||
for (i = 0; i < l; i++) {
|
||||
put_u8(c[i]);
|
||||
putchar(' ');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
265
target/linux/mpc85xx/image/spi-loader/string.S
Normal file
265
target/linux/mpc85xx/image/spi-loader/string.S
Normal file
@@ -0,0 +1,265 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) Paul Mackerras 1997.
|
||||
*
|
||||
* NOTE: this code runs in 32 bit mode and is packaged as ELF32.
|
||||
*/
|
||||
|
||||
#include <ppc_asm.h>
|
||||
|
||||
.text
|
||||
.globl strcpy
|
||||
strcpy:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r5)
|
||||
bne 1b
|
||||
blr
|
||||
|
||||
.globl strncpy
|
||||
strncpy:
|
||||
cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r6,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r6)
|
||||
bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
|
||||
blr
|
||||
|
||||
.globl strcat
|
||||
strcat:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r0,1(r5)
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
addi r5,r5,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
stbu r0,1(r5)
|
||||
bne 1b
|
||||
blr
|
||||
|
||||
.globl strchr
|
||||
strchr:
|
||||
addi r3,r3,-1
|
||||
1: lbzu r0,1(r3)
|
||||
cmpw 0,r0,r4
|
||||
beqlr
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
li r3,0
|
||||
blr
|
||||
|
||||
.globl strcmp
|
||||
strcmp:
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r3,1(r5)
|
||||
cmpwi 1,r3,0
|
||||
lbzu r0,1(r4)
|
||||
subf. r3,r0,r3
|
||||
beqlr 1
|
||||
beq 1b
|
||||
blr
|
||||
|
||||
.globl strncmp
|
||||
strncmp:
|
||||
mtctr r5
|
||||
addi r5,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r3,1(r5)
|
||||
cmpwi 1,r3,0
|
||||
lbzu r0,1(r4)
|
||||
subf. r3,r0,r3
|
||||
beqlr 1
|
||||
bdnzt eq,1b
|
||||
blr
|
||||
|
||||
.globl strlen
|
||||
strlen:
|
||||
addi r4,r3,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
subf r3,r3,r4
|
||||
blr
|
||||
|
||||
.globl memset
|
||||
memset:
|
||||
rlwimi r4,r4,8,16,23
|
||||
rlwimi r4,r4,16,0,15
|
||||
addi r6,r3,-4
|
||||
cmplwi 0,r5,4
|
||||
blt 7f
|
||||
stwu r4,4(r6)
|
||||
beqlr
|
||||
andi. r0,r6,3
|
||||
add r5,r0,r5
|
||||
subf r6,r0,r6
|
||||
rlwinm r0,r5,32-2,2,31
|
||||
mtctr r0
|
||||
bdz 6f
|
||||
1: stwu r4,4(r6)
|
||||
bdnz 1b
|
||||
6: andi. r5,r5,3
|
||||
7: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r6,r6,3
|
||||
8: stbu r4,1(r6)
|
||||
bdnz 8b
|
||||
blr
|
||||
|
||||
.globl memmove
|
||||
memmove:
|
||||
cmplw 0,r3,r4
|
||||
bgt backwards_memcpy
|
||||
/* fall through */
|
||||
|
||||
.globl memcpy
|
||||
memcpy:
|
||||
rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
|
||||
addi r6,r3,-4
|
||||
addi r4,r4,-4
|
||||
beq 3f /* if less than 8 bytes to do */
|
||||
andi. r0,r6,3 /* get dest word aligned */
|
||||
mtctr r7
|
||||
bne 5f
|
||||
andi. r0,r4,3 /* check src word aligned too */
|
||||
bne 3f
|
||||
1: lwz r7,4(r4)
|
||||
lwzu r8,8(r4)
|
||||
stw r7,4(r6)
|
||||
stwu r8,8(r6)
|
||||
bdnz 1b
|
||||
andi. r5,r5,7
|
||||
2: cmplwi 0,r5,4
|
||||
blt 3f
|
||||
lwzu r0,4(r4)
|
||||
addi r5,r5,-4
|
||||
stwu r0,4(r6)
|
||||
3: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
addi r4,r4,3
|
||||
addi r6,r6,3
|
||||
4: lbzu r0,1(r4)
|
||||
stbu r0,1(r6)
|
||||
bdnz 4b
|
||||
blr
|
||||
5: subfic r0,r0,4
|
||||
cmpw cr1,r0,r5
|
||||
add r7,r0,r4
|
||||
andi. r7,r7,3 /* will source be word-aligned too? */
|
||||
ble cr1,3b
|
||||
bne 3b /* do byte-by-byte if not */
|
||||
mtctr r0
|
||||
6: lbz r7,4(r4)
|
||||
addi r4,r4,1
|
||||
stb r7,4(r6)
|
||||
addi r6,r6,1
|
||||
bdnz 6b
|
||||
subf r5,r0,r5
|
||||
rlwinm. r7,r5,32-3,3,31
|
||||
beq 2b
|
||||
mtctr r7
|
||||
b 1b
|
||||
|
||||
.globl backwards_memcpy
|
||||
backwards_memcpy:
|
||||
rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
|
||||
add r6,r3,r5
|
||||
add r4,r4,r5
|
||||
beq 3f
|
||||
andi. r0,r6,3
|
||||
mtctr r7
|
||||
bne 5f
|
||||
andi. r0,r4,3
|
||||
bne 3f
|
||||
1: lwz r7,-4(r4)
|
||||
lwzu r8,-8(r4)
|
||||
stw r7,-4(r6)
|
||||
stwu r8,-8(r6)
|
||||
bdnz 1b
|
||||
andi. r5,r5,7
|
||||
2: cmplwi 0,r5,4
|
||||
blt 3f
|
||||
lwzu r0,-4(r4)
|
||||
subi r5,r5,4
|
||||
stwu r0,-4(r6)
|
||||
3: cmpwi 0,r5,0
|
||||
beqlr
|
||||
mtctr r5
|
||||
4: lbzu r0,-1(r4)
|
||||
stbu r0,-1(r6)
|
||||
bdnz 4b
|
||||
blr
|
||||
5: cmpw cr1,r0,r5
|
||||
subf r7,r0,r4
|
||||
andi. r7,r7,3
|
||||
ble cr1,3b
|
||||
bne 3b
|
||||
mtctr r0
|
||||
6: lbzu r7,-1(r4)
|
||||
stbu r7,-1(r6)
|
||||
bdnz 6b
|
||||
subf r5,r0,r5
|
||||
rlwinm. r7,r5,32-3,3,31
|
||||
beq 2b
|
||||
mtctr r7
|
||||
b 1b
|
||||
|
||||
.globl memchr
|
||||
memchr:
|
||||
cmpwi 0,r5,0
|
||||
blelr
|
||||
mtctr r5
|
||||
addi r3,r3,-1
|
||||
1: lbzu r0,1(r3)
|
||||
cmpw r0,r4
|
||||
beqlr
|
||||
bdnz 1b
|
||||
li r3,0
|
||||
blr
|
||||
|
||||
.globl memcmp
|
||||
memcmp:
|
||||
cmpwi 0,r5,0
|
||||
ble 2f
|
||||
mtctr r5
|
||||
addi r6,r3,-1
|
||||
addi r4,r4,-1
|
||||
1: lbzu r3,1(r6)
|
||||
lbzu r0,1(r4)
|
||||
subf. r3,r0,r3
|
||||
bdnzt 2,1b
|
||||
blr
|
||||
2: li r3,0
|
||||
blr
|
||||
|
||||
|
||||
/*
|
||||
* Flush the dcache and invalidate the icache for a range of addresses.
|
||||
*
|
||||
* flush_cache(addr, len)
|
||||
*/
|
||||
.global flush_cache
|
||||
flush_cache:
|
||||
addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
|
||||
rlwinm. 4,4,27,5,31
|
||||
mtctr 4
|
||||
beqlr
|
||||
1: dcbf 0,3
|
||||
icbi 0,3
|
||||
addi 3,3,0x20
|
||||
bdnz 1b
|
||||
sync
|
||||
isync
|
||||
blr
|
||||
|
||||
151
target/linux/ramips/dts/mt7621_zyxel_nwa-ax.dtsi
Normal file
151
target/linux/ramips/dts/mt7621_zyxel_nwa-ax.dtsi
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "mt7621.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
label-mac-device = &gmac0;
|
||||
};
|
||||
};
|
||||
|
||||
&nand {
|
||||
status = "okay";
|
||||
|
||||
mediatek,nmbm;
|
||||
mediatek,bmt-max-ratio = <15>;
|
||||
mediatek,bmt-max-reserved-blocks = <64>;
|
||||
mediatek,bmt-remap-range =
|
||||
<0x0 0x980000>,
|
||||
<0x2980000 0x7800000>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "u-boot";
|
||||
reg = <0x0 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@80000 {
|
||||
label = "u-boot-env";
|
||||
reg = <0x80000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
factory: partition@100000 {
|
||||
label = "factory";
|
||||
reg = <0x100000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@180000 {
|
||||
label = "firmware";
|
||||
reg = <0x180000 0x2800000>;
|
||||
|
||||
/* This concatenates kernel1 & kernel2 & rootfs */
|
||||
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "kernel";
|
||||
reg = <0x0 0x800000>;
|
||||
};
|
||||
|
||||
partition@400000 {
|
||||
label = "ubi";
|
||||
reg = <0x800000 0x2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
partition@2980000 {
|
||||
label = "zy_firmware_1";
|
||||
reg = <0x2980000 0x2800000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@5180000 {
|
||||
label = "zy_rootfs_data";
|
||||
reg = <0x5180000 0x1400000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@6580000 {
|
||||
label = "zy_logs";
|
||||
reg = <0x6580000 0xd00000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@7280000 {
|
||||
label = "myzyxel";
|
||||
reg = <0x7280000 0x480000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@7700000 {
|
||||
label = "bootconfig";
|
||||
reg = <0x7700000 0x80000>;
|
||||
};
|
||||
|
||||
mrd: partition@7780000 {
|
||||
label = "mrd";
|
||||
reg = <0x7780000 0x80000>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pcie {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie1 {
|
||||
wlan_5g: wifi@0,0 {
|
||||
reg = <0x0 0 0 0 0>;
|
||||
compatible = "mediatek,mt76";
|
||||
|
||||
mediatek,mtd-eeprom = <&factory 0x0>;
|
||||
|
||||
/* MAC-Address set in userspace */
|
||||
};
|
||||
};
|
||||
|
||||
&gmac0 {
|
||||
nvmem-cells = <&macaddr_mrd_1fff8>;
|
||||
nvmem-cell-names = "mac-address";
|
||||
};
|
||||
|
||||
&switch0 {
|
||||
ports {
|
||||
port@4 {
|
||||
status = "okay";
|
||||
label = "lan";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&mrd {
|
||||
compatible = "nvmem-cells";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
macaddr_mrd_1fff8: macaddr@1fff8 {
|
||||
reg = <0x1fff8 0x6>;
|
||||
};
|
||||
};
|
||||
|
||||
&state_default {
|
||||
gpio {
|
||||
groups = "uart3", "rgmii2";
|
||||
function = "gpio";
|
||||
};
|
||||
};
|
||||
|
||||
ðernet {
|
||||
pinctrl-0 = <&mdio_pins>, <&rgmii1_pins>;
|
||||
};
|
||||
45
target/linux/ramips/dts/mt7621_zyxel_nwa50ax.dts
Normal file
45
target/linux/ramips/dts/mt7621_zyxel_nwa50ax.dts
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "mt7621_zyxel_nwa-ax.dtsi"
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
compatible = "zyxel,nwa50ax", "mediatek,mt7621-soc";
|
||||
model = "ZyXEL NWA50AX";
|
||||
|
||||
aliases {
|
||||
led-boot = &led_system_green;
|
||||
led-failsafe = &led_system_red;
|
||||
led-running = &led_system_green;
|
||||
led-upgrade = &led_system_red;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led_system_red: system_red {
|
||||
label = "red:system";
|
||||
gpios = <&gpio 6 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
led_system_green: system_green {
|
||||
label = "green:system";
|
||||
gpios = <&gpio 7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
system_blue {
|
||||
label = "blue:system";
|
||||
gpios = <&gpio 8 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
gpios = <&gpio 30 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_RESTART>;
|
||||
};
|
||||
};
|
||||
};
|
||||
6
target/linux/ramips/dts/mt7621_zyxel_nwa55axe.dts
Normal file
6
target/linux/ramips/dts/mt7621_zyxel_nwa55axe.dts
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "mt7621_zyxel_nwa-ax.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "zyxel,nwa55axe", "mediatek,mt7621-soc";
|
||||
model = "ZyXEL NWA55AXE";
|
||||
};
|
||||
1362
target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c
Normal file
1362
target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,13 @@ define Build/zytrx-header
|
||||
mv $@.new $@
|
||||
endef
|
||||
|
||||
define Build/zyxel-nwa-fit
|
||||
$(TOPDIR)/scripts/mkits-zyxel-fit.sh \
|
||||
$@.its $@ "6b e1 6f e1 ff ff ff ff ff ff"
|
||||
PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new
|
||||
@mv $@.new $@
|
||||
endef
|
||||
|
||||
define Device/dsa-migration
|
||||
DEVICE_COMPAT_VERSION := 1.1
|
||||
DEVICE_COMPAT_MESSAGE := Config cannot be migrated from swconfig to DSA
|
||||
@@ -2193,6 +2200,33 @@ define Device/zyxel_nr7101
|
||||
endef
|
||||
TARGET_DEVICES += zyxel_nr7101
|
||||
|
||||
define Device/zyxel_nwa-ax
|
||||
$(Device/dsa-migration)
|
||||
DEVICE_VENDOR := ZyXEL
|
||||
BLOCKSIZE := 128k
|
||||
PAGESIZE := 2048
|
||||
KERNEL_SIZE := 8192k
|
||||
UBINIZE_OPTS := -E 5
|
||||
DEVICE_PACKAGES := kmod-mt7915e uboot-envtools zyxel-bootconfig
|
||||
KERNEL := kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
|
||||
IMAGES += factory.bin ramboot-factory.bin
|
||||
IMAGE/factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi | zyxel-nwa-fit
|
||||
IMAGE/ramboot-factory.bin := append-kernel | pad-to $$(KERNEL_SIZE) | append-ubi
|
||||
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
|
||||
endef
|
||||
|
||||
define Device/zyxel_nwa50ax
|
||||
$(Device/zyxel_nwa-ax)
|
||||
DEVICE_MODEL := NWA50AX
|
||||
endef
|
||||
TARGET_DEVICES += zyxel_nwa50ax
|
||||
|
||||
define Device/zyxel_nwa55axe
|
||||
$(Device/zyxel_nwa-ax)
|
||||
DEVICE_MODEL := NWA55AXE
|
||||
endef
|
||||
TARGET_DEVICES += zyxel_nwa55axe
|
||||
|
||||
define Device/zyxel_wap6805
|
||||
$(Device/dsa-migration)
|
||||
BLOCKSIZE := 128k
|
||||
|
||||
@@ -21,7 +21,9 @@ ramips_setup_interfaces()
|
||||
tplink,re650-v2|\
|
||||
ubnt,unifi-6-lite|\
|
||||
ubnt,unifi-flexhd|\
|
||||
ubnt,unifi-nanohd)
|
||||
ubnt,unifi-nanohd|\
|
||||
zyxel,nwa50ax|\
|
||||
zyxel,nwa55axe)
|
||||
ucidef_set_interface_lan "lan"
|
||||
;;
|
||||
ampedwireless,ally-r1900k|\
|
||||
|
||||
@@ -106,4 +106,10 @@ case "$board" in
|
||||
[ "$PHYNBR" = "1" ] && \
|
||||
macaddr_setbit_la "$(mtd_get_mac_binary Factory 0xe000)" > /sys${DEVPATH}/macaddress
|
||||
;;
|
||||
zyxel,nwa50ax|\
|
||||
zyxel,nwa55axe)
|
||||
hw_mac_addr="$(mtd_get_mac_binary mrd 0x1fff8)"
|
||||
[ "$PHYNBR" = "0" ] && macaddr_add $hw_mac_addr 1 > /sys${DEVPATH}/macaddress
|
||||
[ "$PHYNBR" = "1" ] && macaddr_add $hw_mac_addr 2 > /sys${DEVPATH}/macaddress
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -95,7 +95,9 @@ platform_do_upgrade() {
|
||||
xiaomi,mi-router-cr6606|\
|
||||
xiaomi,mi-router-cr6608|\
|
||||
xiaomi,mi-router-cr6609|\
|
||||
xiaomi,redmi-router-ac2100)
|
||||
xiaomi,redmi-router-ac2100|\
|
||||
zyxel,nwa50ax|\
|
||||
zyxel,nwa55axe)
|
||||
nand_do_upgrade "$1"
|
||||
;;
|
||||
iodata,wn-ax1167gr2|\
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
1665185696
|
||||
1665787481
|
||||
|
||||
Reference in New Issue
Block a user