Path: blob/main/sys/contrib/dev/mediatek/mt76/mcu.c
48378 views
// SPDX-License-Identifier: ISC1/*2* Copyright (C) 2019 Lorenzo Bianconi <[email protected]>3*/45#include "mt76.h"67struct sk_buff *8__mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,9int len, int data_len, gfp_t gfp)10{11const struct mt76_mcu_ops *ops = dev->mcu_ops;12struct sk_buff *skb;1314len = max_t(int, len, data_len);15len = ops->headroom + len + ops->tailroom;1617skb = alloc_skb(len, gfp);18if (!skb)19return NULL;2021memset(skb->head, 0, len);22skb_reserve(skb, ops->headroom);2324if (data && data_len)25skb_put_data(skb, data, data_len);2627return skb;28}29EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc);3031struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,32unsigned long expires)33{34unsigned long timeout;3536if (!time_is_after_jiffies(expires))37return NULL;3839timeout = expires - jiffies;40wait_event_timeout(dev->mcu.wait,41(!skb_queue_empty(&dev->mcu.res_q) ||42test_bit(MT76_MCU_RESET, &dev->phy.state)),43timeout);44return skb_dequeue(&dev->mcu.res_q);45}46EXPORT_SYMBOL_GPL(mt76_mcu_get_response);4748void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)49{50skb_queue_tail(&dev->mcu.res_q, skb);51wake_up(&dev->mcu.wait);52}53EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);5455int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,56int len, bool wait_resp, struct sk_buff **ret_skb)57{58struct sk_buff *skb;5960if (dev->mcu_ops->mcu_send_msg)61return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);6263skb = mt76_mcu_msg_alloc(dev, data, len);64if (!skb)65return -ENOMEM;6667return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);68}69EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);7071int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,72int cmd, bool wait_resp,73struct sk_buff **ret_skb)74{75unsigned int retry = 0;76struct sk_buff *orig_skb = NULL;77unsigned long expires;78int ret, seq;7980if (mt76_is_sdio(dev))81if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung))82return -EIO;8384if (ret_skb)85*ret_skb = NULL;8687mutex_lock(&dev->mcu.mutex);8889if (dev->mcu_ops->mcu_skb_prepare_msg) {90orig_skb = skb;91ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq);92if (ret < 0)93goto out;94}9596retry:97/* orig skb might be needed for retry, mcu_skb_send_msg consumes it */98if (orig_skb)99skb_get(orig_skb);100ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);101if (ret < 0)102goto out;103104if (!wait_resp) {105ret = 0;106goto out;107}108109expires = jiffies + dev->mcu.timeout;110111do {112skb = mt76_mcu_get_response(dev, expires);113if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) &&114orig_skb && retry++ < dev->mcu_ops->max_retry) {115dev_err(dev->dev, "Retry message %08x (seq %d)\n",116cmd, seq);117skb = orig_skb;118goto retry;119}120121ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);122if (!ret && ret_skb)123*ret_skb = skb;124else125dev_kfree_skb(skb);126} while (ret == -EAGAIN);127128129out:130dev_kfree_skb(orig_skb);131mutex_unlock(&dev->mcu.mutex);132133return ret;134}135EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);136137#if defined(__linux__)138int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,139#elif defined(__FreeBSD__)140int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const u8 *data,141#endif142int len, int max_len)143{144int err, cur_len;145146while (len > 0) {147cur_len = min_t(int, max_len, len);148149err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);150if (err)151return err;152153data += cur_len;154len -= cur_len;155156if (dev->queue_ops->tx_cleanup)157dev->queue_ops->tx_cleanup(dev,158dev->q_mcu[MT_MCUQ_FWDL],159false);160}161162return 0;163}164EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);165166167