lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4928ea79-2794-05fb-d1a8-942b589a1c3a@marcan.st>
Date:   Wed, 3 Nov 2021 17:28:13 +0900
From:   Hector Martin <marcan@...can.st>
To:     Aditya Garg <gargaditya08@...e.com>,
        "aspriel@...il.com" <aspriel@...il.com>,
        "franky.lin@...adcom.com" <franky.lin@...adcom.com>,
        "hante.meuleman@...adcom.com" <hante.meuleman@...adcom.com>,
        "chi-hsien.lin@...ineon.com" <chi-hsien.lin@...ineon.com>,
        "wright.feng@...ineon.com" <wright.feng@...ineon.com>,
        "chung-hsien.hsu@...ineon.com" <chung-hsien.hsu@...ineon.com>
Cc:     "linux-wireless@...r.kernel.org" <linux-wireless@...r.kernel.org>,
        "brcm80211-dev-list.pdl@...adcom.com" 
        <brcm80211-dev-list.pdl@...adcom.com>,
        "SHA-cyfmac-dev-list@...ineon.com" <SHA-cyfmac-dev-list@...ineon.com>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        Stan Skowronek <stan@...ellium.com>,
        Sven Peter <sven@...npeter.dev>,
        Alyssa Rosenzweig <alyssa@...enzweig.io>,
        Joey Gouly <joey.gouly@....com>
Subject: Re: [PATCH v3 1/3] brcmfmac: Add support for BCM4378 on Apple
 hardware (with their special OTP).

Hi,

I'd been meaning to rewrite this patch because it's such a mess, but 
since we're here... (CCing some relevant folks)

Overall: this patch combines a ton of unrelated random changes, many of 
which without explanation, with some completely crazy approaches. Stan 
(CC'ed) has so far refused to interact with the kernel community in any 
way whatsoever, and I do not feel comfortable using his patches without 
thorough review, including reverse engineering the changes to figure out 
what they actually do and why. We've already gone through this with some 
of his other patches, which ended up being largely rewritten or entirely 
dropped in the end.

The firmware situation with this patch is completely unacceptable. It 
seems the original intent here is to have users load the driver, have it 
print the required firmware version, and then expect users to copy 
specifically that firmware file set from macOS, and reload again. This 
is obviously not the right way to do this. We need to statically copy 
all firmware from macOS/recovery mode with a naming scheme that this 
driver can use, at initial install time, and it needs to dynamically 
select the right firmware for any given platform it is booted on.

The main issue with these machines is that there is a large set of 
required firmware variants; a few core firmware files plus many nvram 
variants for different hardware modules and device revisions. A lot of 
them are identical and can be symlinked, but we need to work out a 
naming scheme for these variations. There are several more dimensions of 
nvram selection than what we're used to on Linux.

For example, nvram is currently named in this kind of fashion:

brcmfmac43455-sdio.raspberrypi,3-model-a-plus.txt

While Apple indexes firmware using a combination of platform module, 
vendor, module version, and antenna config. The first three come from an 
OTP inside the WiFi module, while the antenna config comes from the 
Apple Device Tree and needs to be forwarded to Linux at boot time by the 
bootloader. In addition, there is also chip ID and revision.

Apple names their NVRAM using the following scheme:

C-4378__s-B1/P-honshu-X3_M-RASP_V-u__m-6.5.txt

Where 4378 is the chip, B1 is the revision, "honshu" is the platform, 
"X3" is the antenna config, "RASP" is the module, "u" is the vendor, and 
"6.5" is the module version.

Trying to translate this to something following the Linux conventions, 
we might end up with something like this:

brcmfmac4378b1-pcie.apple,honshu-RASP-u-6.5-X3.txt

However, on macOS, many of these files are copies or symlinks. For 
example, on honshu, the module version and antenna config do not matter. 
So this can simplify to:

brcmfmac4378b1-pcie.apple,honshu-RASP-u.txt

What I've been thinking is we can have the installation process detect 
those duplicates/links, and install only firmware files with the most 
generic name. Then the driver could attempt to load firmwares starting 
with more specific naming and going towards less specific. That would 
avoid having to have a giant pile of symlinks in /lib/firmware/brcm 
(there are 286 discrete files/links in Apple's firmware directory just 
for 4378...)

I would like to have a thorough discussion about how to handle the 
firmware situation, as this affects the software stack from the 
installer to the bootloader to the kernel. We also need a new devicetree 
binding for the antenna type parameter, as that needs to be set via the 
bootloader from the Apple Device Tree info.

On 03/11/2021 13.30, Aditya Garg wrote:
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> index 0ee421f30aa24..8f7db434de111 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
> @@ -5136,8 +5136,13 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
>   		ie_offset =  DOT11_MGMT_HDR_LEN +
>   			     DOT11_BCN_PRB_FIXED_LEN;
>   		ie_len = len - ie_offset;
> -		if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
> +		if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
>   			vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
> +			if (vif == NULL) {
> +				bphy_err(drvr, "No p2p device available for probe response\n");
> +				return -ENODEV;
> +			}
> +		}

Why is this necessary?

> -static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
> +char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
>   module_param_string(alternative_fw_path, brcmf_firmware_path,
> -		    BRCMF_FW_ALTPATH_LEN, 0400);
> +		    BRCMF_FW_ALTPATH_LEN, 0600);
>   MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
>   
> +char brcmf_mac_addr[18];
> +module_param_string(nvram_mac_addr, brcmf_mac_addr,
> +			18, 0600);
> +MODULE_PARM_DESC(nvram_mac_addr, "Set MAC address in NVRAM");

The MAC address should come from the device tree, just as it works for 
every other ethernet device on OF platforms. This already works fine for 
e.g. the wired ethernet; it should be done the same way here.

> +
> +char brcmf_otp_chip_id[BRCMF_OTP_VERSION_MAX];
> +module_param_string(otp_chip_id, brcmf_otp_chip_id, BRCMF_OTP_VERSION_MAX, 0400);
> +MODULE_PARM_DESC(otp_chip_id, "Chip ID and revision from OTP");
> +
> +char brcmf_otp_nvram_id[BRCMF_OTP_VERSION_MAX];
> +module_param_string(otp_nvram_id, brcmf_otp_nvram_id, BRCMF_OTP_VERSION_MAX, 0400);
> +MODULE_PARM_DESC(otp_chip_id, "NVRAM variant from OTP");
> +

This is crazy; the driver should read OTP and figure out what firmware 
it needs. The only piece of external information required is the antenna 
config, which should come from the device tree on ARM platforms (not 
sure how this is passed through on x86/T2 Macs, does anyone have any idea?)

>   static int brcmf_fcmode;
>   module_param_named(fcmode, brcmf_fcmode, int, 0);
>   MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
> @@ -75,7 +88,6 @@ MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
>   #endif
>   
>   static struct brcmfmac_platform_data *brcmfmac_pdata;
> -struct brcmf_mp_global_t brcmf_mp_global;
>   
>   void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
>   {
> @@ -376,22 +388,6 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
>   }
>   #endif
>   
> -static void brcmf_mp_attach(void)
> -{
> -	/* If module param firmware path is set then this will always be used,
> -	 * if not set then if available use the platform data version. To make
> -	 * sure it gets initialized at all, always copy the module param version
> -	 */
> -	strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
> -		BRCMF_FW_ALTPATH_LEN);
> -	if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
> -	    (brcmf_mp_global.firmware_path[0] == '\0')) {
> -		strlcpy(brcmf_mp_global.firmware_path,
> -			brcmfmac_pdata->fw_alternative_path,
> -			BRCMF_FW_ALTPATH_LEN);
> -	}
> -}

Why is this being removed?

> +static void brcmf_fw_set_macaddr(struct nvram_parser *nvp, const char *mac_addr)
> +{
> +	uint8_t mac[6] = { 0 };
> +	size_t len = strlen("macaddr=") + 17 + 1; /* 17 = "aa:bb:cc:dd:ee:ff" */
> +	unsigned i = 0;
> +	unsigned long res = 0;
> +	char tmp[3];
> +
> +	while(mac_addr[0] && mac_addr[1] && i < 6) {
> +		tmp[0] = mac_addr[0];
> +		tmp[1] = mac_addr[1];
> +		tmp[2] = 0;
> +		if(kstrtoul(tmp, 16, &res))
> +			break;
> +		mac[i] = res;
> +		mac_addr += 2;
> +		i ++;
> +		while(*mac_addr == ':' || *mac_addr == ' ' || *mac_addr == '-')
> +			mac_addr ++;
> +	}
> +	if(i < 6)
> +		pr_warn("invalid MAC address supplied for brcmfmac!\n");
> +
> +	memmove(&nvp->nvram[len], &nvp->nvram[0], nvp->nvram_len);
> +	nvp->nvram_len += len;
> +	sprintf(&nvp->nvram[0], "macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
> +		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
> +}

The driver already has the ability to set the MAC address; why do we 
need to set it in nvram? Just call the MAC address change function at 
driver initialization (instead of the MAC address get function, for 
these chips). The MAC address should come from the device tree, e.g. via 
eth_platform_get_mac_address(). See tg3 for a driver that already does 
this properly (and works on the M1 Mac Mini with zero changes).

> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
> index ec6fc7a150a6a..1c1d5131c3f36 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
> @@ -565,7 +565,8 @@ static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
>   
>   	/* Set the discovery state to SCAN */
>   	vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
> -	(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
> +	if (vif != NULL)
> +		(void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
>   
>   	/* Disable P2P discovery in the firmware */
>   	vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
> @@ -1351,6 +1352,8 @@ brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac)
>   	 * if not (sa addr > da addr),
>   	 * this device will process gon request and drop gon req of peer.
>   	 */
> +	if(p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif == NULL)
> +		return false;
>   	ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
>   	if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) {
>   		brcmf_dbg(INFO, "Block transmit gon req !!!\n");
> @@ -1559,6 +1562,10 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,
>   	else
>   		vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
>   
> +	if (vif == NULL) {
> +		bphy_err(drvr, " no P2P interface available\n");
> +		goto exit;
> +	}
>   	err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params,
>   					sizeof(*af_params));
>   	if (err) {

Are these really the only brcmfmac chips without a P2P interface? What 
does this mean for end users? What features are lost?

> +static u32
> +brcmf_pcie_reg_map(struct brcmf_pciedev_info *devinfo, u32 reg)
> +{
> +	switch(reg) {
> +	case BRCMF_PCIE_PCIE2REG_INTMASK:
> +		if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
> +			return BRCMF_PCIE_64_PCIE2REG_INTMASK;
> +		return reg;
> +	case BRCMF_PCIE_PCIE2REG_MAILBOXINT:
> +		if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
> +			return BRCMF_PCIE_64_PCIE2REG_MAILBOXINT;
> +		return reg;
> +	case BRCMF_PCIE_PCIE2REG_MAILBOXMASK:
> +		if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
> +			return BRCMF_PCIE_64_PCIE2REG_MAILBOXMASK;
> +		return reg;
> +	case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_0:
> +		if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
> +			return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_0;
> +		return reg;
> +	case BRCMF_PCIE_PCIE2REG_H2D_MAILBOX_1:
> +		if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID)
> +			return BRCMF_PCIE_64_PCIE2REG_H2D_MAILBOX_1;
> +		return reg;
> +	default:
> +		return reg;
> +	}
> +}

This kind of register mapping is ugly. A much better way to do this is 
to have static structures containing the list of registers for each 
given chip/variant. Then you just set it at load time and the functions 
that need those registers use those structures to find them, instead of 
constants.

> +
> +
> +

Too many blank lines

>   #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
>   		CHIPCREGOFFS(reg), value)
>   
> @@ -543,6 +626,7 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid)
>   	core = brcmf_chip_get_core(devinfo->ci, coreid);
>   	if (core) {
>   		bar0_win = core->base;
> +
>   		pci_write_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW, bar0_win);
>   		if (pci_read_config_dword(pdev, BRCMF_PCIE_BAR0_WINDOW,
>   					  &bar0_win) == 0) {

This seems like a leftover.

> @@ -615,11 +699,129 @@ static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo)
>   	}
>   }
>   
> +#define OTP_SIZE		64
> +#define OTP_CORE_ID		BCMA_CORE_GCI
> +#define OTP_CC_ADDR_4378	0x1120
> +
> +static void brcmf_pcie_process_otp_tuple(struct brcmf_pciedev_info *devinfo, u8 type, u8 size, u8 *data)
> +{
> +	char tmp[OTP_SIZE], t_chiprev[8] = "", t_module[8] = "", t_modrev[8] = "", t_vendor[8] = "", t_chip[8] = "";
> +	unsigned i, len;
> +
> +	switch(type) {
> +	case 0x15: /* system vendor OTP */
> +		if(size < 4)
> +			return;
> +		if(*(u32 *)data != 8)
> +			dev_warn(&devinfo->pdev->dev, "system vendor OTP header unexpected: %d\n", *(u32 *)data);
> +		size -= 4;
> +		data += 4;
> +		while(size) {
> +			if(data[0] == 0xFF)
> +				break;
> +			for(len=0; len<size; len++)
> +				if(data[len] == 0x00 || data[len] == ' ' || data[len] == 0xFF)
> +					break;
> +			memcpy(tmp, data, len);
> +			tmp[len] = 0;
> +			data += len;
> +			size -= len;
> +			if(size) {
> +				data ++;
> +				size --;
> +			}
> +			brcmf_dbg(PCIE, "system vendor OTP element '%s'\n", tmp);
> +
> +			if(len < 2)
> +				continue;
> +			if(tmp[1] == '=' && len < 8)
> +				switch(tmp[0]) {
> +				case 's':
> +					strcpy(t_chiprev, tmp + 2);
> +					break;
> +				case 'M':
> +					strcpy(t_module, tmp + 2);
> +					break;
> +				case 'm':
> +					strcpy(t_modrev, tmp + 2);
> +					break;
> +				case 'V':
> +					strcpy(t_vendor, tmp + 2);
> +					break;
> +				}
> +		}
> +
> +		sprintf(t_chip, (devinfo->ci->chip > 40000) ? "%05d" : "%04x", devinfo->ci->chip);
> +		dev_info(&devinfo->pdev->dev, "module revision data: chip %s, chip rev %s, module %s, module rev %s, vendor %s\n", t_chip, t_chiprev, t_module, t_modrev, t_vendor);
> +
> +		if(t_chiprev[0])
> +			sprintf(brcmf_otp_chip_id, "C-%s__s-%s", t_chip, t_chiprev);
> +		else
> +			sprintf(brcmf_otp_chip_id, "C-%s", t_chip);
> +		sprintf(brcmf_otp_nvram_id, "M-%s_V-%s__m-%s", t_module, t_vendor, t_modrev);
> +
> +		break;
> +	case 0x80: /* Broadcom CIS */
> +		if(size < 1)
> +			return;
> +		switch(data[0]) {
> +		case 0x83: /* serial number */
> +			for(i=0; i<16 && i<size-1; i++)
> +				sprintf(tmp + 2 * i, "%02x", data[i+1]);
> +			dev_info(&devinfo->pdev->dev, "module serial number: %s\n", tmp);
> +			break;
> +		}
> +		break;
> +	}
> +}

This seems to be building the Apple-formwat firmware name for users to 
use to find the right firmware. As I said, this is entirely the wrong 
approach to do it. The driver needs to use this information to find the 
right firmware itself, and the firmware copying/installation process 
needs to copy *all* of them.

> +
> +static u32 brcmf_pcie_buscore_prep_addr(const struct pci_dev *pdev, u32 addr);
> +
> +static void brcmf_pcie_read_otp(struct brcmf_pciedev_info *devinfo)
> +{
> +	u8 otp[OTP_SIZE], type, size;
> +	unsigned i;
> +	struct brcmf_core *core;
> +	u32 base;
> +
> +	if (devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) {
> +		/* for whatever reason, reading OTP works only once after reset */
> +		if(brcmf_otp_chip_id[0])
> +			return;

Why? Has this been debugged to figure out why it fails and after what point?

> +
> +		core = brcmf_chip_get_core(devinfo->ci, OTP_CORE_ID);
> +		if(!core) {
> +			dev_err(&devinfo->pdev->dev, "can't find core for OTP\n");
> +			return;
> +		}
> +		base = brcmf_pcie_buscore_prep_addr(devinfo->pdev, core->base + OTP_CC_ADDR_4378);
> +
> +		for(i=0; i<OTP_SIZE; i+=2)
> +			((u16 *)otp)[i/2] = brcmf_pcie_read_reg16(devinfo, base + i);
> +
> +		i = 0;
> +		while(i < OTP_SIZE - 1) {
> +			type = otp[i];
> +			if(!type) { /* null tuple */
> +				i ++;
> +				continue;
> +			}
> +			size = otp[i + 1];
> +			i += 2;
> +			if(i + size <= OTP_SIZE)
> +				brcmf_pcie_process_otp_tuple(devinfo, type, size, otp + i);
> +			i += size;
> +		}
> +	}
> +}
> +
>   
>   static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo)
>   {
>   	u32 config;
>   
> +	brcmf_pcie_read_otp(devinfo);
> +
>   	/* BAR1 window may not be sized properly */
>   	brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
>   	brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_CONFIGADDR, 0x4e0);
> @@ -809,30 +1011,34 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo,
>   
>   static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
>   {
> -	brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
> +	brcmf_pcie_write_reg32(devinfo, brcmf_pcie_reg_map(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK), 0);
>   }

See above for why this is the wrong approach (also the other instances).
> @@ -1543,6 +1754,8 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
>   	return 0;
>   }
>   
> +#define RANDOMBYTES_SIZE        264
> +#define CLEAR_SIZE              256
>   
>   static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
>   					const struct firmware *fw, void *nvram,
> @@ -1553,15 +1766,16 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
>   	u32 sharedram_addr_written;
>   	u32 loop_counter;
>   	int err;
> -	u32 address;
> +	u32 address, clraddr;
>   	u32 resetintr;
> +	uint8_t randb[RANDOMBYTES_SIZE];
>   
>   	brcmf_dbg(PCIE, "Halt ARM.\n");
>   	err = brcmf_pcie_enter_download_state(devinfo);
>   	if (err)
>   		return err;
>   
> -	brcmf_dbg(PCIE, "Download FW %s\n", devinfo->fw_name);
> +	brcmf_dbg(PCIE, "Download FW %s 0x%x 0x%x\n", devinfo->fw_name, (unsigned)devinfo->ci->rambase, (unsigned)fw->size);

This seems like a leftover debug change.

>   	brcmf_pcie_copy_mem_todev(devinfo, devinfo->ci->rambase,
>   				  (void *)fw->data, fw->size);
>   
> @@ -1574,20 +1788,38 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
>   	brcmf_pcie_write_ram32(devinfo, devinfo->ci->ramsize - 4, 0);
>   
>   	if (nvram) {
> -		brcmf_dbg(PCIE, "Download NVRAM %s\n", devinfo->nvram_name);
>   		address = devinfo->ci->rambase + devinfo->ci->ramsize -
>   			  nvram_len;
> +		brcmf_dbg(PCIE, "Download NVRAM %s 0x%x 0x%x\n", devinfo->nvram_name, address, nvram_len);

Ditto

>   		brcmf_pcie_copy_mem_todev(devinfo, address, nvram, nvram_len);
>   		brcmf_fw_nvram_free(nvram);
> +
> +		address -= RANDOMBYTES_SIZE;
> +		get_random_bytes(randb, RANDOMBYTES_SIZE - 8);
> +		memcpy(randb + RANDOMBYTES_SIZE - 8, "\x00\x01\x00\x00\xde\xc0\xed\xfe", 8);
> +		brcmf_pcie_copy_mem_todev(devinfo, address, randb, RANDOMBYTES_SIZE);

Do Apple chips require some random seed placed before the nvram? And if 
so, why is this being done unconditionally for all chips? Do the other 
chips not care if we do this? Can it cause issues?

>   	} else {
>   		brcmf_dbg(PCIE, "No matching NVRAM file found %s\n",
>   			  devinfo->nvram_name);
> +		address = devinfo->ci->rambase + devinfo->ci->ramsize;
> +	}
> +
> +	memset(randb, 0, CLEAR_SIZE);
> +	clraddr = devinfo->ci->rambase + fw->size;
> +	while(clraddr < address) {
> +		u32 block = address - clraddr;
> +		if(block > CLEAR_SIZE)
> +			block = CLEAR_SIZE;
> +		if(((clraddr + block - 1) ^ clraddr) & -CLEAR_SIZE)
> +			block = (CLEAR_SIZE - clraddr) & (CLEAR_SIZE - 1);
> +		brcmf_pcie_copy_mem_todev(devinfo, clraddr, randb, block);
> +		clraddr += block;
>   	}

Looks like this is clearing memory from the end of firmware to the 
nvram/random area. Why is this necessary?

>   
>   	sharedram_addr_written = brcmf_pcie_read_ram32(devinfo,
>   						       devinfo->ci->ramsize -
>   						       4);
> -	brcmf_dbg(PCIE, "Bring ARM in running state\n");
> +	brcmf_dbg(PCIE, "Bring ARM in running state (RAM sign: 0x%08x)\n", sharedram_addr_written);
>   	err = brcmf_pcie_exit_download_state(devinfo, resetintr);
>   	if (err)
>   		return err;

Leftover debug?

> +	if(devinfo->ci->chip == BRCM_CC_4378_CHIP_ID) {
> +		brcmf_pcie_read_otp(devinfo);
> +
> +		if(!brcmf_mac_addr[0]) {
> +			dev_info(&pdev->dev, "hardware discovery complete, not starting driver\n");
> +			ret = -ENODEV;
> +			goto exit;
> +		}
> +	}

Yeah, this is crazy. The whole "load the driver once, tell the user what 
info they need, have them copy the firmware and set things up and load 
it again" dance is ridiculous. Hard NAK on doing things this way.

-- 
Hector Martin (marcan@...can.st)
Public Key: https://mrcn.st/pub

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ