Commit 185c106f authored by Jérôme Pouiller's avatar Jérôme Pouiller Committed by Greg Kroah-Hartman
Browse files

staging: wfx: add support for start-up indication



Once firmware is loaded, it send a first indication to host. This
indication signalize that host can start to communicate with firmware.
In add, it contains information about chip and firmware (MAC addresses,
firmware version, etc...).

Signed-off-by: default avatarJérôme Pouiller <jerome.pouiller@silabs.com>
Link: https://lore.kernel.org/r/20190919142527.31797-10-Jerome.Pouiller@silabs.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1cc298c9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ wfx-y := \
	bh.o \
	hwio.o \
	fwio.o \
	hif_rx.o \
	main.o \
	debug.o
wfx-$(CONFIG_SPI) += bus_spi.o
+3 −1
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include "wfx.h"
#include "hwio.h"
#include "traces.h"
#include "hif_rx.h"
#include "hif_api_cmd.h"

static void device_wakeup(struct wfx_dev *wdev)
@@ -107,7 +108,8 @@ static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
	}

	skb_put(skb, hif->len);
	dev_kfree_skb(skb); /* FIXME: handle received data */
	// wfx_handle_rx takes care on SKB livetime
	wfx_handle_rx(wdev, skb);

	return piggyback;

+57 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
 * (WSM) API.
 *
 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
 * Copyright (c) 2010, ST-Ericsson
 */
#include <linux/skbuff.h>
#include <linux/etherdevice.h>

#include "hif_rx.h"
#include "wfx.h"
#include "hif_api_cmd.h"

static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf)
{
	struct hif_ind_startup *body = buf;

	if (body->status || body->firmware_type > 4) {
		dev_err(wdev->dev, "received invalid startup indication");
		return -EINVAL;
	}
	memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup));
	le32_to_cpus(&wdev->hw_caps.status);
	le16_to_cpus(&wdev->hw_caps.hardware_id);
	le16_to_cpus(&wdev->hw_caps.num_inp_ch_bufs);
	le16_to_cpus(&wdev->hw_caps.size_inp_ch_buf);

	complete(&wdev->firmware_ready);
	return 0;
}

static const struct {
	int msg_id;
	int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf);
} hif_handlers[] = {
	{ HIF_IND_ID_STARTUP,              hif_startup_indication },
};

void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
{
	int i;
	struct hif_msg *hif = (struct hif_msg *) skb->data;
	int hif_id = hif->id;

	for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
		if (hif_handlers[i].msg_id == hif_id) {
			if (hif_handlers[i].handler)
				hif_handlers[i].handler(wdev, hif, hif->body);
			goto free;
		}
	}
	dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id);
free:
	dev_kfree_skb(skb);
}
+18 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
 * (WSM) API.
 *
 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
 * Copyright (c) 2010, ST-Ericsson
 * Copyright (C) 2010, ST-Ericsson SA
 */
#ifndef WFX_HIF_RX_H
#define WFX_HIF_RX_H

struct wfx_dev;
struct sk_buff;

void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb);

#endif
+45 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
 */
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/mmc/sdio_func.h>
@@ -87,6 +88,9 @@ struct wfx_dev *wfx_init_common(struct device *dev,
	wdev->hwbus_ops = hwbus_ops;
	wdev->hwbus_priv = hwbus_priv;
	memcpy(&wdev->pdata, pdata, sizeof(*pdata));

	init_completion(&wdev->firmware_ready);

	return wdev;
}

@@ -96,7 +100,9 @@ void wfx_free_common(struct wfx_dev *wdev)

int wfx_probe(struct wfx_dev *wdev)
{
	int i;
	int err;
	const void *macaddr;

	wfx_bh_register(wdev);

@@ -104,6 +110,45 @@ int wfx_probe(struct wfx_dev *wdev)
	if (err)
		goto err1;

	err = wait_for_completion_interruptible_timeout(&wdev->firmware_ready, 10 * HZ);
	if (err <= 0) {
		if (err == 0) {
			dev_err(wdev->dev, "timeout while waiting for startup indication. IRQ configuration error?\n");
			err = -ETIMEDOUT;
		} else if (err == -ERESTARTSYS) {
			dev_info(wdev->dev, "probe interrupted by user\n");
		}
		goto err1;
	}

	// FIXME: fill wiphy::hw_version
	dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n",
		 wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor,
		 wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label,
		 wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor,
		 wdev->keyset, *((u32 *) &wdev->hw_caps.capabilities));

	if (wfx_api_older_than(wdev, 1, 0)) {
		dev_err(wdev->dev, "unsupported firmware API version (expect 1 while firmware returns %d)\n",
			wdev->hw_caps.api_version_major);
		err = -ENOTSUPP;
		goto err1;
	}

	for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
		eth_zero_addr(wdev->addresses[i].addr);
		macaddr = of_get_mac_address(wdev->dev->of_node);
		if (macaddr) {
			ether_addr_copy(wdev->addresses[i].addr, macaddr);
			wdev->addresses[i].addr[ETH_ALEN - 1] += i;
		}
		ether_addr_copy(wdev->addresses[i].addr, wdev->hw_caps.mac_addr[i]);
		if (!is_valid_ether_addr(wdev->addresses[i].addr)) {
			dev_warn(wdev->dev, "using random MAC address\n");
			eth_random_addr(wdev->addresses[i].addr);
		}
		dev_info(wdev->dev, "MAC address %d: %pM\n", i, wdev->addresses[i].addr);
	}

	return 0;

Loading