Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2021-04-10 13:40:59 +08:00
commit 787f4b8aac
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
58 changed files with 3030 additions and 562 deletions

View File

@ -118,6 +118,9 @@ KERNEL_MAKE_FLAGS = \
cmd_syscalls= \
$(if $(__package_mk),KBUILD_EXTRA_SYMBOLS="$(wildcard $(PKG_SYMVERS_DIR)/*.symvers)")
KERNEL_NOSTDINC_FLAGS = \
-nostdinc $(if $(DUMP),, -isystem $(shell $(TARGET_CC) -print-file-name=include))
ifeq ($(call qstrip,$(CONFIG_EXTERNAL_KERNEL_TREE))$(call qstrip,$(CONFIG_KERNEL_GIT_CLONE_URI)),)
KERNEL_MAKE_FLAGS += \
KERNELRELEASE=$(LINUX_VERSION)

View File

@ -52,7 +52,8 @@ $(call KernelPackage/ath10k-ct)
VARIANT:=smallbuffers
endef
NOSTDINC_FLAGS = \
NOSTDINC_FLAGS := \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(PKG_BUILD_DIR) \
-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
-I$(STAGING_DIR)/usr/include/mac80211-backport \

View File

@ -0,0 +1,301 @@
From: Johannes Berg <johannes.berg@intel.com>
Date: Sun, 6 Dec 2020 14:54:42 +0200
Subject: [PATCH] cfg80211: support immediate reconnect request hint
There are cases where it's necessary to disconnect, but an
immediate reconnection is desired. Support a hint to userspace
that this is the case, by including a new attribute in the
deauth or disassoc event.
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20201206145305.58d33941fb9d.I0e7168c205c7949529c8e3b86f3c9b12c01a7017@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6410,13 +6410,15 @@ void cfg80211_abandon_assoc(struct net_d
* @dev: network device
* @buf: 802.11 frame (header + body)
* @len: length of the frame data
+ * @reconnect: immediate reconnect is desired (include the nl80211 attribute)
*
* This function is called whenever deauthentication has been processed in
* station mode. This includes both received deauthentication frames and
* locally generated ones. This function may sleep. The caller must hold the
* corresponding wdev's mutex.
*/
-void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
+ bool reconnect);
/**
* cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2527,6 +2527,10 @@ enum nl80211_commands {
* override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
* NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
*
+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
+ * disassoc events to indicate that an immediate reconnect to the AP
+ * is desired.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3016,6 +3020,8 @@ enum nl80211_attrs {
NL80211_ATTR_S1G_CAPABILITY,
NL80211_ATTR_S1G_CAPABILITY_MASK,
+ NL80211_ATTR_RECONNECT_REQUESTED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2729,7 +2729,7 @@ static void ieee80211_report_disconnect(
};
if (tx)
- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len);
+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, false);
else
cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
@@ -4716,7 +4716,8 @@ void ieee80211_mgd_quiesce(struct ieee80
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
- IEEE80211_DEAUTH_FRAME_LEN);
+ IEEE80211_DEAUTH_FRAME_LEN,
+ false);
}
/* This is a bit of a hack - we should find a better and more generic
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2015 Intel Deutschland GmbH
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019-2020 Intel Corporation
*/
#include <linux/kernel.h>
@@ -81,7 +81,8 @@ static void cfg80211_process_auth(struct
}
static void cfg80211_process_deauth(struct wireless_dev *wdev,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ bool reconnect)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@@ -89,7 +90,7 @@ static void cfg80211_process_deauth(stru
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
- nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
+ nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL);
if (!wdev->current_bss ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
@@ -100,7 +101,8 @@ static void cfg80211_process_deauth(stru
}
static void cfg80211_process_disassoc(struct wireless_dev *wdev,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ bool reconnect)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@@ -108,7 +110,8 @@ static void cfg80211_process_disassoc(st
u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
- nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL);
+ nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect,
+ GFP_KERNEL);
if (WARN_ON(!wdev->current_bss ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
@@ -133,9 +136,9 @@ void cfg80211_rx_mlme_mgmt(struct net_de
if (ieee80211_is_auth(mgmt->frame_control))
cfg80211_process_auth(wdev, buf, len);
else if (ieee80211_is_deauth(mgmt->frame_control))
- cfg80211_process_deauth(wdev, buf, len);
+ cfg80211_process_deauth(wdev, buf, len, false);
else if (ieee80211_is_disassoc(mgmt->frame_control))
- cfg80211_process_disassoc(wdev, buf, len);
+ cfg80211_process_disassoc(wdev, buf, len, false);
}
EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
@@ -180,22 +183,23 @@ void cfg80211_abandon_assoc(struct net_d
}
EXPORT_SYMBOL(cfg80211_abandon_assoc);
-void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
+ bool reconnect)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_mgmt *mgmt = (void *)buf;
ASSERT_WDEV_LOCK(wdev);
- trace_cfg80211_tx_mlme_mgmt(dev, buf, len);
+ trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
if (WARN_ON(len < 2))
return;
if (ieee80211_is_deauth(mgmt->frame_control))
- cfg80211_process_deauth(wdev, buf, len);
+ cfg80211_process_deauth(wdev, buf, len, reconnect);
else
- cfg80211_process_disassoc(wdev, buf, len);
+ cfg80211_process_disassoc(wdev, buf, len, reconnect);
}
EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -732,6 +732,7 @@ static const struct nla_policy nl80211_p
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
[NL80211_ATTR_S1G_CAPABILITY_MASK] =
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
+ [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
};
/* policy for the key attributes */
@@ -15899,7 +15900,7 @@ static void nl80211_send_mlme_event(stru
const u8 *buf, size_t len,
enum nl80211_commands cmd, gfp_t gfp,
int uapsd_queues, const u8 *req_ies,
- size_t req_ies_len)
+ size_t req_ies_len, bool reconnect)
{
struct sk_buff *msg;
void *hdr;
@@ -15921,6 +15922,9 @@ static void nl80211_send_mlme_event(stru
nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies)))
goto nla_put_failure;
+ if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED))
+ goto nla_put_failure;
+
if (uapsd_queues >= 0) {
struct nlattr *nla_wmm =
nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME);
@@ -15949,7 +15953,8 @@ void nl80211_send_rx_auth(struct cfg8021
size_t len, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0);
+ NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0,
+ false);
}
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
@@ -15959,23 +15964,25 @@ void nl80211_send_rx_assoc(struct cfg802
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_ASSOCIATE, gfp, uapsd_queues,
- req_ies, req_ies_len);
+ req_ies, req_ies_len, false);
}
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+ size_t len, bool reconnect, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0);
+ NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0,
+ reconnect);
}
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+ size_t len, bool reconnect, gfp_t gfp)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0);
+ NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0,
+ reconnect);
}
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
@@ -16006,7 +16013,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
- NULL, 0);
+ NULL, 0, false);
}
EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Portions of this file
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018, 2020 Intel Corporation
*/
#ifndef __NET_WIRELESS_NL80211_H
#define __NET_WIRELESS_NL80211_H
@@ -69,10 +69,12 @@ void nl80211_send_rx_assoc(struct cfg802
const u8 *req_ies, size_t req_ies_len);
void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
- const u8 *buf, size_t len, gfp_t gfp);
+ const u8 *buf, size_t len,
+ bool reconnect, gfp_t gfp);
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
- const u8 *buf, size_t len, gfp_t gfp);
+ const u8 *buf, size_t len,
+ bool reconnect, gfp_t gfp);
void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *addr, gfp_t gfp);
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2684,19 +2684,23 @@ DEFINE_EVENT(netdev_frame_event, cfg8021
);
TRACE_EVENT(cfg80211_tx_mlme_mgmt,
- TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
- TP_ARGS(netdev, buf, len),
+ TP_PROTO(struct net_device *netdev, const u8 *buf, int len,
+ bool reconnect),
+ TP_ARGS(netdev, buf, len, reconnect),
TP_STRUCT__entry(
NETDEV_ENTRY
__dynamic_array(u8, frame, len)
+ __field(int, reconnect)
),
TP_fast_assign(
NETDEV_ASSIGN;
memcpy(__get_dynamic_array(frame), buf, len);
+ __entry->reconnect = reconnect;
),
- TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x",
+ TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x reconnect:%d",
NETDEV_PR_ARG,
- le16_to_cpup((__le16 *)__get_dynamic_array(frame)))
+ le16_to_cpup((__le16 *)__get_dynamic_array(frame)),
+ __entry->reconnect)
);
DECLARE_EVENT_CLASS(netdev_mac_evt,

View File

@ -0,0 +1,271 @@
From: Johannes Berg <johannes.berg@intel.com>
Date: Sun, 6 Dec 2020 14:54:43 +0200
Subject: [PATCH] mac80211: support driver-based disconnect with reconnect hint
Support the driver indicating that a disconnection needs
to be performed, and pass through the reconnect hint in
this case.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20201206145305.5c8dab7a22a0.I58459fdf6968b16c90cab9c574f0f04ca22b0c79@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -5885,6 +5885,17 @@ void ieee80211_beacon_loss(struct ieee80
void ieee80211_connection_loss(struct ieee80211_vif *vif);
/**
+ * ieee80211_disconnect - request disconnection
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @reconnect: immediate reconnect is desired
+ *
+ * Request disconnection from the current network and, if enabled, send a
+ * hint to the higher layers that immediate reconnect is desired.
+ */
+void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect);
+
+/**
* ieee80211_resume_disconnect - disconnect from AP after resume
*
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -461,7 +461,9 @@ struct ieee80211_if_managed {
unsigned long probe_timeout;
int probe_send_count;
bool nullfunc_failed;
- bool connection_loss;
+ u8 connection_loss:1,
+ driver_disconnect:1,
+ reconnect:1;
struct cfg80211_bss *associated;
struct ieee80211_mgd_auth_data *auth_data;
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2720,7 +2720,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get)
static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
const u8 *buf, size_t len, bool tx,
- u16 reason)
+ u16 reason, bool reconnect)
{
struct ieee80211_event event = {
.type = MLME_EVENT,
@@ -2729,7 +2729,7 @@ static void ieee80211_report_disconnect(
};
if (tx)
- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, false);
+ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect);
else
cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
@@ -2751,13 +2751,18 @@ static void __ieee80211_disconnect(struc
tx = !sdata->csa_block_tx;
- /* AP is probably out of range (or not reachable for another reason) so
- * remove the bss struct for that AP.
- */
- cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
+ if (!ifmgd->driver_disconnect) {
+ /*
+ * AP is probably out of range (or not reachable for another
+ * reason) so remove the bss struct for that AP.
+ */
+ cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
+ }
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ ifmgd->driver_disconnect ?
+ WLAN_REASON_DEAUTH_LEAVING :
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
tx, frame_buf);
mutex_lock(&local->mtx);
sdata->vif.csa_active = false;
@@ -2770,7 +2775,9 @@ static void __ieee80211_disconnect(struc
mutex_unlock(&local->mtx);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx,
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+ ifmgd->reconnect);
+ ifmgd->reconnect = false;
sdata_unlock(sdata);
}
@@ -2789,6 +2796,13 @@ static void ieee80211_beacon_connection_
sdata_info(sdata, "Connection to AP %pM lost\n",
ifmgd->bssid);
__ieee80211_disconnect(sdata);
+ ifmgd->connection_loss = false;
+ } else if (ifmgd->driver_disconnect) {
+ sdata_info(sdata,
+ "Driver requested disconnection from AP %pM\n",
+ ifmgd->bssid);
+ __ieee80211_disconnect(sdata);
+ ifmgd->driver_disconnect = false;
} else {
ieee80211_mgd_probe_ap(sdata, true);
}
@@ -2827,6 +2841,21 @@ void ieee80211_connection_loss(struct ie
}
EXPORT_SYMBOL(ieee80211_connection_loss);
+void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_hw *hw = &sdata->local->hw;
+
+ trace_api_disconnect(sdata, reconnect);
+
+ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return;
+
+ sdata->u.mgd.driver_disconnect = true;
+ sdata->u.mgd.reconnect = reconnect;
+ ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
+}
+EXPORT_SYMBOL(ieee80211_disconnect);
static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
bool assoc)
@@ -3130,7 +3159,7 @@ static void ieee80211_rx_mgmt_deauth(str
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false,
- reason_code);
+ reason_code, false);
return;
}
@@ -3179,7 +3208,8 @@ static void ieee80211_rx_mgmt_disassoc(s
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
- ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
+ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code,
+ false);
}
static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@ -4199,7 +4229,8 @@ static void ieee80211_rx_mgmt_beacon(str
true, deauth_buf);
ieee80211_report_disconnect(sdata, deauth_buf,
sizeof(deauth_buf), true,
- WLAN_REASON_DEAUTH_LEAVING);
+ WLAN_REASON_DEAUTH_LEAVING,
+ false);
return;
}
@@ -4344,7 +4375,7 @@ static void ieee80211_sta_connection_los
tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
- reason);
+ reason, false);
}
static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
@@ -5431,7 +5462,8 @@ int ieee80211_mgd_auth(struct ieee80211_
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- WLAN_REASON_UNSPECIFIED);
+ WLAN_REASON_UNSPECIFIED,
+ false);
}
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -5503,7 +5535,8 @@ int ieee80211_mgd_assoc(struct ieee80211
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- WLAN_REASON_UNSPECIFIED);
+ WLAN_REASON_UNSPECIFIED,
+ false);
}
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@@ -5802,7 +5835,7 @@ int ieee80211_mgd_deauth(struct ieee8021
ieee80211_destroy_auth_data(sdata, false);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5822,7 +5855,7 @@ int ieee80211_mgd_deauth(struct ieee8021
ieee80211_destroy_assoc_data(sdata, false, true);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5837,7 +5870,7 @@ int ieee80211_mgd_deauth(struct ieee8021
req->reason_code, tx, frame_buf);
ieee80211_report_disconnect(sdata, frame_buf,
sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
@@ -5870,7 +5903,7 @@ int ieee80211_mgd_disassoc(struct ieee80
frame_buf);
ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
- req->reason_code);
+ req->reason_code, false);
return 0;
}
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2,7 +2,7 @@
/*
* Portions of this file
* Copyright(c) 2016-2017 Intel Deutschland GmbH
-* Copyright (C) 2018 - 2019 Intel Corporation
+* Copyright (C) 2018 - 2020 Intel Corporation
*/
#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ)
@@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss,
)
);
+TRACE_EVENT(api_disconnect,
+ TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect),
+
+ TP_ARGS(sdata, reconnect),
+
+ TP_STRUCT__entry(
+ VIF_ENTRY
+ __field(int, reconnect)
+ ),
+
+ TP_fast_assign(
+ VIF_ASSIGN;
+ __entry->reconnect = reconnect;
+ ),
+
+ TP_printk(
+ VIF_PR_FMT " reconnect:%d",
+ VIF_PR_ARG, __entry->reconnect
+ )
+);
+
TRACE_EVENT(api_cqm_rssi_notify,
TP_PROTO(struct ieee80211_sub_if_data *sdata,
enum nl80211_cqm_rssi_threshold_event rssi_event,

View File

@ -68,7 +68,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static int fq_init(struct fq *fq, int flows_cnt)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -855,7 +855,6 @@ enum txq_info_flags {
@@ -857,7 +857,6 @@ enum txq_info_flags {
*/
struct txq_info {
struct fq_tin tin;

View File

@ -536,7 +536,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
};
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2740,7 +2740,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u
@@ -2761,7 +2761,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u
TP_ARGS(local, sdata)
);
@ -545,7 +545,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, bool enabled),
@@ -2767,6 +2767,22 @@ TRACE_EVENT(drv_sta_set_4addr,
@@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr,
)
);

View File

@ -0,0 +1,61 @@
From: Johannes Berg <johannes.berg@intel.com>
Date: Tue, 23 Mar 2021 21:05:01 +0100
Subject: [PATCH] mac80211: fix TXQ AC confusion
Normally, TXQs have
txq->tid = tid;
txq->ac = ieee80211_ac_from_tid(tid);
However, the special management TXQ actually has
txq->tid = IEEE80211_NUM_TIDS; // 16
txq->ac = IEEE80211_AC_VO;
This makes sense, but ieee80211_ac_from_tid(16) is the same
as ieee80211_ac_from_tid(0) which is just IEEE80211_AC_BE.
Now, normally this is fine. However, if the netdev queues
were stopped, then the code in ieee80211_tx_dequeue() will
propagate the stop from the interface (vif->txqs_stopped[])
if the AC 2 (ieee80211_ac_from_tid(txq->tid)) is marked as
stopped. On wake, however, __ieee80211_wake_txqs() will wake
the TXQ if AC 0 (txq->ac) is woken up.
If a driver stops all queues with ieee80211_stop_tx_queues()
and then wakes them again with ieee80211_wake_tx_queues(),
the ieee80211_wake_txqs() tasklet will run to resync queue
and TXQ state. If all queues were woken, then what'll happen
is that _ieee80211_wake_txqs() will run in order of HW queues
0-3, typically (and certainly for iwlwifi) corresponding to
ACs 0-3, so it'll call __ieee80211_wake_txqs() for each AC in
order 0-3.
When __ieee80211_wake_txqs() is called for AC 0 (VO) that'll
wake up the management TXQ (remember its tid is 16), and the
driver's wake_tx_queue() will be called. That tries to get a
frame, which will immediately *stop* the TXQ again, because
now we check against AC 2, and AC 2 hasn't yet been marked as
woken up again in sdata->vif.txqs_stopped[] since we're only
in the __ieee80211_wake_txqs() call for AC 0.
Thus, the management TXQ will never be started again.
Fix this by checking txq->ac directly instead of calculating
the AC as ieee80211_ac_from_tid(txq->tid).
Fixes: adf8ed01e4fd ("mac80211: add an optional TXQ for other PS-buffered frames")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3589,7 +3589,7 @@ begin:
test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
goto out;
- if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
+ if (vif->txqs_stopped[txq->ac]) {
set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
goto out;
}

View File

@ -0,0 +1,60 @@
From: Johannes Berg <johannes.berg@intel.com>
Date: Fri, 19 Mar 2021 23:28:01 +0100
Subject: [PATCH] mac80211: don't apply flow control on management frames
In some cases (depending on the driver, but it's true e.g. for
iwlwifi) we're using an internal TXQ for management packets,
mostly to simplify the code and to have a place to queue them.
However, it appears that in certain cases we can confuse the
code and management frames are dropped, which is certainly not
what we want.
Short-circuit the processing of management frames. To keep the
impact minimal, only put them on the frags queue and check the
tid == management only for doing that and to skip the airtime
fairness checks, if applicable.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -5,7 +5,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*
* Transmit and frame generation functions.
*/
@@ -1403,8 +1403,17 @@ static void ieee80211_txq_enqueue(struct
ieee80211_set_skb_enqueue_time(skb);
spin_lock_bh(&fq->lock);
- fq_tin_enqueue(fq, tin, flow_idx, skb,
- fq_skb_free_func);
+ /*
+ * For management frames, don't really apply codel etc.,
+ * we don't want to apply any shaping or anything we just
+ * want to simplify the driver API by having them on the
+ * txqi.
+ */
+ if (unlikely(txqi->txq.tid == IEEE80211_NUM_TIDS))
+ __skb_queue_tail(&txqi->frags, skb);
+ else
+ fq_tin_enqueue(fq, tin, flow_idx, skb,
+ fq_skb_free_func);
spin_unlock_bh(&fq->lock);
}
@@ -3846,6 +3855,9 @@ bool ieee80211_txq_airtime_check(struct
if (!txq->sta)
return true;
+ if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
+ return true;
+
sta = container_of(txq->sta, struct sta_info, sta);
if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
sta->airtime[txq->ac].aql_limit_low)

View File

@ -0,0 +1,21 @@
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Mon, 8 Mar 2021 23:01:49 +0100
Subject: [PATCH] mac80211: set sk_pacing_shift for 802.3 txpath
Similar to 802.11 txpath, set socket sk_pacing_shift for 802.3 tx path.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4173,6 +4173,9 @@ static bool ieee80211_tx_8023(struct iee
unsigned long flags;
int q = info->hw_queue;
+ if (sta)
+ sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
+
if (ieee80211_queue_skb(local, sdata, sta, skb))
return true;

View File

@ -36,9 +36,9 @@
u8 ps_dtim_period;
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2527,6 +2527,9 @@ enum nl80211_commands {
* override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
* NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
@@ -2531,6 +2531,9 @@ enum nl80211_commands {
* disassoc events to indicate that an immediate reconnect to the AP
* is desired.
*
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
@ -46,9 +46,9 @@
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3016,6 +3019,8 @@ enum nl80211_attrs {
NL80211_ATTR_S1G_CAPABILITY,
NL80211_ATTR_S1G_CAPABILITY_MASK,
@@ -3022,6 +3025,8 @@ enum nl80211_attrs {
NL80211_ATTR_RECONNECT_REQUESTED,
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
@ -87,7 +87,7 @@
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1401,6 +1401,7 @@ struct ieee80211_local {
@@ -1403,6 +1403,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */
@ -129,15 +129,15 @@
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -732,6 +732,7 @@ static const struct nla_policy nl80211_p
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
@@ -733,6 +733,7 @@ static const struct nla_policy nl80211_p
[NL80211_ATTR_S1G_CAPABILITY_MASK] =
NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -3240,6 +3241,20 @@ static int nl80211_set_wiphy(struct sk_b
@@ -3241,6 +3242,20 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
return result;
}

View File

@ -235,7 +235,8 @@ endef
TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny
NOSTDINC_FLAGS = \
NOSTDINC_FLAGS := \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(PKG_BUILD_DIR) \
-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
-I$(STAGING_DIR)/usr/include/mac80211-backport \

View File

@ -34,7 +34,8 @@ define KernelPackage/mwlwifi
AUTOLOAD:=$(call AutoLoad,50,mwlwifi)
endef
NOSTDINC_FLAGS = \
NOSTDINC_FLAGS := \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(PKG_BUILD_DIR) \
-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
-I$(STAGING_DIR)/usr/include/mac80211-backport \

View File

@ -31,7 +31,8 @@ define KernelPackage/rtl8812au-ct
PROVIDES:=kmod-rtl8812au
endef
NOSTDINC_FLAGS = \
NOSTDINC_FLAGS := \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(PKG_BUILD_DIR) \
-I$(PKG_BUILD_DIR)/include \
-I$(STAGING_DIR)/usr/include/mac80211-backport \

View File

@ -1,19 +1,25 @@
--- a/nl80211.h
+++ b/nl80211.h
@@ -2527,6 +2527,9 @@ enum nl80211_commands {
@@ -2527,6 +2527,13 @@ enum nl80211_commands {
* override mask. Used with NL80211_ATTR_S1G_CAPABILITY in
* NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT.
*
+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
+ * disassoc events to indicate that an immediate reconnect to the AP
+ * is desired.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+ * transmit power to stay within regulatory limits. u32, dBi.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3016,6 +3019,8 @@ enum nl80211_attrs {
@@ -3016,6 +3023,10 @@ enum nl80211_attrs {
NL80211_ATTR_S1G_CAPABILITY,
NL80211_ATTR_S1G_CAPABILITY_MASK,
+ NL80211_ATTR_RECONNECT_REQUESTED,
+
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+
/* add attributes here, update the policy in nl80211.c */

View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: GPL-2.0-only
include $(TOPDIR)/rules.mk
PKG_NAME:=bcm4908img
PKG_RELEASE:=1
PKG_BUILD_DEPENDS := bcm4908img/host
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/bcm4908img
SECTION:=utils
CATEGORY:=Base system
TITLE:=Utility handling BCM4908 images
MAINTAINER:=Rafał Miłecki <rafal@milecki.pl>
DEPENDS:=@TARGET_bcm4908
endef
define Package/bcm4908img/description
CFE bootloader for BCM4908 uses custom image format. It consists of:
1. Optional cferom image
2. bootfs JFFS2 partition (cferam, kernel, DTB and optional helper files)
3. padding
4. rootfs simply appended to the bootfs + padding
5. tail with checksum and basic device info
This util allows creating, modifying and extracting from BCM4908 images.
endef
define Host/Prepare
$(CP) ./src/* $(HOST_BUILD_DIR)
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS) -Wall"
endef
define Package/bcm4908img/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bcm4908img $(1)/usr/bin/
endef
define Host/Install
$(INSTALL_BIN) $(HOST_BUILD_DIR)/bcm4908img $(STAGING_DIR_HOST)/bin/
endef
$(eval $(call BuildPackage,bcm4908img))
$(eval $(call HostBuild))

View File

@ -0,0 +1,7 @@
all: bcm4908img
bcm4908img:
$(CC) $(CFLAGS) -o $@ bcm4908img.c -Wall
clean:
rm -f bcm4908img

View File

@ -0,0 +1,997 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
*/
#include <byteswap.h>
#include <endian.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le32(x) bswap_32(x)
#define le32_to_cpu(x) bswap_32(x)
#define cpu_to_be32(x) (x)
#define be32_to_cpu(x) (x)
#define cpu_to_le16(x) bswap_16(x)
#define le16_to_cpu(x) bswap_16(x)
#define cpu_to_be16(x) (x)
#define be16_to_cpu(x) (x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le32(x) (x)
#define le32_to_cpu(x) (x)
#define cpu_to_be32(x) bswap_32(x)
#define be32_to_cpu(x) bswap_32(x)
#define cpu_to_le16(x) (x)
#define le16_to_cpu(x) (x)
#define cpu_to_be16(x) bswap_16(x)
#define be16_to_cpu(x) bswap_16(x)
#else
#error "Unsupported endianness"
#endif
#define WFI_VERSION 0x00005732
#define WFI_VERSION_NAND_1MB_DATA 0x00005731
#define WFI_NOR_FLASH 1
#define WFI_NAND16_FLASH 2
#define WFI_NAND128_FLASH 3
#define WFI_NAND256_FLASH 4
#define WFI_NAND512_FLASH 5
#define WFI_NAND1024_FLASH 6
#define WFI_NAND2048_FLASH 7
#define WFI_FLAG_HAS_PMC 0x1
#define WFI_FLAG_SUPPORTS_BTRM 0x2
#define UBI_EC_HDR_MAGIC 0x55424923
static int debug;
struct bcm4908img_tail {
uint32_t crc32;
uint32_t version;
uint32_t chip_id;
uint32_t flash_type;
uint32_t flags;
};
/**
* struct bcm4908img_info - info about BCM4908 image
*
* Standard BCM4908 image consists of:
* 1. (Optional) vedor header
* 2. (Optional) cferom
* 3. bootfs
* 4. padding firmware
* 5. rootfs
* 6. BCM4908 tail
*/
struct bcm4908img_info {
size_t file_size;
size_t cferom_offset;
size_t bootfs_offset;
size_t padding_offset;
size_t rootfs_offset;
uint32_t crc32; /* Calculated checksum */
struct bcm4908img_tail tail;
};
char *pathname;
static inline size_t bcm4908img_min(size_t x, size_t y) {
return x < y ? x : y;
}
/**************************************************
* CRC32
**************************************************/
static const uint32_t crc32_tbl[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
uint32_t bcm4908img_crc32(uint32_t crc, const void *buf, size_t len) {
const uint8_t *in = buf;
while (len) {
crc = crc32_tbl[(crc ^ *in) & 0xff] ^ (crc >> 8);
in++;
len--;
}
return crc;
}
/**************************************************
* Helpers
**************************************************/
static FILE *bcm4908img_open(const char *pathname, const char *mode) {
struct stat st;
if (pathname)
return fopen(pathname, mode);
if (isatty(fileno(stdin))) {
fprintf(stderr, "Reading from TTY stdin is unsupported\n");
return NULL;
}
if (fstat(fileno(stdin), &st)) {
fprintf(stderr, "Failed to fstat stdin: %d\n", -errno);
return NULL;
}
if (S_ISFIFO(st.st_mode)) {
fprintf(stderr, "Reading from pipe stdin is unsupported\n");
return NULL;
}
return stdin;
}
static void bcm4908img_close(FILE *fp) {
if (fp != stdin)
fclose(fp);
}
static int bcm4908img_calc_crc32(FILE *fp, struct bcm4908img_info *info) {
uint8_t buf[1024];
size_t length;
size_t bytes;
/* Start with cferom (or bootfs) - skip vendor header */
fseek(fp, info->cferom_offset, SEEK_SET);
info->crc32 = 0xffffffff;
length = info->file_size - info->cferom_offset - sizeof(struct bcm4908img_tail);
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
length -= bytes;
}
if (length) {
fprintf(stderr, "Failed to read last %zd B of data\n", length);
return -EIO;
}
return 0;
}
/**************************************************
* Existing firmware parser
**************************************************/
struct chk_header {
uint32_t magic;
uint32_t header_len;
uint8_t reserved[8];
uint32_t kernel_chksum;
uint32_t rootfs_chksum;
uint32_t kernel_len;
uint32_t rootfs_len;
uint32_t image_chksum;
uint32_t header_chksum;
char board_id[0];
};
static bool bcm4908img_is_all_ff(const void *buf, size_t length)
{
const uint8_t *in = buf;
int i;
for (i = 0; i < length; i++) {
if (in[i] != 0xff)
return false;
}
return true;
}
static int bcm4908img_parse(FILE *fp, struct bcm4908img_info *info) {
struct bcm4908img_tail *tail = &info->tail;
struct chk_header *chk;
struct stat st;
uint8_t buf[1024];
uint16_t tmp16;
size_t length;
size_t bytes;
int err = 0;
memset(info, 0, sizeof(*info));
/* File size */
if (fstat(fileno(fp), &st)) {
err = -errno;
fprintf(stderr, "Failed to fstat: %d\n", err);
return err;
}
info->file_size = st.st_size;
/* Vendor formats */
rewind(fp);
if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) {
fprintf(stderr, "Failed to read file header\n");
return -EIO;
}
chk = (void *)buf;
if (be32_to_cpu(chk->magic) == 0x2a23245e)
info->cferom_offset = be32_to_cpu(chk->header_len);
/* Offsets */
for (info->bootfs_offset = info->cferom_offset;
info->bootfs_offset < info->file_size;
info->bootfs_offset += 0x20000) {
if (fseek(fp, info->bootfs_offset, SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek to the 0x%zx\n", info->bootfs_offset);
return err;
}
if (fread(&tmp16, 1, sizeof(tmp16), fp) != sizeof(tmp16)) {
fprintf(stderr, "Failed to read while looking for JFFS2\n");
return -EIO;
}
if (be16_to_cpu(tmp16) == 0x8519)
break;
}
if (info->bootfs_offset >= info->file_size) {
fprintf(stderr, "Failed to find bootfs offset\n");
return -EPROTO;
}
for (info->rootfs_offset = info->bootfs_offset;
info->rootfs_offset < info->file_size;
info->rootfs_offset += 0x20000) {
uint32_t *magic = (uint32_t *)&buf[0];
if (fseek(fp, info->rootfs_offset, SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek: %d\n", err);
return err;
}
length = info->padding_offset ? sizeof(*magic) : 256;
bytes = fread(buf, 1, length, fp);
if (bytes != length) {
fprintf(stderr, "Failed to read %zu bytes\n", length);
return -EIO;
}
if (!info->padding_offset && bcm4908img_is_all_ff(buf, length))
info->padding_offset = info->rootfs_offset;
if (be32_to_cpu(*magic) == UBI_EC_HDR_MAGIC)
break;
}
if (info->rootfs_offset >= info->file_size) {
fprintf(stderr, "Failed to find rootfs offset\n");
return -EPROTO;
}
/* CRC32 */
/* Start with cferom (or bootfs) - skip vendor header */
fseek(fp, info->cferom_offset, SEEK_SET);
info->crc32 = 0xffffffff;
length = info->file_size - info->cferom_offset - sizeof(*tail);
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
info->crc32 = bcm4908img_crc32(info->crc32, buf, bytes);
length -= bytes;
}
if (length) {
fprintf(stderr, "Failed to read last %zd B of data\n", length);
return -EIO;
}
/* Tail */
if (fread(tail, 1, sizeof(*tail), fp) != sizeof(*tail)) {
fprintf(stderr, "Failed to read BCM4908 image tail\n");
return -EIO;
}
/* Standard validation */
if (info->crc32 != le32_to_cpu(tail->crc32)) {
fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", info->crc32, le32_to_cpu(tail->crc32));
return -EPROTO;
}
return 0;
}
/**************************************************
* Info
**************************************************/
static int bcm4908img_info(int argc, char **argv) {
struct bcm4908img_info info;
const char *pathname = NULL;
FILE *fp;
int c;
int err = 0;
while ((c = getopt(argc, argv, "i:")) != -1) {
switch (c) {
case 'i':
pathname = optarg;
break;
}
}
fp = bcm4908img_open(pathname, "r");
if (!fp) {
fprintf(stderr, "Failed to open BCM4908 image\n");
err = -EACCES;
goto out;
}
err = bcm4908img_parse(fp, &info);
if (err) {
fprintf(stderr, "Failed to parse BCM4908 image\n");
goto err_close;
}
if (info.bootfs_offset != info.cferom_offset)
printf("cferom offset:\t%zu\n", info.cferom_offset);
printf("bootfs offset:\t0x%zx\n", info.bootfs_offset);
if (info.padding_offset)
printf("padding offset:\t0x%zx\n", info.padding_offset);
printf("rootfs offset:\t0x%zx\n", info.rootfs_offset);
printf("Checksum:\t0x%08x\n", info.crc32);
err_close:
bcm4908img_close(fp);
out:
return err;
}
/**************************************************
* Create
**************************************************/
static ssize_t bcm4908img_create_append_file(FILE *trx, const char *in_path, uint32_t *crc32) {
FILE *in;
size_t bytes;
ssize_t length = 0;
uint8_t buf[1024];
in = fopen(in_path, "r");
if (!in) {
fprintf(stderr, "Failed to open %s\n", in_path);
return -EACCES;
}
while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
if (fwrite(buf, 1, bytes, trx) != bytes) {
fprintf(stderr, "Failed to write %zu B to %s\n", bytes, pathname);
length = -EIO;
break;
}
*crc32 = bcm4908img_crc32(*crc32, buf, bytes);
length += bytes;
}
fclose(in);
return length;
}
static ssize_t bcm4908img_create_append_zeros(FILE *trx, size_t length) {
uint8_t *buf;
buf = malloc(length);
if (!buf)
return -ENOMEM;
memset(buf, 0, length);
if (fwrite(buf, 1, length, trx) != length) {
fprintf(stderr, "Failed to write %zu B to %s\n", length, pathname);
free(buf);
return -EIO;
}
free(buf);
return length;
}
static ssize_t bcm4908img_create_align(FILE *trx, size_t cur_offset, size_t alignment) {
if (cur_offset & (alignment - 1)) {
size_t length = alignment - (cur_offset % alignment);
return bcm4908img_create_append_zeros(trx, length);
}
return 0;
}
static int bcm4908img_create(int argc, char **argv) {
struct bcm4908img_tail tail = {
.version = cpu_to_le32(WFI_VERSION),
.chip_id = cpu_to_le32(0x4908),
.flash_type = cpu_to_le32(WFI_NAND128_FLASH),
.flags = cpu_to_le32(WFI_FLAG_SUPPORTS_BTRM),
};
uint32_t crc32 = 0xffffffff;
size_t cur_offset = 0;
ssize_t bytes;
FILE *fp;
int c;
int err = 0;
if (argc < 3) {
fprintf(stderr, "No BCM4908 image pathname passed\n");
err = -EINVAL;
goto out;
}
pathname = argv[2];
fp = fopen(pathname, "w+");
if (!fp) {
fprintf(stderr, "Failed to open %s\n", pathname);
err = -EACCES;
goto out;
}
optind = 3;
while ((c = getopt(argc, argv, "f:a:A:")) != -1) {
switch (c) {
case 'f':
bytes = bcm4908img_create_append_file(fp, optarg, &crc32);
if (bytes < 0) {
fprintf(stderr, "Failed to append file %s\n", optarg);
} else {
cur_offset += bytes;
}
break;
case 'a':
bytes = bcm4908img_create_align(fp, cur_offset, strtol(optarg, NULL, 0));
if (bytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
cur_offset += bytes;
break;
case 'A':
bytes = strtol(optarg, NULL, 0) - cur_offset;
if (bytes < 0) {
fprintf(stderr, "Current BCM4908 image length is 0x%zx, can't pad it with zeros to 0x%lx\n", cur_offset, strtol(optarg, NULL, 0));
} else {
bytes = bcm4908img_create_append_zeros(fp, bytes);
if (bytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
cur_offset += bytes;
}
break;
}
if (err)
goto err_close;
}
tail.crc32 = cpu_to_le32(crc32);
bytes = fwrite(&tail, 1, sizeof(tail), fp);
if (bytes != sizeof(tail)) {
fprintf(stderr, "Failed to write BCM4908 image tail to %s\n", pathname);
return -EIO;
}
err_close:
fclose(fp);
out:
return err;
}
/**************************************************
* Extract
**************************************************/
static int bcm4908img_extract(int argc, char **argv) {
struct bcm4908img_info info;
const char *pathname = NULL;
const char *type = NULL;
uint8_t buf[1024];
size_t offset;
size_t length;
size_t bytes;
FILE *fp;
int c;
int err = 0;
while ((c = getopt(argc, argv, "i:t:")) != -1) {
switch (c) {
case 'i':
pathname = optarg;
break;
case 't':
type = optarg;
break;
}
}
fp = bcm4908img_open(pathname, "r");
if (!fp) {
fprintf(stderr, "Failed to open BCM4908 image\n");
err = -EACCES;
goto err_out;
}
err = bcm4908img_parse(fp, &info);
if (err) {
fprintf(stderr, "Failed to parse BCM4908 image\n");
goto err_close;
}
if (!type) {
err = -EINVAL;
fprintf(stderr, "No data to extract specified\n");
goto err_close;
} else if (!strcmp(type, "cferom")) {
offset = info.cferom_offset;
length = info.bootfs_offset - offset;
if (!length) {
err = -ENOENT;
fprintf(stderr, "This BCM4908 image doesn't contain cferom\n");
goto err_close;
}
} else if (!strcmp(type, "bootfs")) {
offset = info.bootfs_offset;
length = (info.padding_offset ? info.padding_offset : info.rootfs_offset) - offset;
} else if (!strcmp(type, "rootfs")) {
offset = info.rootfs_offset;
length = info.file_size - offset - sizeof(struct bcm4908img_tail);
} else if (!strcmp(type, "firmware")) {
offset = info.bootfs_offset;
length = info.file_size - offset - sizeof(struct bcm4908img_tail);
} else {
err = -EINVAL;
fprintf(stderr, "Unsupported extract type: %s\n", type);
goto err_close;
}
if (!length) {
err = -EINVAL;
fprintf(stderr, "Failed to find requested data in input image\n");
goto err_close;
}
fseek(fp, offset, SEEK_SET);
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
fwrite(buf, bytes, 1, stdout);
length -= bytes;
}
if (length) {
err = -EIO;
fprintf(stderr, "Failed to read last %zd B of data\n", length);
goto err_close;
}
err_close:
bcm4908img_close(fp);
err_out:
return err;
}
/**************************************************
* bootfs
**************************************************/
#define JFFS2_MAGIC_BITMASK 0x1985
#define JFFS2_COMPR_NONE 0x00
#define JFFS2_COMPR_ZERO 0x01
#define JFFS2_COMPR_RTIME 0x02
#define JFFS2_COMPR_RUBINMIPS 0x03
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
#define JFFS2_COMPR_LZO 0x07
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
/* INCOMPAT: Fail to mount the filesystem */
#define JFFS2_FEATURE_INCOMPAT 0xc000
/* ROCOMPAT: Mount read-only */
#define JFFS2_FEATURE_ROCOMPAT 0x8000
/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
typedef struct {
uint32_t v32;
} __attribute__((packed)) jint32_t;
typedef struct {
uint16_t v16;
} __attribute__((packed)) jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
};
struct jffs2_raw_dirent
{
jint16_t magic;
jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t pino;
jint32_t version;
jint32_t ino; /* == zero for unlink */
jint32_t mctime;
uint8_t nsize;
uint8_t type;
uint8_t unused[2];
jint32_t node_crc;
jint32_t name_crc;
uint8_t name[0];
};
#define je16_to_cpu(x) ((x).v16)
#define je32_to_cpu(x) ((x).v32)
static int bcm4908img_bootfs_ls(FILE *fp, struct bcm4908img_info *info) {
struct jffs2_unknown_node node;
struct jffs2_raw_dirent dirent;
size_t offset;
size_t bytes;
int err = 0;
for (offset = info->bootfs_offset; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) {
char name[FILENAME_MAX + 1];
if (fseek(fp, offset, SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek: %d\n", err);
return err;
}
bytes = fread(&node, 1, sizeof(node), fp);
if (bytes != sizeof(node)) {
fprintf(stderr, "Failed to read %zu bytes\n", sizeof(node));
return -EIO;
}
if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) {
break;
}
if (je16_to_cpu(node.nodetype) != JFFS2_NODETYPE_DIRENT) {
continue;
}
memcpy(&dirent, &node, sizeof(node));
bytes += fread((uint8_t *)&dirent + sizeof(node), 1, sizeof(dirent) - sizeof(node), fp);
if (bytes != sizeof(dirent)) {
fprintf(stderr, "Failed to read %zu bytes\n", sizeof(node));
return -EIO;
}
if (dirent.nsize + 1 > sizeof(name)) {
/* Keep reading & printing BUT exit with error code */
fprintf(stderr, "Too long filename\n");
err = -ENOMEM;
continue;
}
bytes = fread(name, 1, dirent.nsize, fp);
if (bytes != dirent.nsize) {
fprintf(stderr, "Failed to read filename\n");
return -EIO;
}
name[bytes] = '\0';
printf("%s\n", name);
}
return err;
}
static int bcm4908img_bootfs_mv(FILE *fp, struct bcm4908img_info *info, int argc, char **argv) {
struct jffs2_unknown_node node;
struct jffs2_raw_dirent dirent;
const char *oldname;
const char *newname;
size_t offset;
size_t bytes;
int err = -ENOENT;
if (argc - optind < 2) {
fprintf(stderr, "No enough arguments passed\n");
return -EINVAL;
}
oldname = argv[optind++];
newname = argv[optind++];
if (strlen(newname) != strlen(oldname)) {
fprintf(stderr, "New filename must have the same length as the old one\n");
return -EINVAL;
}
for (offset = info->bootfs_offset; ; offset += (je32_to_cpu(node.totlen) + 0x03) & ~0x03) {
char name[FILENAME_MAX];
uint32_t crc32;
if (fseek(fp, offset, SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek: %d\n", err);
return err;
}
bytes = fread(&node, 1, sizeof(node), fp);
if (bytes != sizeof(node)) {
fprintf(stderr, "Failed to read %zu bytes\n", sizeof(node));
return -EIO;
}
if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) {
break;
}
if (je16_to_cpu(node.nodetype) != JFFS2_NODETYPE_DIRENT) {
continue;
}
bytes += fread((uint8_t *)&dirent + sizeof(node), 1, sizeof(dirent) - sizeof(node), fp);
if (bytes != sizeof(dirent)) {
fprintf(stderr, "Failed to read %zu bytes\n", sizeof(node));
return -EIO;
}
if (dirent.nsize + 1 > sizeof(name)) {
fprintf(stderr, "Too long filename\n");
err = -ENOMEM;
continue;
}
bytes = fread(name, 1, dirent.nsize, fp);
if (bytes != dirent.nsize) {
fprintf(stderr, "Failed to read filename\n");
return -EIO;
}
name[bytes] = '\0';
if (debug)
printf("offset:%08zx name_crc:%04x filename:%s\n", offset, je32_to_cpu(dirent.name_crc), name);
if (strcmp(name, oldname)) {
continue;
}
if (fseek(fp, offset + offsetof(struct jffs2_raw_dirent, name_crc), SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek: %d\n", err);
return err;
}
crc32 = bcm4908img_crc32(0, newname, dirent.nsize);
bytes = fwrite(&crc32, 1, sizeof(crc32), fp);
if (bytes != sizeof(crc32)) {
fprintf(stderr, "Failed to write new CRC32\n");
return -EIO;
}
if (fseek(fp, offset + offsetof(struct jffs2_raw_dirent, name), SEEK_SET)) {
err = -errno;
fprintf(stderr, "Failed to fseek: %d\n", err);
return err;
}
bytes = fwrite(newname, 1, dirent.nsize, fp);
if (bytes != dirent.nsize) {
fprintf(stderr, "Failed to write new filename\n");
return -EIO;
}
/* Calculate new BCM4908 image checksum */
err = bcm4908img_calc_crc32(fp, info);
if (err) {
fprintf(stderr, "Failed to write new filename\n");
return err;
}
info->tail.crc32 = cpu_to_le32(info->crc32);
if (fseek(fp, -sizeof(struct bcm4908img_tail), SEEK_END)) {
err = -errno;
fprintf(stderr, "Failed to write new filename\n");
return err;
}
if (fwrite(&info->tail, 1, sizeof(struct bcm4908img_tail), fp) != sizeof(struct bcm4908img_tail)) {
fprintf(stderr, "Failed to write updated tail\n");
return -EIO;
}
printf("Successfully renamed %s to the %s\n", oldname, newname);
return 0;
}
fprintf(stderr, "Failed to find %s\n", oldname);
return -ENOENT;
}
static int bcm4908img_bootfs(int argc, char **argv) {
struct bcm4908img_info info;
const char *pathname = NULL;
const char *mode;
const char *cmd;
FILE *fp;
int c;
int err = 0;
while ((c = getopt(argc, argv, "i:")) != -1) {
switch (c) {
case 'i':
pathname = optarg;
break;
}
}
if (argc - optind < 1) {
fprintf(stderr, "No bootfs command specified\n");
err = -EINVAL;
goto out;
}
cmd = argv[optind++];
mode = strcmp(cmd, "mv") ? "r" : "r+";
fp = bcm4908img_open(pathname, mode);
if (!fp) {
fprintf(stderr, "Failed to open BCM4908 image\n");
err = -EACCES;
goto out;
}
err = bcm4908img_parse(fp, &info);
if (err) {
fprintf(stderr, "Failed to parse BCM4908 image\n");
goto err_close;
}
if (!strcmp(cmd, "ls")) {
err = bcm4908img_bootfs_ls(fp, &info);
} else if (!strcmp(cmd, "mv")) {
err = bcm4908img_bootfs_mv(fp, &info, argc, argv);
} else {
err = -EINVAL;
fprintf(stderr, "Unsupported bootfs command: %s\n", cmd);
}
err_close:
bcm4908img_close(fp);
out:
return err;
}
/**************************************************
* Start
**************************************************/
static void usage() {
printf("Usage:\n");
printf("\n");
printf("Info about a BCM4908 image:\n");
printf("\tbcm4908img info <options>\n");
printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
printf("\n");
printf("Creating a new BCM4908 image:\n");
printf("\tbcm4908img create <file> [options]\n");
printf("\t-f file\t\t\t\tadd data from specified file\n");
printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
printf("\n");
printf("Extracting from a BCM4908 image:\n");
printf("\tbcm4908img extract <options>\n");
printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
printf("\t-t <type>\t\t\t\tone of: cferom, bootfs, rootfs, firmware\n");
printf("\n");
printf("Access bootfs in a BCM4908 image:\n");
printf("\tbcm4908img bootfs <options> <command> <arguments>\n");
printf("\t-i <file>\t\t\t\tinput BCM490 image\n");
printf("\tls\t\t\t\t\tlist bootfs files\n");
printf("\tmv <source> <dest>\t\t\trename bootfs file\n");
}
int main(int argc, char **argv) {
if (argc > 1) {
optind++;
if (!strcmp(argv[1], "info"))
return bcm4908img_info(argc, argv);
else if (!strcmp(argv[1], "create"))
return bcm4908img_create(argc, argv);
else if (!strcmp(argv[1], "extract"))
return bcm4908img_extract(argc, argv);
else if (!strcmp(argv[1], "bootfs"))
return bcm4908img_bootfs(argc, argv);
}
usage();
return 0;
}

View File

@ -1,18 +1,18 @@
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myl
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
@@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
ofpart-y += ofpart_core.o
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
+obj-$(CONFIG_MTD_PARSER_CYBERTAN) += parser_cybertan.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -92,6 +92,14 @@ config MTD_OF_PARTS_BCM4908
that can have multiple "firmware" partitions. It takes care of
finding currently used one and backup ones.
@@ -102,6 +102,14 @@ config MTD_OF_PARTS_LINKSYS_NS
two "firmware" partitions. Currently used firmware has to be detected
using CFE environment variable.
+config MTD_PARSER_CYBERTAN
+ tristate "Parser for Cybertan format partitions"

View File

@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
ARCH:=aarch64
BOARD:=bcm4908
BOARDNAME:=Broadcom BCM4908 (ARMv8A CPUs Brahma-B53)
FEATURES:=squashfs nand usb pci pcie gpio source-only
FEATURES:=squashfs nand usb pci pcie gpio
CPU_TYPE:=cortex-a53
SUBTARGETS:=generic
@ -20,6 +20,8 @@ include $(INCLUDE_DIR)/target.mk
KERNELNAME:=Image dtbs
DEFAULT_PACKAGES += kmod-usb-ohci kmod-usb2 kmod-usb3
DEFAULT_PACKAGES += \
bcm4908img \
kmod-usb-ohci kmod-usb2 kmod-usb3
$(eval $(call BuildTarget))

View File

@ -0,0 +1,213 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
RAMFS_COPY_BIN="bcm4908img"
PART_NAME=firmware
# $(1): file to read from
# $(2): offset in bytes
# $(3): length in bytes
get_content() {
dd if="$1" skip=$2 bs=1 count=$3 2>/dev/null
}
# $(1): file to read from
# $(2): offset in bytes
get_hex_u32_be() {
dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -e '1/1 "%02x"'
}
platform_expected_image() {
local machine=$(board_name)
case "$machine" in
asus,gt-ac5300) echo "asus GT-AC5300";;
netgear,r8000p) echo "chk U12H359T00_NETGEAR";;
tplink,archer-c2300-v1) echo "";;
esac
}
platform_identify() {
local magic
local size
magic=$(get_hex_u32_be "$1" 0)
case "$magic" in
2a23245e)
echo "chk"
return
;;
esac
size=$(wc -c "$1" | cut -d ' ' -f 1)
magic=$(get_content "$1" $((size - 20 - 64 + 8)) 12)
case "$magic" in
GT-AC5300)
echo "asus"
return
;;
esac
echo "unknown"
}
platform_check_image() {
[ "$#" -gt 1 ] && return 1
local expected_image=$(platform_expected_image)
local error=0
bcm4908img info -i "$1" > /dev/null || {
echo "Failed to validate BCM4908 image" >&2
notify_firmware_broken
return 1
}
bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" || {
# OpenWrt images have 1-openwrt dummy file in the bootfs.
# Don't allow backup if it's missing
notify_firmware_no_backup
}
case "$(platform_identify "$1")" in
asus)
local size=$(wc -c "$1" | cut -d ' ' -f 1)
local productid=$(get_content "$1" $((size - 20 - 64 + 8)) 12)
[ -n "$expected_image" -a "asus $productid" != "$expected_image" ] && {
echo "Firmware productid mismatch ($productid)" >&2
error=1
}
;;
chk)
local header_len=$((0x$(get_hex_u32_be "$1" 4)))
local board_id_len=$(($header_len - 40))
local board_id=$(dd if="$1" skip=40 bs=1 count=$board_id_len 2>/dev/null | hexdump -v -e '1/1 "%c"')
[ -n "$expected_image" -a "chk $board_id" != "$expected_image" ] && {
echo "Firmware board_id mismatch ($board_id)" >&2
error=1
}
;;
*)
echo "Invalid image type. Please use firmware specific for this device." >&2
notify_firmware_broken
error=1
;;
esac
return $error
}
# $1: cferam index increment value
platform_calc_new_cferam() {
local inc="$1"
local dir="/tmp/sysupgrade-bcm4908"
local mtd=$(find_mtd_part bootfs)
[ -z "$mtd" ] && {
echo "Failed to find bootfs partition" >&2
return
}
rm -fR $dir
mkdir -p $dir
mount -t jffs2 -o ro $mtd $dir || {
echo "Failed to mount bootfs partition $mtd" >&2
rm -fr $dir
return
}
local idx=$(ls $dir/cferam.??? | sed -n 's/.*cferam\.\(\d\d\d\)/\1/p')
[ -z "$idx" ] && {
echo "Failed to find cferam current index" >&2
rm -fr $dir
return
}
umount $dir
rm -fr $dir
idx=$(((idx + inc) % 1000))
echo $(printf "cferam.%03d" $idx)
}
platform_do_upgrade_ubi() {
local dir="/tmp/sysupgrade-bcm4908"
local inc=1
# Verify new bootfs size
local mtd_bootfs_size=$(grep "\"bootfs\"" /proc/mtd | sed "s/mtd[0-9]*:[ \t]*\([^ \t]*\).*/\1/")
[ -z "$mtd_bootfs_size" ] && {
echo "Unable to find \"bootfs\" partition size"
return
}
mtd_bootfs_size=$((0x$mtd_bootfs_size))
local img_bootfs_size=$(bcm4908img extract -i "$1" -t bootfs | wc -c)
[ $img_bootfs_size -gt $mtd_bootfs_size ] && {
echo "New bootfs doesn't fit MTD partition."
return
}
# Find cferam name for new firmware
# For UBI we always flash "firmware" so don't increase cferam index if
# there is "fallback". That could result in cferam.999 & cferam.001
[ -n "$(find_mtd_index backup)" -o -n "$(find_mtd_index fallback)" ] && inc=0
local cferam=$(platform_calc_new_cferam $inc)
[ -z "$cferam" ] && exit 1
# Prepare new firmware
bcm4908img bootfs -i "$1" mv cferam.000 $cferam || {
echo "Failed to rename cferam.000 to $cferam" >&2
exit 1
}
# Extract rootfs for further flashing
rm -fr $dir
mkdir -p $dir
bcm4908img extract -i "$1" -t rootfs > $dir/root || {
echo "Failed to extract rootfs" >&2
rm -fr $dir
exit 1
}
# Flash bootfs MTD partition with new one
mtd erase bootfs || {
echo "Failed to erase bootfs" >&2
rm -fr $dir
exit 1
}
bcm4908img extract -i "$1" -t bootfs | mtd write - bootfs || {
echo "Failed to flash bootfs" >&2
rm -fr $dir
exit 1
}
nand_do_upgrade $dir/root
}
platform_do_upgrade() {
# Try NAND aware UBI upgrade for OpenWrt images
# Below call will exit on success
bcm4908img bootfs -i "$1" ls | grep -q "1-openwrt" && platform_do_upgrade_ubi "$1"
echo "Writing whole image to NAND flash. All erase counters will be lost."
# Find cferam name for new firmware
local cferam=$(platform_calc_new_cferam 1)
[ -z "$cferam" ] && exit 1
# Prepare new firmware
bcm4908img bootfs -i "$1" mv cferam.000 $cferam || {
echo "Failed to rename cferam.000 to $cferam" >&2
exit 1
}
# Jush flash firmware partition as is
[ -n "$(find_mtd_index backup)" ] && PART_NAME=backup
[ -n "$(find_mtd_index fallback)" ] && PART_NAME=fallback
mtd erase $PART_NAME
default_do_upgrade "$1" "bcm4908img extract -t firmware"
}

View File

@ -121,7 +121,6 @@ CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
# CONFIG_JFFS2_FS is not set
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
@ -139,6 +138,7 @@ CONFIG_MTD_NAND_BRCMNAND=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC_SW_HAMMING=y
CONFIG_MTD_OF_PARTS_BCM4908=y
# CONFIG_MTD_OF_PARTS_LINKSYS_NS is not set
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPLIT_CFE_BOOTFS=y
# CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set

View File

@ -4,6 +4,7 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
DEVICE_VARS += ASUS_PRODUCTID ASUS_BUILD_NO ASUS_FW_REV ASUS_EXT_NO
DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_REGION
define Build/bcm4908asus
$(STAGING_DIR_HOST)/bin/bcm4908asus create -i $@ \
@ -15,12 +16,12 @@ define Build/bcm4908img
rm -fr $@-bootfs
mkdir -p $@-bootfs
cp -r $(DEVICE_NAME)/* $@-bootfs/
touch $@-bootfs/1-dummy
touch $@-bootfs/1-openwrt
cp $(DTS_DIR)/$(firstword $(DEVICE_DTS)).dtb $@-bootfs/94908.dtb
cp $(KDIR)/bcm63xx-cfe/$(subst _,$(comma),$(DEVICE_NAME))/cferam.000 $@-bootfs/
cp $(IMAGE_KERNEL) $@-bootfs/vmlinux.lz
$(STAGING_DIR_HOST)/bin/mkfs.jffs2 --pad --little-endian --squash-uids \
$(STAGING_DIR_HOST)/bin/mkfs.jffs2 --pad=0x800000 --little-endian --squash-uids \
-v -e 128KiB -o $@-bootfs.jffs2 -d $@-bootfs -m none -n
$(STAGING_DIR_HOST)/bin/bcm4908img create $@.new -f $@-bootfs.jffs2 \
-a 0x20000 -f $@
@ -47,6 +48,7 @@ define Device/Default
IMAGE_NAME = $$(IMAGE_PREFIX)-$$(1).$$(2)
BLOCKSIZE := 128k
PAGESIZE := 2048
IMAGE/bin := append-ubi | bcm4908img
endef
define Device/asus_gt-ac5300
@ -67,7 +69,9 @@ define Device/netgear_r8000p
DEVICE_MODEL := R8000P
DEVICE_DTS := broadcom/bcm4908/bcm4906-netgear-r8000p
IMAGES := bin
IMAGE/bin := append-ubi | bcm4908img
IMAGE/chk := append-ubi | bcm4908img | netgear-chk
NETGEAR_BOARD_ID := U12H359T00_NETGEAR
NETGEAR_REGION := 1
endef
TARGET_DEVICES += netgear_r8000p
@ -78,6 +82,7 @@ define Device/tplink_archer-c2300-v1
DEVICE_DTS := broadcom/bcm4908/bcm4906-tplink-archer-c2300-v1
IMAGES := bin
IMAGE/bin := append-ubi | bcm4908img
BROKEN := y
endef
TARGET_DEVICES += tplink_archer-c2300-v1

View File

@ -0,0 +1,30 @@
From 5337af7918bedde9713cd223ce5df74b3d6c7d7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 17 Mar 2021 09:16:31 +0100
Subject: [PATCH] arm64: dts: broadcom: bcm4908: add Ethernet TX irq
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This hardware supports two interrupts, one per DMA channel (RX and TX).
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
@@ -116,8 +116,9 @@
compatible = "brcm,bcm4908-enet";
reg = <0x2000 0x1000>;
- interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "rx";
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "rx", "tx";
};
usb_phy: usb-phy@c200 {

View File

@ -0,0 +1,82 @@
From 9f01f5cdb548352418b34ce77db02a560fe2913b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Mon, 29 Mar 2021 17:45:14 +0200
Subject: [PATCH] arm64: dts: broadcom: bcm4908: add Ethernet MAC addr
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On most BCM4908 devices MAC address can be read from the bootloader
binary section containing device settings. Use NVMEM to describe that.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
.../broadcom/bcm4908/bcm4906-netgear-r8000p.dts | 14 ++++++++++++++
.../broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts | 14 ++++++++++++++
2 files changed, 28 insertions(+)
--- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4906-netgear-r8000p.dts
@@ -74,6 +74,11 @@
};
};
+&enet {
+ nvmem-cells = <&base_mac_addr>;
+ nvmem-cell-names = "mac-address";
+};
+
&usb_phy {
brcm,ioc = <1>;
status = "okay";
@@ -130,8 +135,17 @@
#size-cells = <1>;
partition@0 {
+ compatible = "nvmem-cells";
label = "cferom";
reg = <0x0 0x100000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x100000>;
+
+ base_mac_addr: mac@106a0 {
+ reg = <0x106a0 0x6>;
+ };
};
partition@100000 {
--- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908-asus-gt-ac5300.dts
@@ -44,6 +44,11 @@
};
};
+&enet {
+ nvmem-cells = <&base_mac_addr>;
+ nvmem-cell-names = "mac-address";
+};
+
&usb_phy {
brcm,ioc = <1>;
status = "okay";
@@ -128,8 +133,17 @@
#size-cells = <1>;
partition@0 {
+ compatible = "nvmem-cells";
label = "cferom";
reg = <0x0 0x100000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x100000>;
+
+ base_mac_addr: mac@106a0 {
+ reg = <0x106a0 0x6>;
+ };
};
partition@100000 {

View File

@ -0,0 +1,25 @@
From f4e6d7cdbfae502788bc468295b232dec76ee57e Mon Sep 17 00:00:00 2001
From: Florian Fainelli <f.fainelli@gmail.com>
Date: Fri, 12 Mar 2021 13:11:01 -0800
Subject: [PATCH] net: dsa: bcm_sf2: Fill in BCM4908 CFP entries
The BCM4908 switch has 256 CFP entrie, update that setting so CFP can be
used.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/bcm_sf2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1058,7 +1058,7 @@ static const struct bcm_sf2_of_data bcm_
.type = BCM4908_DEVICE_ID,
.core_reg_align = 0,
.reg_offsets = bcm_sf2_4908_reg_offsets,
- .num_cfp_rules = 0, /* FIXME */
+ .num_cfp_rules = 256,
.num_crossbar_int_ports = 2,
};

View File

@ -0,0 +1,127 @@
From 55cfeb396965c3906a84d09a9c487d065e37773b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Thu, 18 Mar 2021 09:01:42 +0100
Subject: [PATCH 1/2] net: dsa: bcm_sf2: add function finding RGMII register
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Simple macro like REG_RGMII_CNTRL_P() is insufficient as:
1. It doesn't validate port argument
2. It doesn't support chipsets with non-lineral RGMII regs layout
Missing port validation could result in getting register offset from out
of array. Random memory -> random offset -> random reads/writes. It
affected e.g. BCM4908 for REG_RGMII_CNTRL_P(7).
Fixes: a78e86ed586d ("net: dsa: bcm_sf2: Prepare for different register layouts")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/bcm_sf2.c | 49 +++++++++++++++++++++++++++++-----
drivers/net/dsa/bcm_sf2_regs.h | 2 --
2 files changed, 42 insertions(+), 9 deletions(-)
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -31,6 +31,31 @@
#include "b53/b53_priv.h"
#include "b53/b53_regs.h"
+static u16 bcm_sf2_reg_rgmii_cntrl(struct bcm_sf2_priv *priv, int port)
+{
+ switch (priv->type) {
+ case BCM4908_DEVICE_ID:
+ /* TODO */
+ break;
+ default:
+ switch (port) {
+ case 0:
+ return REG_RGMII_0_CNTRL;
+ case 1:
+ return REG_RGMII_1_CNTRL;
+ case 2:
+ return REG_RGMII_2_CNTRL;
+ default:
+ break;
+ }
+ }
+
+ WARN_ONCE(1, "Unsupported port %d\n", port);
+
+ /* RO fallback reg */
+ return REG_SWITCH_STATUS;
+}
+
static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
@@ -586,6 +611,7 @@ static void bcm_sf2_sw_mac_config(struct
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
u32 id_mode_dis = 0, port_mode;
+ u32 reg_rgmii_ctrl;
u32 reg, offset;
if (port == core_readl(priv, CORE_IMP0_PRT_ID))
@@ -615,10 +641,12 @@ static void bcm_sf2_sw_mac_config(struct
goto force_link;
}
+ reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
+
/* Clear id_mode_dis bit, and the existing port mode, let
* RGMII_MODE_EN bet set by mac_link_{up,down}
*/
- reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+ reg = reg_readl(priv, reg_rgmii_ctrl);
reg &= ~ID_MODE_DIS;
reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
@@ -633,7 +661,7 @@ static void bcm_sf2_sw_mac_config(struct
reg |= RX_PAUSE_EN;
}
- reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+ reg_writel(priv, reg, reg_rgmii_ctrl);
force_link:
/* Force link settings detected from the PHY */
@@ -659,6 +687,7 @@ static void bcm_sf2_sw_mac_link_set(stru
phy_interface_t interface, bool link)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+ u32 reg_rgmii_ctrl;
u32 reg;
if (!phy_interface_mode_is_rgmii(interface) &&
@@ -666,13 +695,15 @@ static void bcm_sf2_sw_mac_link_set(stru
interface != PHY_INTERFACE_MODE_REVMII)
return;
+ reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);
+
/* If the link is down, just disable the interface to conserve power */
- reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+ reg = reg_readl(priv, reg_rgmii_ctrl);
if (link)
reg |= RGMII_MODE_EN;
else
reg &= ~RGMII_MODE_EN;
- reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+ reg_writel(priv, reg, reg_rgmii_ctrl);
}
static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port,
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -55,8 +55,6 @@ enum bcm_sf2_reg_offs {
#define CROSSBAR_BCM4908_EXT_GPHY4 1
#define CROSSBAR_BCM4908_EXT_RGMII 2
-#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_CNTRL + (x))
-
/* Relative to REG_RGMII_CNTRL */
#define RGMII_MODE_EN (1 << 0)
#define ID_MODE_DIS (1 << 1)

View File

@ -0,0 +1,56 @@
From 6859d91549341c2ad769d482de58129f080c0f04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Thu, 18 Mar 2021 09:01:43 +0100
Subject: [PATCH 2/2] net: dsa: bcm_sf2: fix BCM4908 RGMII reg(s)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
BCM4908 has only 1 RGMII reg for controlling port 7.
Fixes: 73b7a6047971 ("net: dsa: bcm_sf2: support BCM4908's integrated switch")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/dsa/bcm_sf2.c | 11 +++++++----
drivers/net/dsa/bcm_sf2_regs.h | 1 +
2 files changed, 8 insertions(+), 4 deletions(-)
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -35,7 +35,12 @@ static u16 bcm_sf2_reg_rgmii_cntrl(struc
{
switch (priv->type) {
case BCM4908_DEVICE_ID:
- /* TODO */
+ switch (port) {
+ case 7:
+ return REG_RGMII_11_CNTRL;
+ default:
+ break;
+ }
break;
default:
switch (port) {
@@ -1077,9 +1082,7 @@ static const u16 bcm_sf2_4908_reg_offset
[REG_PHY_REVISION] = 0x14,
[REG_SPHY_CNTRL] = 0x24,
[REG_CROSSBAR] = 0xc8,
- [REG_RGMII_0_CNTRL] = 0xe0,
- [REG_RGMII_1_CNTRL] = 0xec,
- [REG_RGMII_2_CNTRL] = 0xf8,
+ [REG_RGMII_11_CNTRL] = 0x014c,
[REG_LED_0_CNTRL] = 0x40,
[REG_LED_1_CNTRL] = 0x4c,
[REG_LED_2_CNTRL] = 0x58,
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -21,6 +21,7 @@ enum bcm_sf2_reg_offs {
REG_RGMII_0_CNTRL,
REG_RGMII_1_CNTRL,
REG_RGMII_2_CNTRL,
+ REG_RGMII_11_CNTRL,
REG_LED_0_CNTRL,
REG_LED_1_CNTRL,
REG_LED_2_CNTRL,

View File

@ -12,7 +12,7 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
--- a/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
@@ -280,7 +280,7 @@
@@ -281,7 +281,7 @@
gpio0: gpio-controller@500 {
compatible = "brcm,bcm6345-gpio";
reg-names = "dirout", "dat";

View File

@ -29,7 +29,7 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1285,10 +1285,14 @@ static int bcm_sf2_sw_probe(struct platf
@@ -1319,10 +1319,14 @@ static int bcm_sf2_sw_probe(struct platf
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;

View File

@ -15,7 +15,7 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1299,6 +1299,12 @@ static int bcm_sf2_sw_probe(struct platf
@@ -1333,6 +1333,12 @@ static int bcm_sf2_sw_probe(struct platf
priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
priv->irq0, priv->irq1);

View File

@ -1,109 +0,0 @@
From 7e2dc41c745f6d9c571919d98abed2d783fce8fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Sun, 14 Mar 2021 22:43:32 +0100
Subject: [PATCH] net: dsa: bcm_sf2: quick fix for RGMII reg access on BCM4908
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
BCM4908 has only 1 RGMII register and it's used for port 7.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
drivers/net/dsa/bcm_sf2.c | 30 +++++++++++++++++++++++-------
drivers/net/dsa/bcm_sf2_regs.h | 1 +
2 files changed, 24 insertions(+), 7 deletions(-)
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -587,10 +587,19 @@ static void bcm_sf2_sw_mac_config(struct
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
u32 id_mode_dis = 0, port_mode;
u32 reg, offset;
+ u32 rgmii_ctrl;
if (port == core_readl(priv, CORE_IMP0_PRT_ID))
return;
+ if (priv->type == BCM4908_DEVICE_ID) {
+ if (port != 7)
+ return;
+ rgmii_ctrl = REG_RGMII_11_CNTRL;
+ } else {
+ rgmii_ctrl = REG_RGMII_CNTRL_P(port);
+ }
+
if (priv->type == BCM4908_DEVICE_ID ||
priv->type == BCM7445_DEVICE_ID)
offset = CORE_STS_OVERRIDE_GMIIP_PORT(port);
@@ -618,7 +627,7 @@ static void bcm_sf2_sw_mac_config(struct
/* Clear id_mode_dis bit, and the existing port mode, let
* RGMII_MODE_EN bet set by mac_link_{up,down}
*/
- reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+ reg = reg_readl(priv, rgmii_ctrl);
reg &= ~ID_MODE_DIS;
reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
@@ -633,7 +642,7 @@ static void bcm_sf2_sw_mac_config(struct
reg |= RX_PAUSE_EN;
}
- reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+ reg_writel(priv, reg, rgmii_ctrl);
force_link:
/* Force link settings detected from the PHY */
@@ -659,6 +668,7 @@ static void bcm_sf2_sw_mac_link_set(stru
phy_interface_t interface, bool link)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+ u32 rgmii_ctrl;
u32 reg;
if (!phy_interface_mode_is_rgmii(interface) &&
@@ -666,13 +676,21 @@ static void bcm_sf2_sw_mac_link_set(stru
interface != PHY_INTERFACE_MODE_REVMII)
return;
+ if (priv->type == BCM4908_DEVICE_ID) {
+ if (port != 7)
+ return;
+ rgmii_ctrl = REG_RGMII_11_CNTRL;
+ } else {
+ rgmii_ctrl = REG_RGMII_CNTRL_P(port);
+ }
+
/* If the link is down, just disable the interface to conserve power */
- reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+ reg = reg_readl(priv, rgmii_ctrl);
if (link)
reg |= RGMII_MODE_EN;
else
reg &= ~RGMII_MODE_EN;
- reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+ reg_writel(priv, reg, rgmii_ctrl);
}
static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port,
@@ -1046,9 +1064,7 @@ static const u16 bcm_sf2_4908_reg_offset
[REG_PHY_REVISION] = 0x14,
[REG_SPHY_CNTRL] = 0x24,
[REG_CROSSBAR] = 0xc8,
- [REG_RGMII_0_CNTRL] = 0xe0,
- [REG_RGMII_1_CNTRL] = 0xec,
- [REG_RGMII_2_CNTRL] = 0xf8,
+ [REG_RGMII_11_CNTRL] = 0x014c,
[REG_LED_0_CNTRL] = 0x40,
[REG_LED_1_CNTRL] = 0x4c,
[REG_LED_2_CNTRL] = 0x58,
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -21,6 +21,7 @@ enum bcm_sf2_reg_offs {
REG_RGMII_0_CNTRL,
REG_RGMII_1_CNTRL,
REG_RGMII_2_CNTRL,
+ REG_RGMII_11_CNTRL,
REG_LED_0_CNTRL,
REG_LED_1_CNTRL,
REG_LED_2_CNTRL,

View File

@ -31,6 +31,10 @@ bcm53xx_setup_interfaces()
ucidef_add_switch "switch0" \
"0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "5t@eth0"
;;
linksys,panamera)
ucidef_add_switch "switch1" \
"0:lan" "1:lan:7" "2:lan:4" "3:lan:8" "4:wan" "5t@eth0"
;;
luxul,abr-4500-v1|\
luxul,xbr-4500-v1)
ucidef_add_switch "switch0" \
@ -84,6 +88,7 @@ bcm53xx_setup_macs()
case "$board" in
dlink,dir-885l | \
linksys,panamera | \
netgear,r7900 | \
netgear,r8000 | \
netgear,r8500)
@ -105,6 +110,7 @@ bcm53xx_setup_macs()
offset=1
;;
dlink,dir-885l | \
linksys,panamera | \
netgear,r7900 | \
netgear,r8000 | \
netgear,r8500)

View File

@ -0,0 +1,13 @@
#!/bin/sh /etc/rc.common
START=97
boot() {
. /lib/functions.sh
case $(board_name) in
linksys,panamera)
# clear partialboots
nvram set partialboots=0 && nvram commit
;;
esac
}

View File

@ -258,6 +258,7 @@ CONFIG_MTD_BCM47XX_PARTS=y
CONFIG_MTD_NAND_BRCMNAND=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC_SW_HAMMING=y
CONFIG_MTD_OF_PARTS_LINKSYS_NS=y
CONFIG_MTD_PARSER_TRX=y
CONFIG_MTD_RAW_NAND=y
CONFIG_MTD_SPI_NOR=y

View File

@ -274,7 +274,6 @@ define Device/linksys_ea9500
DEVICE_MODEL := EA9500
DEVICE_PACKAGES := $(BRCMFMAC_4366C0) $(USB3_PACKAGES)
DEVICE_DTS := bcm47094-linksys-panamera
BROKEN := y
endef
TARGET_DEVICES += linksys_ea9500

View File

@ -0,0 +1,47 @@
From 1ca5f2430c4f9d85b98b8d6e5d93f8d4802faf8e Mon Sep 17 00:00:00 2001
From: Vivek Unune <npcomplete13@gmail.com>
Date: Wed, 14 Oct 2020 15:27:27 -0400
Subject: [PATCH] ARM: dts: BCM5301X: Linksys EA9500 add port 5 and port 7
Add ports 5 and 7 which are connected to gmac cores 1 & 2.
These will be disabled for now.
Signed-off-by: Vivek Unune <npcomplete13@gmail.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
.../boot/dts/bcm47094-linksys-panamera.dts | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -242,6 +242,30 @@
label = "wan";
};
+ port@5 {
+ reg = <5>;
+ ethernet = <&gmac0>;
+ label = "cpu";
+ status = "disabled";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
+ port@7 {
+ reg = <7>;
+ ethernet = <&gmac1>;
+ label = "cpu";
+ status = "disabled";
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+
port@8 {
reg = <8>;
ethernet = <&gmac2>;

View File

@ -0,0 +1,71 @@
From bd9a01e28e5d1632528e531480b42d6e2c861d88 Mon Sep 17 00:00:00 2001
From: Vivek Unune <npcomplete13@gmail.com>
Date: Sun, 1 Nov 2020 15:08:03 -0500
Subject: [PATCH] ARM: dts: BCM5301X: Linksys EA9500 add fixed partitions
This router has dual paritions to store trx firmware image and
dual partitions for nvram. The second one in each of these cases acts
as a backup store.
When tested with OpenWrt, the default partition parser causes two issues:
1. It labels both nvram partitions as nvram. In factory, second one is
labeled devinfo.
2. It parses second trx image and tries to create second 'linux' partition
and fails with - cannot create duplicate 'linux' partition
The following patch works around both of these issues.
Signed-off-by: Vivek Unune <npcomplete13@gmail.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
.../boot/dts/bcm47094-linksys-panamera.dts | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -292,3 +292,44 @@
&usb3_phy {
status = "okay";
};
+
+&nandcs {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "boot";
+ reg = <0x0000000 0x0080000>;
+ read-only;
+ };
+
+ partition@80000 {
+ label = "nvram";
+ reg = <0x080000 0x0100000>;
+ };
+
+ partition@180000{
+ label = "devinfo";
+ reg = <0x0180000 0x080000>;
+ };
+
+ partition@200000 {
+ label = "firmware";
+ reg = <0x0200000 0x01D00000>;
+ compatible = "brcm,trx";
+ };
+
+ partition@1F00000 {
+ label = "failsafe";
+ reg = <0x01F00000 0x01D00000>;
+ read-only;
+ };
+
+ partition@5200000 {
+ label = "system";
+ reg = <0x05200000 0x02E00000>;
+ };
+ };
+};

View File

@ -0,0 +1,49 @@
From 2f34ae32f5e74096540cd7ce95bfd467cb74b21a Mon Sep 17 00:00:00 2001
From: Vivek Unune <npcomplete13@gmail.com>
Date: Wed, 4 Nov 2020 15:29:51 -0500
Subject: [PATCH] ARM: dts: BCM5301X: Use corretc pinctrl compatible for 4709x
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
BCM47094 version of pinmux uses different compatible and supports MDIO
pinmux pins. Hence, use the correct compatible string and defines the
MDIO pins group.
Signed-off-by: Vivek Unune <npcomplete13@gmail.com>
Acked-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm/boot/dts/bcm47094.dtsi | 9 +++++++++
arch/arm/boot/dts/bcm5301x.dtsi | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/dts/bcm47094.dtsi
+++ b/arch/arm/boot/dts/bcm47094.dtsi
@@ -8,6 +8,15 @@
/ {
};
+&pinctrl {
+ compatible = "brcm,bcm4709-pinmux";
+
+ pinmux_mdio: mdio {
+ groups = "mdio_grp";
+ function = "mdio";
+ };
+};
+
&usb3_phy {
compatible = "brcm,ns-bx-usb3-phy";
};
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -428,7 +428,7 @@
#address-cells = <1>;
#size-cells = <1>;
- pin-controller@1c0 {
+ pinctrl: pin-controller@1c0 {
compatible = "brcm,bcm4708-pinmux";
reg = <0x1c0 0x24>;
reg-names = "cru_gpio_control";

View File

@ -0,0 +1,61 @@
From c862059875cffc013ee27bf9759ac288224e7a14 Mon Sep 17 00:00:00 2001
From: Vivek Unune <npcomplete13@gmail.com>
Date: Wed, 4 Nov 2020 15:29:52 -0500
Subject: [PATCH] ARM: dts: BCM5301X: Linksys EA9500 make use of pinctrl
Now that we have a pin controller, use that instead of manuplating the
mdio/mdc pins directly. i.e. we no longer require the mdio-mii-mux
Signed-off-by: Vivek Unune <npcomplete13@gmail.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
.../boot/dts/bcm47094-linksys-panamera.dts | 26 +++----------------
1 file changed, 4 insertions(+), 22 deletions(-)
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -123,33 +123,13 @@
};
};
- mdio-bus-mux {
- #address-cells = <1>;
- #size-cells = <0>;
+ mdio-bus-mux@18003000 {
/* BIT(9) = 1 => external mdio */
- mdio_ext: mdio@200 {
+ mdio@200 {
reg = <0x200>;
#address-cells = <1>;
#size-cells = <0>;
- };
- };
-
- mdio-mii-mux {
- compatible = "mdio-mux-mmioreg";
- mdio-parent-bus = <&mdio_ext>;
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x1800c1c0 0x4>;
-
- /* BIT(6) = mdc, BIT(7) = mdio */
- mux-mask = <0xc0>;
-
- mdio-mii@0 {
- /* Enable MII function */
- reg = <0x0>;
- #address-cells = <1>;
- #size-cells = <0>;
switch@0 {
compatible = "brcm,bcm53125";
@@ -159,6 +139,8 @@
reset-names = "robo_reset";
reg = <0>;
dsa,member = <1 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinmux_mdio>;
ports {
#address-cells = <1>;

View File

@ -0,0 +1,60 @@
From 1d3352aeed164ef73f05cf80ca001f11d2f3312d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Mon, 29 Mar 2021 07:54:30 +0200
Subject: [PATCH] ARM: dts: BCM5301X: Fix Linksys EA9500 partitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Partitions are basically fixed indeed but firmware ones don't have
hardcoded function ("firmware" vs "failsafe"). Actual function depends
on bootloader configuration. Use a proper binding for that.
While at it fix numbers formatting to avoid:
arch/arm/boot/dts/bcm47094-linksys-panamera.dt.yaml: partitions: 'partition@1F00000' does not match any of the regexes: '^partition@[0-9a-f]+$', 'pinctrl-[0-9]+'
From schema: Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm/boot/dts/bcm47094-linksys-panamera.dts | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -279,7 +279,7 @@
&nandcs {
partitions {
- compatible = "fixed-partitions";
+ compatible = "linksys,ns-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -300,20 +300,18 @@
};
partition@200000 {
- label = "firmware";
- reg = <0x0200000 0x01D00000>;
- compatible = "brcm,trx";
+ reg = <0x0200000 0x01d00000>;
+ compatible = "linksys,ns-firmware", "brcm,trx";
};
- partition@1F00000 {
- label = "failsafe";
- reg = <0x01F00000 0x01D00000>;
- read-only;
+ partition@1f00000 {
+ reg = <0x01f00000 0x01d00000>;
+ compatible = "linksys,ns-firmware", "brcm,trx";
};
partition@5200000 {
label = "system";
- reg = <0x05200000 0x02E00000>;
+ reg = <0x05200000 0x02e00000>;
};
};
};

View File

@ -0,0 +1,27 @@
From dcb56d61d5a8acca0a357cc603397bc0272ce4cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Mon, 29 Mar 2021 10:04:09 +0200
Subject: [PATCH] ARM: dts: BCM5301X: Set Linksys EA9500 power LED
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Set Linux default trigger to default on, just like it's normally done
for power LEDs.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
arch/arm/boot/dts/bcm47094-linksys-panamera.dts | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
+++ b/arch/arm/boot/dts/bcm47094-linksys-panamera.dts
@@ -75,6 +75,7 @@
power {
label = "bcm53xx:white:power";
gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
};
wifi-disabled {

View File

@ -20,8 +20,8 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
- #address-cells = <1>;
- #size-cells = <1>;
- pin-controller@1c0 {
+ pinctrl {
- pinctrl: pin-controller@1c0 {
+ pinctrl: pinctrl {
compatible = "brcm,bcm4708-pinmux";
- reg = <0x1c0 0x24>;
- reg-names = "cru_gpio_control";

View File

@ -21,7 +21,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
#include "b53_regs.h"
#include "b53_priv.h"
@@ -1587,6 +1588,28 @@ static int b53_switch_init(struct b53_de
@@ -1587,6 +1588,29 @@ static int b53_switch_init(struct b53_de
return ret;
}
@ -44,7 +44,8 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+ * For some reason it doesn't work (no packets on eth2).
+ */
+ if (of_machine_is_compatible("netgear,r7900") ||
+ of_machine_is_compatible("netgear,r8000"))
+ of_machine_is_compatible("netgear,r8000") ||
+ (of_machine_is_compatible("linksys,panamera") && dev->chip_id == BCM53012_DEVICE_ID))
+ sw_dev->cpu_port = 5;
+
dev->enabled_ports |= BIT(sw_dev->cpu_port);

View File

@ -0,0 +1,34 @@
From b87b6d2d6f540e29c3f98e1572d64e560d73d6c1 Mon Sep 17 00:00:00 2001
From: Wei Yongjun <weiyongjun1@huawei.com>
Date: Thu, 4 Mar 2021 06:46:00 +0000
Subject: [PATCH] mtd: parsers: ofpart: make symbol 'bcm4908_partitions_quirks'
static
The sparse tool complains as follows:
drivers/mtd/parsers/ofpart_core.c:25:32: warning:
symbol 'bcm4908_partitions_quirks' was not declared. Should it be static?
This symbol is not used outside of ofpart_core.c, so this
commit marks it static.
Fixes: 457da931b608 ("mtd: parsers: ofpart: support BCM4908 fixed partitions")
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210304064600.3279138-1-weiyongjun1@huawei.com
---
drivers/mtd/parsers/ofpart_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -22,7 +22,7 @@ struct fixed_partitions_quirks {
int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
};
-struct fixed_partitions_quirks bcm4908_partitions_quirks = {
+static struct fixed_partitions_quirks bcm4908_partitions_quirks = {
.post_parse = bcm4908_partitions_post_parse,
};

View File

@ -1,4 +1,4 @@
From a5d83d6e2bc747b13f347962d4b335d70b23559b Mon Sep 17 00:00:00 2001
From 658c4448bbbf02a143abf1b89d09a3337ebd3ba6 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Fri, 12 Mar 2021 07:28:19 +0100
Subject: [PATCH] mtd: core: add nvmem-cells compatible to parse mtd as nvmem
@ -13,6 +13,8 @@ nvmem provider.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Tested-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-1-ansuelsmth@gmail.com
---
drivers/mtd/mtdcore.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

View File

@ -1,12 +1,15 @@
From 42645976c3289b03a12f1bd2bc131fd98fc27170 Mon Sep 17 00:00:00 2001
From 52981a0fa9f7d68641e0e6bb584054c6d9eb2056 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Fri, 12 Mar 2021 07:28:20 +0100
Subject: [PATCH] devicetree: nvmem: nvmem: drop $nodename restriction
Subject: [PATCH] dt-bindings: nvmem: drop $nodename restriction
Drop $nodename restriction as now mtd partition can also be used as
nvmem provider.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-2-ansuelsmth@gmail.com
---
Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
1 file changed, 3 deletions(-)

View File

@ -1,4 +1,4 @@
From 377aa0135dc8489312edd3184d143ce3a89ff7ee Mon Sep 17 00:00:00 2001
From ac42c46f983e4a9003a7bb91ad44a23ab7b8f534 Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Fri, 12 Mar 2021 07:28:21 +0100
Subject: [PATCH] dt-bindings: mtd: Document use of nvmem-cells compatible
@ -8,6 +8,8 @@ nvmem provider.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-3-ansuelsmth@gmail.com
---
.../bindings/mtd/partitions/nvmem-cells.yaml | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)

View File

@ -0,0 +1,98 @@
From 2fa7294175c76e1ec568aa75c1891fd908728c8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Fri, 12 Mar 2021 14:49:18 +0100
Subject: [PATCH] dt-bindings: mtd: add binding for Linksys Northstar
partitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Linksys on Broadcom Northstar devices uses fixed flash layout with
multiple firmware partitions.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-1-zajec5@gmail.com
---
.../mtd/partitions/linksys,ns-partitions.yaml | 74 +++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/linksys,ns-partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Linksys Northstar partitioning
+
+description: |
+ Linksys devices based on Broadcom Northstar architecture often use two
+ firmware partitions. One is used for regular booting, the other is treated as
+ fallback.
+
+ This binding allows defining all fixed partitions and marking those containing
+ firmware. System can use that information e.g. for booting or flashing
+ purposes.
+
+maintainers:
+ - Rafał Miłecki <rafal@milecki.pl>
+
+properties:
+ compatible:
+ const: linksys,ns-partitions
+
+ "#address-cells":
+ enum: [ 1, 2 ]
+
+ "#size-cells":
+ enum: [ 1, 2 ]
+
+patternProperties:
+ "^partition@[0-9a-f]+$":
+ $ref: "partition.yaml#"
+ properties:
+ compatible:
+ items:
+ - const: linksys,ns-firmware
+ - const: brcm,trx
+ unevaluatedProperties: false
+
+required:
+ - "#address-cells"
+ - "#size-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ partitions {
+ compatible = "linksys,ns-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "boot";
+ reg = <0x0 0x100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "nvram";
+ reg = <0x100000 0x100000>;
+ };
+
+ partition@200000 {
+ compatible = "linksys,ns-firmware", "brcm,trx";
+ reg = <0x200000 0xf00000>;
+ };
+
+ partition@1100000 {
+ compatible = "linksys,ns-firmware", "brcm,trx";
+ reg = <0x1100000 0xf00000>;
+ };
+ };

View File

@ -0,0 +1,156 @@
From 7134a2d026d942210b4d26d6059c9d979ca7866e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Fri, 12 Mar 2021 14:49:19 +0100
Subject: [PATCH] mtd: parsers: ofpart: support Linksys Northstar partitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This allows extending ofpart parser with support for Linksys Northstar
devices. That support uses recently added quirks mechanism.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-2-zajec5@gmail.com
---
drivers/mtd/parsers/Kconfig | 10 +++++
drivers/mtd/parsers/Makefile | 1 +
drivers/mtd/parsers/ofpart_core.c | 6 +++
drivers/mtd/parsers/ofpart_linksys_ns.c | 50 +++++++++++++++++++++++++
drivers/mtd/parsers/ofpart_linksys_ns.h | 18 +++++++++
5 files changed, 85 insertions(+)
create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.c
create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.h
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -76,6 +76,16 @@ config MTD_OF_PARTS_BCM4908
that can have multiple "firmware" partitions. It takes care of
finding currently used one and backup ones.
+config MTD_OF_PARTS_LINKSYS_NS
+ bool "Linksys Northstar partitioning support"
+ depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCM4908 || COMPILE_TEST)
+ default ARCH_BCM_5301X
+ help
+ This provides partitions parser for Linksys devices based on Broadcom
+ Northstar architecture. Linksys commonly uses fixed flash layout with
+ two "firmware" partitions. Currently used firmware has to be detected
+ using CFE environment variable.
+
config MTD_PARSER_IMAGETAG
tristate "Parser for BCM963XX Image Tag format partitions"
depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdl
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
ofpart-y += ofpart_core.o
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
+ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -17,6 +17,7 @@
#include <linux/mtd/partitions.h>
#include "ofpart_bcm4908.h"
+#include "ofpart_linksys_ns.h"
struct fixed_partitions_quirks {
int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
@@ -26,6 +27,10 @@ static struct fixed_partitions_quirks bc
.post_parse = bcm4908_partitions_post_parse,
};
+static struct fixed_partitions_quirks linksys_ns_partitions_quirks = {
+ .post_parse = linksys_ns_partitions_post_parse,
+};
+
static const struct of_device_id parse_ofpart_match_table[];
static bool node_has_compatible(struct device_node *pp)
@@ -164,6 +169,7 @@ static const struct of_device_id parse_o
{ .compatible = "fixed-partitions" },
/* Customized */
{ .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
+ { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, },
{},
};
MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);
--- /dev/null
+++ b/drivers/mtd/parsers/ofpart_linksys_ns.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/bcm47xx_nvram.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include "ofpart_linksys_ns.h"
+
+#define NVRAM_BOOT_PART "bootpartition"
+
+static int ofpart_linksys_ns_bootpartition(void)
+{
+ char buf[4];
+ int bootpartition;
+
+ /* Check CFE environment variable */
+ if (bcm47xx_nvram_getenv(NVRAM_BOOT_PART, buf, sizeof(buf)) > 0) {
+ if (!kstrtoint(buf, 0, &bootpartition))
+ return bootpartition;
+ pr_warn("Failed to parse %s value \"%s\"\n", NVRAM_BOOT_PART,
+ buf);
+ } else {
+ pr_warn("Failed to get NVRAM \"%s\"\n", NVRAM_BOOT_PART);
+ }
+
+ return 0;
+}
+
+int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts)
+{
+ int bootpartition = ofpart_linksys_ns_bootpartition();
+ int trx_idx = 0;
+ int i;
+
+ for (i = 0; i < nr_parts; i++) {
+ if (of_device_is_compatible(parts[i].of_node, "linksys,ns-firmware")) {
+ if (trx_idx++ == bootpartition)
+ parts[i].name = "firmware";
+ else
+ parts[i].name = "backup";
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/drivers/mtd/parsers/ofpart_linksys_ns.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __OFPART_LINKSYS_NS_H
+#define __OFPART_LINKSYS_NS_H
+
+#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS
+int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts);
+#else
+static inline int linksys_ns_partitions_post_parse(struct mtd_info *mtd,
+ struct mtd_partition *parts,
+ int nr_parts)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#endif

View File

@ -17,7 +17,7 @@
#define je16_to_cpu(x) ((x).v16)
#define je32_to_cpu(x) ((x).v32)
#define NR_PARTS 1
#define NR_PARTS 2
static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd,
const struct mtd_partition **pparts,
@ -58,12 +58,16 @@ static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd,
if (!parts)
return -ENOMEM;
parts[0].name = "bootfs";
parts[0].offset = 0;
parts[0].size = rootfs_offset;
if (type == MTDSPLIT_PART_TYPE_UBI)
parts[0].name = UBI_PART_NAME;
parts[1].name = UBI_PART_NAME;
else
parts[0].name = ROOTFS_PART_NAME;
parts[0].offset = rootfs_offset;
parts[0].size = mtd->size - rootfs_offset;
parts[1].name = ROOTFS_PART_NAME;
parts[1].offset = rootfs_offset;
parts[1].size = mtd->size - rootfs_offset;
*pparts = parts;

View File

@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -185,3 +185,12 @@ config MTD_REDBOOT_PARTS_READONLY
@@ -195,3 +195,12 @@ config MTD_REDBOOT_PARTS_READONLY
'FIS directory' images, enable this option.
endif # MTD_REDBOOT_PARTS
@ -31,7 +31,7 @@ Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
+ formatted DTS.
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
@@ -13,3 +13,4 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o

View File

@ -18,7 +18,7 @@ Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -128,6 +128,13 @@ config MTD_PARSER_TRX
@@ -138,6 +138,13 @@ config MTD_PARSER_TRX
This driver will parse TRX header and report at least two partitions:
kernel and rootfs.
@ -34,7 +34,7 @@ Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) +=
@@ -11,6 +11,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)
obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o

View File

@ -5,7 +5,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
@@ -38,6 +38,8 @@ static bool node_has_compatible(struct d
return of_get_property(pp, "compatible", NULL);
}
@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
static int parse_fixed_partitions(struct mtd_info *master,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@@ -42,6 +44,7 @@ static int parse_fixed_partitions(struct
@@ -47,6 +49,7 @@ static int parse_fixed_partitions(struct
struct mtd_partition *parts;
struct device_node *mtd_node;
struct device_node *ofpart_node;
@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
const char *partname;
struct device_node *pp;
int nr_parts, i, ret = 0;
@@ -126,9 +129,15 @@ static int parse_fixed_partitions(struct
@@ -131,9 +134,15 @@ static int parse_fixed_partitions(struct
parts[i].size = of_read_number(reg + a_cells, s_cells);
parts[i].of_node = pp;
@ -41,7 +41,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
parts[i].name = partname;
if (of_get_property(pp, "read-only", &len))
@@ -241,6 +250,18 @@ static int __init ofpart_parser_init(voi
@@ -247,6 +256,18 @@ static int __init ofpart_parser_init(voi
return 0;
}

View File

@ -1,6 +1,6 @@
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -33,6 +33,38 @@ static bool node_has_compatible(struct d
@@ -38,6 +38,38 @@ static bool node_has_compatible(struct d
return of_get_property(pp, "compatible", NULL);
}
@ -39,7 +39,7 @@
static int parse_fixed_partitions(struct mtd_info *master,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@@ -46,6 +78,8 @@ static int parse_fixed_partitions(struct
@@ -51,6 +83,8 @@ static int parse_fixed_partitions(struct
struct device_node *pp;
int nr_parts, i, ret = 0;
bool dedicated = true;
@ -48,7 +48,7 @@
/* Pull of_node from the master device node */
mtd_node = mtd_get_of_node(master);
@@ -88,7 +122,9 @@ static int parse_fixed_partitions(struct
@@ -93,7 +127,9 @@ static int parse_fixed_partitions(struct
return 0;
parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
@ -59,7 +59,7 @@
return -ENOMEM;
i = 0;
@@ -137,6 +173,11 @@ static int parse_fixed_partitions(struct
@@ -142,6 +178,11 @@ static int parse_fixed_partitions(struct
if (of_get_property(pp, "lock", &len))
parts[i].mask_flags |= MTD_POWERUP_LOCK;
@ -71,7 +71,7 @@
i++;
}
@@ -146,6 +187,11 @@ static int parse_fixed_partitions(struct
@@ -151,6 +192,11 @@ static int parse_fixed_partitions(struct
if (quirks && quirks->post_parse)
quirks->post_parse(master, parts, nr_parts);
@ -83,7 +83,7 @@
*pparts = parts;
return nr_parts;
@@ -156,6 +202,7 @@ ofpart_fail:
@@ -161,6 +207,7 @@ ofpart_fail:
ofpart_none:
of_node_put(pp);
kfree(parts);

View File

@ -5,7 +5,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
--- a/drivers/mtd/parsers/ofpart_core.c
+++ b/drivers/mtd/parsers/ofpart_core.c
@@ -33,6 +33,8 @@ static bool node_has_compatible(struct d
@@ -38,6 +38,8 @@ static bool node_has_compatible(struct d
return of_get_property(pp, "compatible", NULL);
}
@ -14,7 +14,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
static int parse_fixed_partitions(struct mtd_info *master,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@@ -43,6 +45,7 @@ static int parse_fixed_partitions(struct
@@ -48,6 +50,7 @@ static int parse_fixed_partitions(struct
struct device_node *mtd_node;
struct device_node *ofpart_node;
const char *partname;
@ -22,7 +22,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
struct device_node *pp;
int nr_parts, i, ret = 0;
bool dedicated = true;
@@ -126,9 +129,13 @@ static int parse_fixed_partitions(struct
@@ -131,9 +134,13 @@ static int parse_fixed_partitions(struct
parts[i].size = of_read_number(reg + a_cells, s_cells);
parts[i].of_node = pp;
@ -39,7 +39,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
parts[i].name = partname;
if (of_get_property(pp, "read-only", &len))
@@ -241,6 +248,18 @@ static int __init ofpart_parser_init(voi
@@ -247,6 +254,18 @@ static int __init ofpart_parser_init(voi
return 0;
}

View File

@ -28,7 +28,6 @@ define Host/Compile
$(call cc,addpattern)
$(call cc,asustrx)
$(call cc,bcm4908asus,-Wall)
$(call cc,bcm4908img,-Wall)
$(call cc,bcm4908kernel,-Wall)
$(call cc,buffalo-enc buffalo-lib,-Wall)
$(call cc,buffalo-tag buffalo-lib,-Wall)

View File

@ -1,379 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
*/
#include <byteswap.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#if !defined(__BYTE_ORDER)
#error "Unknown byte order"
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le32(x) bswap_32(x)
#define le32_to_cpu(x) bswap_32(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le32(x) (x)
#define le32_to_cpu(x) (x)
#else
#error "Unsupported endianness"
#endif
struct bcm4908img_tail {
uint32_t crc32;
uint32_t unk1;
uint32_t family;
uint32_t unk2;
uint32_t unk3;
};
char *pathname;
static size_t prefix_len;
static size_t suffix_len;
static inline size_t bcm4908img_min(size_t x, size_t y) {
return x < y ? x : y;
}
/**************************************************
* CRC32
**************************************************/
static const uint32_t crc32_tbl[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
uint32_t bcm4908img_crc32(uint32_t crc, uint8_t *buf, size_t len) {
while (len) {
crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
buf++;
len--;
}
return crc;
}
/**************************************************
* Check
**************************************************/
static void bcm4908img_check_parse_options(int argc, char **argv) {
int c;
while ((c = getopt(argc, argv, "p:s:")) != -1) {
switch (c) {
case 'p':
prefix_len = atoi(optarg);
break;
case 's':
suffix_len = atoi(optarg);
break;
}
}
}
static int bcm4908img_check(int argc, char **argv) {
struct bcm4908img_tail tail;
struct stat st;
uint8_t buf[1024];
uint32_t crc32;
size_t length;
size_t bytes;
FILE *fp;
int err = 0;
if (argc < 3) {
fprintf(stderr, "No BCM4908 image pathname passed\n");
err = -EINVAL;
goto out;
}
pathname = argv[2];
optind = 3;
bcm4908img_check_parse_options(argc, argv);
if (stat(pathname, &st)) {
fprintf(stderr, "Failed to stat %s\n", pathname);
err = -EIO;
goto out;
}
fp = fopen(pathname, "r");
if (!fp) {
fprintf(stderr, "Failed to open %s\n", pathname);
err = -EACCES;
goto out;
}
fseek(fp, prefix_len, SEEK_SET);
crc32 = 0xffffffff;
length = st.st_size - prefix_len - sizeof(tail) - suffix_len;
while (length && (bytes = fread(buf, 1, bcm4908img_min(sizeof(buf), length), fp)) > 0) {
crc32 = bcm4908img_crc32(crc32, buf, bytes);
length -= bytes;
}
if (length) {
fprintf(stderr, "Failed to read last %zd B of data from %s\n", length, pathname);
err = -EIO;
goto err_close;
}
if (fread(&tail, 1, sizeof(tail), fp) != sizeof(tail)) {
fprintf(stderr, "Failed to read BCM4908 image tail\n");
err = -EIO;
goto err_close;
}
if (crc32 != le32_to_cpu(tail.crc32)) {
fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(tail.crc32));
err = -EPROTO;
goto err_close;
}
printf("Found a valid BCM4908 image (crc: 0x%08x)\n", crc32);
err_close:
fclose(fp);
out:
return err;
}
/**************************************************
* Create
**************************************************/
static ssize_t bcm4908img_create_append_file(FILE *trx, const char *in_path, uint32_t *crc32) {
FILE *in;
size_t bytes;
ssize_t length = 0;
uint8_t buf[1024];
in = fopen(in_path, "r");
if (!in) {
fprintf(stderr, "Failed to open %s\n", in_path);
return -EACCES;
}
while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
if (fwrite(buf, 1, bytes, trx) != bytes) {
fprintf(stderr, "Failed to write %zu B to %s\n", bytes, pathname);
length = -EIO;
break;
}
*crc32 = bcm4908img_crc32(*crc32, buf, bytes);
length += bytes;
}
fclose(in);
return length;
}
static ssize_t bcm4908img_create_append_zeros(FILE *trx, size_t length) {
uint8_t *buf;
buf = malloc(length);
if (!buf)
return -ENOMEM;
memset(buf, 0, length);
if (fwrite(buf, 1, length, trx) != length) {
fprintf(stderr, "Failed to write %zu B to %s\n", length, pathname);
free(buf);
return -EIO;
}
free(buf);
return length;
}
static ssize_t bcm4908img_create_align(FILE *trx, size_t cur_offset, size_t alignment) {
if (cur_offset & (alignment - 1)) {
size_t length = alignment - (cur_offset % alignment);
return bcm4908img_create_append_zeros(trx, length);
}
return 0;
}
static int bcm4908img_create(int argc, char **argv) {
struct bcm4908img_tail tail = {
.unk1 = cpu_to_le32(0x5732),
.family = cpu_to_le32(0x4908),
.unk2 = cpu_to_le32(0x03),
.unk3 = cpu_to_le32(0x02),
};
uint32_t crc32 = 0xffffffff;
size_t cur_offset = 0;
ssize_t bytes;
FILE *fp;
int c;
int err = 0;
if (argc < 3) {
fprintf(stderr, "No BCM4908 image pathname passed\n");
err = -EINVAL;
goto out;
}
pathname = argv[2];
fp = fopen(pathname, "w+");
if (!fp) {
fprintf(stderr, "Failed to open %s\n", pathname);
err = -EACCES;
goto out;
}
optind = 3;
while ((c = getopt(argc, argv, "f:a:A:")) != -1) {
switch (c) {
case 'f':
bytes = bcm4908img_create_append_file(fp, optarg, &crc32);
if (bytes < 0) {
fprintf(stderr, "Failed to append file %s\n", optarg);
} else {
cur_offset += bytes;
}
break;
case 'a':
bytes = bcm4908img_create_align(fp, cur_offset, strtol(optarg, NULL, 0));
if (bytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
cur_offset += bytes;
break;
case 'A':
bytes = strtol(optarg, NULL, 0) - cur_offset;
if (bytes < 0) {
fprintf(stderr, "Current BCM4908 image length is 0x%zx, can't pad it with zeros to 0x%lx\n", cur_offset, strtol(optarg, NULL, 0));
} else {
bytes = bcm4908img_create_append_zeros(fp, bytes);
if (bytes < 0)
fprintf(stderr, "Failed to append zeros\n");
else
cur_offset += bytes;
}
break;
}
if (err)
goto err_close;
}
tail.crc32 = cpu_to_le32(crc32);
bytes = fwrite(&tail, 1, sizeof(tail), fp);
if (bytes != sizeof(tail)) {
fprintf(stderr, "Failed to write BCM4908 image tail to %s\n", pathname);
return -EIO;
}
err_close:
fclose(fp);
out:
return err;
}
/**************************************************
* Start
**************************************************/
static void usage() {
printf("Usage:\n");
printf("\n");
printf("Checking a BCM4908 image:\n");
printf("\tbcm4908img check <file> [options]\tcheck if images is valid\n");
printf("\t-p prefix\t\t\tlength of custom header to skip (default: 0)\n");
printf("\t-s suffix\t\t\tlength of custom tail to skip (default: 0)\n");
printf("\n");
printf("Creating a new BCM4908 image:\n");
printf("\tbcm4908img create <file> [options]\n");
printf("\t-f file\t\t\t\tadd data from specified file\n");
printf("\t-a alignment\t\t\tpad image with zeros to specified alignment\n");
printf("\t-A offset\t\t\t\tappend zeros until reaching specified offset\n");
}
int main(int argc, char **argv) {
if (argc > 1) {
if (!strcmp(argv[1], "check"))
return bcm4908img_check(argc, argv);
else if (!strcmp(argv[1], "create"))
return bcm4908img_create(argc, argv);
}
usage();
return 0;
}

View File

@ -27,11 +27,11 @@
#endif
struct bcm4908kernel_header {
uint32_t unk1;
uint32_t unk2;
uint32_t length;
uint32_t boot_load_addr; /* AKA la_address */
uint32_t boot_addr; /* AKA la_entrypt */
uint32_t data_len;
uint8_t magic[4];
uint32_t unused;
uint32_t uncomplen; /* Empty for LZMA, used for LZ4 */
};
static void usage() {
@ -103,14 +103,14 @@ int main(int argc, char **argv) {
length += bytes;
}
header.unk1 = cpu_to_le32(0x00080000);
header.unk2 = cpu_to_le32(0x00080000);
header.length = cpu_to_le32(length);
header.boot_load_addr = cpu_to_le32(0x00080000);
header.boot_addr = cpu_to_le32(0x00080000);
header.data_len = cpu_to_le32(length);
header.magic[0] = 'B';
header.magic[1] = 'R';
header.magic[2] = 'C';
header.magic[3] = 'M';
header.unused = 0;
header.uncomplen = 0;
fseek(out, 0, SEEK_SET);