Skip to contentSkip to conversation

brcmfmac: add CLM download support

PATCH Superseded Wright Feng 4 participants 5 messages Aug 28, 2017 Broadcom BRCM80211 IEEE802.11 wireless drivers

v4 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/1 brcmfmac: add CLM download support

From: Chung-Hsien Hsu <[email protected]>

The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob.

The CLM blob file is optional. If the file does not exist, the download process will be bypassed. It will not affect the driver loading.

---
v2: Revise commit message to describe in more detail
v3: Add error handling in brcmf_c_get_clm_name function
v4: Correct the length of dload_buf in brcmf_c_download function

---
 .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  10 ++
 .../wireless/broadcom/brcm80211/brcmfmac/common.c  | 161 +++++++++++++++++++++
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |   2 +
 .../wireless/broadcom/brcm80211/brcmfmac/core.h    |   2 +
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       |  31 ++++
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  19 +++
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  19 +++
 .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  18 +++
 8 files changed, 262 insertions(+)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +10 -0
index b55c329..df42e09 100644
@@ -71,6 +71,7 @@ struct brcmf_bus_dcmd {
  * @wowl_config: specify if dongle is configured for wowl when going to suspend
  * @get_ramsize: obtain size of device memory.
  * @get_memdump: obtain device memory dump in provided buffer.
+ * @get_fwname: obtain firmware name.
  *
  * This structure provides an abstract interface towards the
  * bus specific driver. For control messages to common driver
@@ -87,6 +88,8 @@ struct brcmf_bus_ops {
 	void (*wowl_config)(struct device *dev, bool enabled);
 	size_t (*get_ramsize)(struct device *dev);
 	int (*get_memdump)(struct device *dev, void *data, size_t len);
+	int (*get_fwname)(struct device *dev, uint chip, uint chiprev,
+			  unsigned char *fw_name);
 };
 
 
@@ -214,6 +217,13 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
 	return bus->ops->get_memdump(bus->dev, data, len);
 }
 
+static inline
+int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev,
+			 unsigned char *fw_name)
+{
+	return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name);
+}
+
 /*
  * interface functions from common layer
  */
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +161 -0

197 lines not on this page · raw message

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +2 -0
index 511d190..7414dff 100644
@@ -941,6 +941,8 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data)
 	seq_printf(s, "anarev: %u\n", ri->anarev);
 	seq_printf(s, "nvramrev: %08x\n", ri->nvramrev);
 
+	seq_printf(s, "clmrev: %s\n", bus_if->drvr->clmver);
+
 	return 0;
 }
 
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +2 -0
index a4dd313..ae39128 100644
@@ -141,6 +141,8 @@ struct brcmf_pub {
 	struct notifier_block inetaddr_notifier;
 	struct notifier_block inet6addr_notifier;
 	struct brcmf_mp_device *settings;
+
+	u8 clmver[BRCMF_DCMD_SMLEN];
 };
 
 /* forward declarations */
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +31 -0
index 9a1eb5a..fffe347 100644
@@ -147,6 +147,21 @@
 #define BRCMF_MFP_CAPABLE		1
 #define BRCMF_MFP_REQUIRED		2
 
+/* MAX_CHUNK_LEN is the maximum length for data passing to firmware in each
+ * ioctl. It is relatively small because firmware has small maximum size input
+ * playload restriction for ioctls.
+ */
+#define MAX_CHUNK_LEN			1400
+
+#define DLOAD_HANDLER_VER		1	/* Downloader version */
+#define DLOAD_FLAG_VER_MASK		0xf000	/* Downloader version mask */
+#define DLOAD_FLAG_VER_SHIFT		12	/* Downloader version shift */
+
+#define DL_BEGIN			0x0002
+#define DL_END				0x0004
+
+#define DL_TYPE_CLM			2
+
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
 	BRCMF_JOIN_PREF_RSSI = 1,
@@ -835,4 +850,20 @@ struct brcmf_gtk_keyinfo_le {
 	u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
 };
 
+/**
+ * struct brcmf_dload_data_le - data passing to firmware for downloading
+ * @flag: flags related to download data.
+ * @dload_type: type of download data.
+ * @len: length in bytes of download data.
+ * @crc: crc of download data.
+ * @data: download data.
+ */
+struct brcmf_dload_data_le {
+	__le16 flag;
+	__le16 dload_type;
+	__le32 len;
+	__le32 crc;
+	u8 data[1];
+};
+
 #endif /* FWIL_TYPES_H_ */
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +19 -0
index f878706..b370ee7 100644
@@ -1350,6 +1350,24 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
 	return 0;
 }
 
+static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				 u8 *fw_name)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
+	struct brcmf_pciedev_info *devinfo = buspub->devinfo;
+	int ret = 0;
+
+	if (devinfo->fw_name[0] != '\0')
+		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_pcie_fwnames,
+						ARRAY_SIZE(brcmf_pcie_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
 
 static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.txdata = brcmf_pcie_tx,
@@ -1359,6 +1377,7 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
 	.wowl_config = brcmf_pcie_wowl_config,
 	.get_ramsize = brcmf_pcie_get_ramsize,
 	.get_memdump = brcmf_pcie_get_memdump,
+	.get_fwname = brcmf_pcie_get_fwname,
 };
 
 
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +19 -0
index b1789b1..3a71ca0 100644
@@ -3972,6 +3972,24 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
 	}
 }
 
+static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				 u8 *fw_name)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+	int ret = 0;
+
+	if (sdiodev->fw_name[0] != '\0')
+		strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_sdio_fwnames,
+						ARRAY_SIZE(brcmf_sdio_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
+
 static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.stop = brcmf_sdio_bus_stop,
 	.preinit = brcmf_sdio_bus_preinit,
@@ -3982,6 +4000,7 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val)
 	.wowl_config = brcmf_sdio_wowl_config,
 	.get_ramsize = brcmf_sdio_bus_get_ramsize,
 	.get_memdump = brcmf_sdio_bus_get_memdump,
+	.get_fwname = brcmf_sdio_get_fwname,
 };
 
 static void brcmf_sdio_firmware_callback(struct device *dev, int err,
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +18 -0
index 8f20a4b..9622dd9 100644
@@ -1128,12 +1128,30 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
 		device_set_wakeup_enable(devinfo->dev, false);
 }
 
+static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev,
+				u8 *fw_name)
+{
+	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+	int ret = 0;
+
+	if (devinfo->fw_name[0] != '\0')
+		strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN);
+	else
+		ret = brcmf_fw_map_chip_to_name(chip, chiprev,
+						brcmf_usb_fwnames,
+						ARRAY_SIZE(brcmf_usb_fwnames),
+						fw_name, NULL);
+
+	return ret;
+}
+
 static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
 	.txdata = brcmf_usb_tx,
 	.stop = brcmf_usb_down,
 	.txctl = brcmf_usb_tx_ctlpkt,
 	.rxctl = brcmf_usb_rx_ctlpkt,
 	.wowl_config = brcmf_usb_wowl_config,
+	.get_fwname = brcmf_usb_get_fwname,
 };
 
 static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
Signature · 1 line
1.9.1
maintainer
#1 lore raw
Quoted 28 lines · Wright Feng

From: Chung-Hsien Hsu <[email protected]>

The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob.

The CLM blob file is optional. If the file does not exist, the download process will be bypassed. It will not affect the driver loading.

---
v2: Revise commit message to describe in more detail
v3: Add error handling in brcmf_c_get_clm_name function
v4: Correct the length of dload_buf in brcmf_c_download function

---
  .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  10 ++
  .../wireless/broadcom/brcm80211/brcmfmac/common.c  | 161 +++++++++++++++++++++
  .../wireless/broadcom/brcm80211/brcmfmac/core.c    |   2 +
  .../wireless/broadcom/brcm80211/brcmfmac/core.h    |   2 +
  .../broadcom/brcm80211/brcmfmac/fwil_types.h       |  31 ++++
  .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  19 +++
  .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  19 +++
  .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  18 +++
  8 files changed, 262 insertions(+)

[...]

Quoted 4 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +0 -0
index 7a2b495..d09922b 100644

[...]

Quoted 7 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +3 -0
@@ -104,12 +106,139 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
  		brcmf_err("Set join_pref error (%d)\n", err);
  }
 
+static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
+			    struct brcmf_dload_data_le *dload_buf,
+			    u32 len)

drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) · line 121

Quoted 10 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +10 -0
+{
+	s32 err;
+
+	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
+	dload_buf->flag = cpu_to_le16(flag);
+	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
+	dload_buf->len = cpu_to_le32(len);
+	dload_buf->crc = cpu_to_le32(0);
+	len = sizeof(*dload_buf) + len - 1;
+	len = len + 8 - (len % 8);

In case len is 8 this will result in 16. So better use roundup() macro from include/linux/kernel.h [1]. However, this means brcmf_fil_iovar_data_set() will read after the allocated buffer space.

By the way, where does the alignment requirement come from?

drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) · line 123

Quoted 2 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +2 -0
+
+	err = brcmf_fil_iovar_data_set(ifp, "clmload", (void *)dload_buf, len);

The cast is not necessary so please remove.

Regards,
Arend

[1] http://elixir.free-electrons.com/linux/latest/source/include/linux/kernel.h#L90

#2 lore raw
Quoted 62 lines · Arend van Spriel
Quoted 28 lines · Wright Feng

From: Chung-Hsien Hsu <[email protected]>

The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob.

The CLM blob file is optional. If the file does not exist, the download process will be bypassed. It will not affect the driver loading.

---
v2: Revise commit message to describe in more detail
v3: Add error handling in brcmf_c_get_clm_name function
v4: Correct the length of dload_buf in brcmf_c_download function

---
 .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  10 ++
 .../wireless/broadcom/brcm80211/brcmfmac/common.c  | 161 +++++++++++++++++++++
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |   2 +
 .../wireless/broadcom/brcm80211/brcmfmac/core.h    |   2 +
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       |  31 ++++
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    |  19 +++
 .../wireless/broadcom/brcm80211/brcmfmac/sdio.c    |  19 +++
 .../net/wireless/broadcom/brcm80211/brcmfmac/usb.c |  18 +++
 8 files changed, 262 insertions(+)

[...]

Quoted 4 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +0 -0
index 7a2b495..d09922b 100644

[...]

Quoted 7 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +3 -0
@@ -104,12 +106,139 @@ void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
 		brcmf_err("Set join_pref error (%d)\n", err);
 }
 
+static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
+			    struct brcmf_dload_data_le *dload_buf,
+			    u32 len)

drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) · line 121

Quoted 10 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +10 -0
+{
+	s32 err;
+
+	flag |= (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT);
+	dload_buf->flag = cpu_to_le16(flag);
+	dload_buf->dload_type = cpu_to_le16(DL_TYPE_CLM);
+	dload_buf->len = cpu_to_le32(len);
+	dload_buf->crc = cpu_to_le32(0);
+	len = sizeof(*dload_buf) + len - 1;
+	len = len + 8 - (len % 8);

In case len is 8 this will result in 16. So better use roundup() macro from include/linux/kernel.h [1]. However, this means brcmf_fil_iovar_data_set() will read after the allocated buffer space.

Quoted 2 lines

By the way, where does the alignment requirement come from?

Thanks for pointing this out. I've tried the download process without this alignment. There's no error/failure showed up. Looks like the alignment is not necessary here so I will remove it.

Quoted 4 lines

drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c void brcmf_c_set_joinpref_default(struct brcmf_if *ifp) · line 123

Quoted 2 lines
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +2 -0
+
+	err = brcmf_fil_iovar_data_set(ifp, "clmload", (void *)dload_buf, len);

The cast is not necessary so please remove.

Will do it.

Regards,
Chung-Hsien

Quoted 5 lines

Regards,
Arend

[1] http://elixir.free-electrons.com/linux/latest/source/include/linux/kernel.h#L90

#3 lore raw
In reply to Wright Feng
Quoted 9 lines · Wright Feng

From: Chung-Hsien Hsu <[email protected]>

The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob.

Not to bikeshed this, but why not just ".clm"? ".clm_blob" seems unnecessary and could feel "unprofessional" to users.

To me simple seems better.

- Steve

maintainer
#4 lore raw
Quoted 11 lines · Steve deRosier
Quoted 9 lines · Wright Feng

From: Chung-Hsien Hsu <[email protected]>

The firmware for brcmfmac devices includes information regarding regulatory constraints. For certain devices this information is kept separately in a binary form that needs to be downloaded to the device. This patch adds support to download this so-called CLM blob file. It uses the same naming scheme as the other firmware files with extension of .clm_blob.

Quoted 4 lines

Not to bikeshed this, but why not just ".clm"? ".clm_blob" seems unnecessary and could feel "unprofessional" to users.

To me simple seems better.

Hi Steve,

Glad you ask ;-) It was one of my comments pre-reviewing this "internally"*. The problem with calling it .clm is that it means something else within Broadcom and Cypress for that matter. The .clm_blob is the output of tool compiling the regulatory data according an input specification which uses the .clm extension. It is similar to regdb.txt and regulatory.bin.

Regards,
Arend

* internally does not quite cover Cypress+Broadcom collaboration.