summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/caif/Kconfig2
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c6
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c13
-rw-r--r--drivers/net/ethernet/realtek/r8169.c2
-rw-r--r--drivers/net/usb/hso.c18
-rw-r--r--drivers/net/wireless/b43/phy_common.c2
-rw-r--r--drivers/net/wireless/cnss2/bus.c16
-rw-r--r--drivers/net/wireless/cnss2/bus.h3
-rw-r--r--drivers/net/wireless/cnss2/main.c89
-rw-r--r--drivers/net/wireless/cnss2/main.h9
-rw-r--r--drivers/net/wireless/cnss2/pci.c1
-rw-r--r--drivers/net/wireless/cnss2/qmi.c321
-rw-r--r--drivers/net/wireless/cnss2/qmi.h7
-rw-r--r--drivers/net/wireless/cnss2/usb.c49
-rw-r--r--drivers/net/wireless/cnss2/wlan_firmware_service_v01.c18
-rw-r--r--drivers/net/wireless/cnss2/wlan_firmware_service_v01.h4
-rw-r--r--drivers/net/xen-netfront.c2
17 files changed, 487 insertions, 75 deletions
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 547098086773..f81df91a9ce1 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -52,5 +52,5 @@ config CAIF_VIRTIO
The caif driver for CAIF over Virtio.
if CAIF_VIRTIO
-source "drivers/vhost/Kconfig"
+source "drivers/vhost/Kconfig.vringh"
endif
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 2f9b12cf9ee5..61a9ab4fe047 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -1163,11 +1163,15 @@ out:
map_failed_frags:
last = i+1;
- for (i = 0; i < last; i++)
+ for (i = 1; i < last; i++)
dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address,
descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK,
DMA_TO_DEVICE);
+ dma_unmap_single(&adapter->vdev->dev,
+ descs[0].fields.address,
+ descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK,
+ DMA_TO_DEVICE);
map_failed:
if (!firmware_has_feature(FW_FEATURE_CMO))
netdev_err(netdev, "tx: unable to map xmit buffer\n");
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index 25a0ad5102d6..855cf8c15c8a 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -111,10 +111,14 @@ static int e1000e_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
ptp_clock_info);
unsigned long flags;
- u64 ns;
+ u64 cycles, ns;
spin_lock_irqsave(&adapter->systim_lock, flags);
- ns = timecounter_read(&adapter->tc);
+
+ /* Use timecounter_cyc2time() to allow non-monotonic SYSTIM readings */
+ cycles = adapter->cc.read(&adapter->cc);
+ ns = timecounter_cyc2time(&adapter->tc, cycles);
+
spin_unlock_irqrestore(&adapter->systim_lock, flags);
*ts = ns_to_timespec64(ns);
@@ -170,9 +174,12 @@ static void e1000e_systim_overflow_work(struct work_struct *work)
systim_overflow_work.work);
struct e1000_hw *hw = &adapter->hw;
struct timespec64 ts;
+ u64 ns;
- adapter->ptp_clock_info.gettime64(&adapter->ptp_clock_info, &ts);
+ /* Update the timecounter */
+ ns = timecounter_read(&adapter->tc);
+ ts = ns_to_timespec64(ns);
e_dbg("SYSTIM overflow check at %lld.%09lu\n",
(long long) ts.tv_sec, ts.tv_nsec);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 93543e176829..8f40e121f7d4 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -324,6 +324,8 @@ enum cfg_version {
};
static const struct pci_device_id rtl8169_pci_tbl[] = {
+ { PCI_VDEVICE(REALTEK, 0x2502), RTL_CFG_1 },
+ { PCI_VDEVICE(REALTEK, 0x2600), RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), 0, 0, RTL_CFG_1 },
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 111d907e0c11..79cede19e0c4 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2825,6 +2825,12 @@ static int hso_get_config_data(struct usb_interface *interface)
return -EIO;
}
+ /* check if we have a valid interface */
+ if (if_num > 16) {
+ kfree(config_data);
+ return -EINVAL;
+ }
+
switch (config_data[if_num]) {
case 0x0:
result = 0;
@@ -2895,10 +2901,18 @@ static int hso_probe(struct usb_interface *interface,
/* Get the interface/port specification from either driver_info or from
* the device itself */
- if (id->driver_info)
+ if (id->driver_info) {
+ /* if_num is controlled by the device, driver_info is a 0 terminated
+ * array. Make sure, the access is in bounds! */
+ for (i = 0; i <= if_num; ++i)
+ if (((u32 *)(id->driver_info))[i] == 0)
+ goto exit;
port_spec = ((u32 *)(id->driver_info))[if_num];
- else
+ } else {
port_spec = hso_get_config_data(interface);
+ if (port_spec < 0)
+ goto exit;
+ }
/* Check if we need to switch to alt interfaces prior to port
* configuration */
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index ec2b9c577b90..3644c9edaf81 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -616,7 +616,7 @@ struct b43_c32 b43_cordic(int theta)
u8 i;
s32 tmp;
s8 signx = 1;
- u32 angle = 0;
+ s32 angle = 0;
struct b43_c32 ret = { .i = 39797, .q = 0, };
while (theta > (180 << 16))
diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c
index 4587d4ef162f..0411f7eb4ea1 100644
--- a/drivers/net/wireless/cnss2/bus.c
+++ b/drivers/net/wireless/cnss2/bus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,8 @@ enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
if (memcmp(dev->bus->name, "pci", 3) == 0)
return CNSS_BUS_PCI;
+ else if (memcmp(dev->bus->name, "usb", 3) == 0)
+ return CNSS_BUS_USB;
else
return CNSS_BUS_NONE;
}
@@ -54,16 +56,6 @@ bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv)
return true;
}
-bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv)
-{
- bool ret = false;
-
- if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
- ret = true;
-
- return ret;
-}
-
void *cnss_bus_dev_to_bus_priv(struct device *dev)
{
if (!dev)
@@ -72,6 +64,8 @@ void *cnss_bus_dev_to_bus_priv(struct device *dev)
switch (cnss_get_dev_bus_type(dev)) {
case CNSS_BUS_PCI:
return cnss_get_pci_priv(to_pci_dev(dev));
+ case CNSS_BUS_USB:
+ return cnss_get_usb_priv(to_usb_interface(dev));
default:
return NULL;
}
diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h
index ff5f5a85469e..f9168c3ade93 100644
--- a/drivers/net/wireless/cnss2/bus.h
+++ b/drivers/net/wireless/cnss2/bus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -58,5 +58,4 @@ int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv,
int modem_current_status);
int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv);
bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv);
-bool cnss_bus_dev_cal_rep_valid(struct cnss_plat_data *plat_priv);
#endif /* _CNSS_BUS_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 76c360b5ce19..8bf7b76f4131 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -259,6 +259,9 @@ int cnss_wlan_enable(struct device *dev,
if (qmi_bypass)
return 0;
+ if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB)
+ goto skip_cfg;
+
if (!config || !host_version) {
cnss_pr_err("Invalid config or host_version pointer\n");
return -EINVAL;
@@ -559,13 +562,49 @@ out:
return ret;
}
-static int cnss_cal_update_hdlr(struct cnss_plat_data *plat_priv)
+static int caldb_mem_bounds_check(struct cnss_plat_data *plat_priv, void *data)
{
- /* QCN7605 store the cal data sent by FW to calDB memory area
- * get out of this after complete data is uploaded. FW is expected
- * to send cal done
- */
- return 0;
+ int ret = 0;
+ struct cnss_cal_data *cal_data = data;
+ u8 *end_ptr, *cal_data_ptr;
+ u32 total_size;
+
+ end_ptr = (u8 *)plat_priv->caldb_mem + QCN7605_CALDB_SIZE;
+ cal_data_ptr = (u8 *)plat_priv->caldb_mem + cal_data->index;
+ total_size = cal_data->total_size;
+
+ if (cal_data_ptr >= end_ptr || (cal_data_ptr + total_size) >= end_ptr) {
+ cnss_pr_err("caldb data offset or size error\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int cnss_cal_update_hdlr(struct cnss_plat_data *plat_priv, void *data)
+{
+ int ret = 0;
+
+ ret = caldb_mem_bounds_check(plat_priv, data);
+ if (ret)
+ CNSS_ASSERT(0);
+ else
+ cnss_wlfw_cal_update_req_send_sync(plat_priv, data);
+
+ return ret;
+}
+
+static int cnss_cal_download_hdlr(struct cnss_plat_data *plat_priv, void *data)
+{
+ int ret = 0;
+
+ ret = caldb_mem_bounds_check(plat_priv, data);
+ if (ret)
+ CNSS_ASSERT(0);
+ else
+ cnss_wlfw_cal_download_req_send_sync(plat_priv, data);
+
+ return ret;
}
static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
@@ -1154,11 +1193,6 @@ static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
goto out;
ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
- if (ret)
- goto out;
- /*cnss driver sends meta data report and waits for FW_READY*/
- if (cnss_bus_dev_cal_rep_valid(plat_priv))
- ret = cnss_wlfw_cal_report_send_sync(plat_priv);
}
out:
return ret;
@@ -1252,7 +1286,10 @@ static void cnss_driver_event_work(struct work_struct *work)
ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
break;
case CNSS_DRIVER_EVENT_CAL_UPDATE:
- ret = cnss_cal_update_hdlr(plat_priv);
+ ret = cnss_cal_update_hdlr(plat_priv, event->data);
+ break;
+ case CNSS_DRIVER_EVENT_CAL_DOWNLOAD:
+ ret = cnss_cal_download_hdlr(plat_priv, event->data);
break;
case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
@@ -1738,6 +1775,25 @@ static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
destroy_workqueue(plat_priv->event_wq);
}
+static int cnss_alloc_caldb_mem(struct cnss_plat_data *plat_priv)
+{
+ int ret = 0;
+
+ plat_priv->caldb_mem = vzalloc(QCN7605_CALDB_SIZE);
+ if (plat_priv->caldb_mem)
+ cnss_pr_dbg("600KB cal db alloc done caldb_mem %pK\n",
+ plat_priv->caldb_mem);
+ else
+ ret = -ENOMEM;
+
+ return ret;
+}
+
+static void cnss_free_caldb_mem(struct cnss_plat_data *plat_priv)
+{
+ vfree(plat_priv->caldb_mem);
+}
+
static const struct platform_device_id cnss_platform_id_table[] = {
{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
@@ -1833,6 +1889,12 @@ static int cnss_probe(struct platform_device *plat_dev)
if (ret)
goto deinit_qmi;
+ if (plat_priv->bus_type == CNSS_BUS_USB) {
+ ret = cnss_alloc_caldb_mem(plat_priv);
+ if (ret)
+ goto remove_debugfs;
+ }
+
setup_timer(&plat_priv->fw_boot_timer,
cnss_bus_fw_boot_timeout_hdlr, (unsigned long)plat_priv);
@@ -1850,6 +1912,8 @@ static int cnss_probe(struct platform_device *plat_dev)
return 0;
+remove_debugfs:
+ cnss_debugfs_destroy(plat_priv);
deinit_qmi:
cnss_qmi_deinit(plat_priv);
deinit_event_work:
@@ -1885,6 +1949,7 @@ static int cnss_remove(struct platform_device *plat_dev)
device_init_wakeup(&plat_dev->dev, false);
unregister_pm_notifier(&cnss_pm_notifier);
del_timer(&plat_priv->fw_boot_timer);
+ cnss_free_caldb_mem(plat_priv);
cnss_debugfs_destroy(plat_priv);
cnss_qmi_deinit(plat_priv);
cnss_event_work_deinit(plat_priv);
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index ec67d31ea945..28469dfc96af 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
CNSS_EVENT_UNINTERRUPTIBLE)
+#define QCN7605_CALDB_SIZE 614400
enum cnss_dev_bus_type {
CNSS_BUS_NONE = -1,
@@ -174,6 +175,11 @@ enum cnss_debug_quirks {
SKIP_RECOVERY,
};
+struct cnss_cal_data {
+ u32 index;
+ u32 total_size;
+};
+
struct cnss_plat_data {
struct platform_device *plat_dev;
void *bus_priv;
@@ -216,6 +222,7 @@ struct cnss_plat_data {
u32 diag_reg_read_mem_type;
u32 diag_reg_read_len;
u8 *diag_reg_read_buf;
+ void *caldb_mem;
bool cal_done;
};
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 427b42c871f3..8816a12f654a 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -699,6 +699,7 @@ int cnss_pci_dev_ramdump(struct cnss_pci_data *pci_priv)
break;
case QCA6290_EMULATION_DEVICE_ID:
case QCA6290_DEVICE_ID:
+ case QCN7605_DEVICE_ID:
ret = cnss_qca6290_ramdump(pci_priv);
break;
default:
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index 85701566c58c..30ac0cc9ad51 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,8 @@
#define MAX_BDF_FILE_NAME 11
#define DEFAULT_BDF_FILE_NAME "bdwlan.elf"
#define BDF_FILE_NAME_PREFIX "bdwlan.e"
+#define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b"
+#define DEFAULT_BIN_BDF_FILE_NAME "bdwlan.bin"
#ifdef CONFIG_CNSS2_DEBUG
static unsigned int qmi_timeout = 10000;
@@ -174,11 +176,13 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
req.bdf_support_valid = 1;
req.bdf_support = 1;
- req.m3_support_valid = 1;
- req.m3_support = 1;
+ if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_PCI) {
+ req.m3_support_valid = 1;
+ req.m3_support = 1;
- req.m3_cache_support_valid = 1;
- req.m3_cache_support = 1;
+ req.m3_cache_support_valid = 1;
+ req.m3_cache_support = 1;
+ }
req.cal_done_valid = 1;
req.cal_done = plat_priv->cal_done;
@@ -278,7 +282,83 @@ static int cnss_qmi_initiate_cal_update_ind_hdlr(
struct cnss_plat_data *plat_priv,
void *msg, unsigned int msg_len)
{
- return 0;
+ struct msg_desc ind_desc;
+ struct wlfw_initiate_cal_update_ind_msg_v01 ind_msg;
+ struct cnss_cal_data *data;
+ int ret = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ind_desc.msg_id = QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01;
+ ind_desc.max_msg_len = WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_initiate_cal_update_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ cnss_pr_err("Failed to decode initiate cal update ind, msg_len: %u, err = %d\n",
+ ret, msg_len);
+ goto qmi_fail;
+ }
+
+ if ((ind_msg.total_size > 0) && (ind_msg.cal_data_location_valid)) {
+ data->index = ind_msg.cal_data_location;
+ data->total_size = ind_msg.total_size;
+ cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_CAL_UPDATE,
+ 0, data);
+ goto out;
+ }
+
+qmi_fail:
+ kfree(data);
+out:
+ return ret;
+}
+
+static int cnss_qmi_initiate_cal_download_ind_hdlr(
+ struct cnss_plat_data *plat_priv,
+ void *msg, unsigned int msg_len)
+{
+ struct msg_desc ind_desc;
+ struct wlfw_initiate_cal_download_ind_msg_v01 ind_msg;
+ struct cnss_cal_data *data;
+ int ret = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ind_desc.msg_id = QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01;
+ ind_desc.max_msg_len =
+ WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN;
+ ind_desc.ei_array = wlfw_initiate_cal_download_ind_msg_v01_ei;
+
+ ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ if (ret < 0) {
+ cnss_pr_err("Failed to decode initiate cal download ind, msg_len: %u, err = %d\n",
+ ret, msg_len);
+ goto qmi_fail;
+ }
+
+ if ((ind_msg.total_size > 0) && (ind_msg.cal_data_location_valid)) {
+ data->index = ind_msg.cal_data_location;
+ data->total_size = ind_msg.total_size;
+ cnss_driver_event_post(plat_priv,
+ CNSS_DRIVER_EVENT_CAL_DOWNLOAD,
+ 0, data);
+
+ goto out;
+ }
+
+qmi_fail:
+ kfree(data);
+out:
+ return ret;
}
static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
@@ -500,6 +580,197 @@ out:
return ret;
}
+int cnss_wlfw_cal_download_req_send_sync(struct cnss_plat_data *plat_priv,
+ void *data)
+{
+ struct wlfw_cal_download_req_msg_v01 *req;
+ struct wlfw_cal_download_resp_msg_v01 resp;
+ struct cnss_cal_data *cal_data = data;
+ struct msg_desc req_desc, resp_desc;
+ unsigned int remaining;
+ u8 *cal_data_read_ptr;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending cal download request message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+
+ req_desc.max_msg_len = WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_CAL_DOWNLOAD_REQ_V01;
+ req_desc.ei_array = wlfw_cal_download_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_CAL_DOWNLOAD_RESP_V01;
+ resp_desc.ei_array = wlfw_cal_download_resp_msg_v01_ei;
+
+ req->valid = true;
+ req->file_id_valid = false;
+ req->seg_id_valid = true;
+ req->seg_id = 0;
+ req->data_valid = true;
+ req->end_valid = true;
+ req->total_size_valid = true;
+ req->total_size = cal_data->total_size;
+
+ req->cal_data_location_valid = true;
+ req->cal_data_location = cal_data->index;
+ cal_data_read_ptr = (u8 *)plat_priv->caldb_mem +
+ cal_data->index;
+ cnss_pr_dbg("cal_data_read_ptr %pK\n", cal_data_read_ptr);
+ remaining = cal_data->total_size;
+
+ while (remaining) {
+ if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+ } else {
+ req->data_len = remaining;
+ req->end = true;
+ }
+
+ memcpy(req->data, cal_data_read_ptr, req->data_len);
+ cnss_pr_dbg("remaining %u data_len %u, seg_id %u, read_ptr %pK\n",
+ remaining, req->data_len, req->seg_id,
+ cal_data_read_ptr);
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc,
+ req, sizeof(*req), &resp_desc, &resp,
+ sizeof(resp), QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send cal download request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("cal download request failed, result: %d, err: %d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ goto out;
+ }
+
+ remaining -= req->data_len;
+ cal_data_read_ptr += req->data_len;
+ req->seg_id++;
+ }
+
+out:
+ kfree(req);
+ kfree(data);
+ if (ret)
+ CNSS_ASSERT(0);
+ return ret;
+}
+
+int cnss_wlfw_cal_update_req_send_sync(struct cnss_plat_data *plat_priv,
+ void *data)
+{
+ struct wlfw_cal_update_req_msg_v01 req;
+ struct wlfw_cal_update_resp_msg_v01 *resp = NULL;
+ struct cnss_cal_data *cal_data = data;
+ struct msg_desc req_desc, resp_desc;
+ unsigned int remaining, data_len;
+ u8 *cal_data_write_ptr;
+ bool end = false;
+ int ret = 0;
+
+ cnss_pr_dbg("Sending cal update request message, state: 0x%lx\n",
+ plat_priv->driver_state);
+
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(resp, 0, sizeof(*resp));
+
+ req_desc.max_msg_len = WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_CAL_UPDATE_REQ_V01;
+ req_desc.ei_array = wlfw_cal_update_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_CAL_UPDATE_RESP_V01;
+ resp_desc.ei_array = wlfw_cal_update_resp_msg_v01_ei;
+
+ req.cal_id = 0;
+ req.seg_id = 0;
+ cal_data_write_ptr = (u8 *)plat_priv->caldb_mem +
+ cal_data->index;
+ remaining = cal_data->total_size;
+
+ while (remaining) {
+ if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+ data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+ } else {
+ data_len = remaining;
+ end = true;
+ }
+
+ cnss_pr_dbg("remaining %u data_len %u, seg_id %u\n",
+ remaining, data_len, req.seg_id);
+
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc,
+ &req, sizeof(req), &resp_desc, resp,
+ sizeof(*resp), QMI_WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ cnss_pr_err("Failed to send cal update request, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+ cnss_pr_err("cal update request failed, result: %d, err: %d\n",
+ resp->resp.result, resp->resp.error);
+ ret = resp->resp.result;
+ goto out;
+ }
+
+ if (!resp->data_valid || resp->data_len != data_len) {
+ cnss_pr_err("cal update read data is invalid, data_valid = %u, data_len = %u\n",
+ resp->data_valid, resp->data_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!resp->seg_id_valid || resp->seg_id != req.seg_id) {
+ cnss_pr_err("seg_id invalid, valid = %u, seg_id = %u, req seg id =%u\n",
+ resp->seg_id_valid, resp->seg_id,
+ req.seg_id);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (resp->end_valid && resp->end) {
+ cnss_pr_dbg("cal update end valid =%u end = %u\n",
+ resp->end_valid, resp->end);
+ /*one valid cal data is available with host*/
+ plat_priv->cal_done = true;
+ }
+
+ memcpy(cal_data_write_ptr, resp->data, resp->data_len);
+ cnss_pr_dbg("cal updated resp->data_len %u\n", resp->data_len);
+ remaining -= resp->data_len;
+ cal_data_write_ptr += resp->data_len;
+ req.seg_id++;
+
+ memset(resp, 0, sizeof(*resp));
+ }
+
+out:
+ kfree(resp);
+ kfree(data);
+ if (ret)
+ CNSS_ASSERT(0);
+ return ret;
+}
+
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
{
struct wlfw_bdf_download_req_msg_v01 *req;
@@ -510,6 +781,7 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
const u8 *temp;
unsigned int remaining;
int ret = 0;
+ enum cnss_bdf_type bdf_type = CNSS_BDF_ELF;
cnss_pr_dbg("Sending BDF download message, state: 0x%lx\n",
plat_priv->driver_state);
@@ -520,12 +792,28 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
goto out;
}
+ if (plat_priv->device_id == QCN7605_DEVICE_ID ||
+ plat_priv->device_id == QCN7605_COMPOSITE_DEVICE_ID ||
+ plat_priv->device_id == QCN7605_STANDALONE_DEVICE_ID)
+ bdf_type = CNSS_BDF_BIN;
+
if (plat_priv->board_info.board_id == 0xFF)
- snprintf(filename, sizeof(filename), DEFAULT_BDF_FILE_NAME);
- else
- snprintf(filename, sizeof(filename),
- BDF_FILE_NAME_PREFIX "%02x",
- plat_priv->board_info.board_id);
+ if (bdf_type == CNSS_BDF_BIN)
+ snprintf(filename, sizeof(filename),
+ DEFAULT_BIN_BDF_FILE_NAME);
+ else
+ snprintf(filename, sizeof(filename),
+ DEFAULT_BDF_FILE_NAME);
+ else {
+ if (bdf_type == CNSS_BDF_BIN)
+ snprintf(filename, sizeof(filename),
+ BIN_BDF_FILE_NAME_PREFIX "%02x",
+ plat_priv->board_info.board_id);
+ else
+ snprintf(filename, sizeof(filename),
+ BDF_FILE_NAME_PREFIX "%02x",
+ plat_priv->board_info.board_id);
+ }
if (bdf_bypass) {
cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n");
@@ -566,7 +854,7 @@ bypass_bdf:
req->data_valid = 1;
req->end_valid = 1;
req->bdf_type_valid = 1;
- req->bdf_type = CNSS_BDF_ELF;
+ req->bdf_type = bdf_type;
if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
@@ -953,11 +1241,6 @@ out:
return ret;
}
-int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv)
-{
- return 0;
-}
-
static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
@@ -997,6 +1280,10 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
case QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01:
cnss_qmi_initiate_cal_update_ind_hdlr(plat_priv, msg, msg_len);
break;
+ case QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01:
+ cnss_qmi_initiate_cal_download_ind_hdlr(plat_priv,
+ msg, msg_len);
+ break;
default:
cnss_pr_err("Invalid QMI WLFW indication, msg_id: 0x%x\n",
msg_id);
diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h
index c6a1e6733505..f11e19ead482 100644
--- a/drivers/net/wireless/cnss2/qmi.h
+++ b/drivers/net/wireless/cnss2/qmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,5 +37,8 @@ int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
u32 data_len, u8 *data);
int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
u8 fw_log_mode);
-int cnss_wlfw_cal_report_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_cal_update_req_send_sync(struct cnss_plat_data *plat_priv,
+ void *data);
+int cnss_wlfw_cal_download_req_send_sync(struct cnss_plat_data *plat_priv,
+ void *data);
#endif /* _CNSS_QMI_H */
diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c
index 70aba70757cf..ee9f21349c3f 100644
--- a/drivers/net/wireless/cnss2/usb.c
+++ b/drivers/net/wireless/cnss2/usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -71,6 +71,25 @@ void cnss_usb_wlan_unregister_driver(struct cnss_usb_wlan_driver *driver_ops)
}
EXPORT_SYMBOL(cnss_usb_wlan_unregister_driver);
+int cnss_usb_is_device_down(struct device *dev)
+{
+ struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+ struct cnss_usb_data *usb_priv;
+
+ if (!plat_priv) {
+ cnss_pr_err("plat_priv is NULL\n");
+ return -ENODEV;
+ }
+
+ usb_priv = plat_priv->bus_priv;
+ if (!usb_priv) {
+ cnss_pr_err("usb_priv is NULL\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cnss_usb_is_device_down);
+
int cnss_usb_register_driver_hdlr(struct cnss_usb_data *usb_priv,
void *data)
{
@@ -262,10 +281,6 @@ static void cnss_usb_remove(struct usb_interface *interface)
struct cnss_usb_data *usb_priv = plat_priv->bus_priv;
cnss_pr_dbg("driver state %lu\n", plat_priv->driver_state);
- if (usb_priv->driver_ops) {
- cnss_pr_dbg("driver_op remove called for USB\n");
- usb_priv->driver_ops->remove(usb_priv->usb_intf);
- }
cnss_unregister_ramdump(plat_priv);
cnss_unregister_subsys(plat_priv);
usb_priv->plat_priv = NULL;
@@ -282,14 +297,11 @@ static int cnss_usb_suspend(struct usb_interface *interface, pm_message_t state)
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
usb_priv = plat_priv->bus_priv;
- if (!usb_priv->driver_ops) {
- cnss_pr_err("driver_ops is NULL\n");
- ret = -EINVAL;
- goto out;
- }
- ret = usb_priv->driver_ops->suspend(usb_priv->usb_intf,
- state);
-out:
+ if (usb_priv->driver_ops)
+ ret = usb_priv->driver_ops->suspend(usb_priv->usb_intf, state);
+ else
+ cnss_pr_dbg("driver_ops is NULL\n");
+
return ret;
}
@@ -300,14 +312,11 @@ static int cnss_usb_resume(struct usb_interface *interface)
struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
usb_priv = plat_priv->bus_priv;
- if (!usb_priv->driver_ops) {
- cnss_pr_err("driver_ops is NULL\n");
- ret = -EINVAL;
- goto out;
- }
- ret = usb_priv->driver_ops->resume(usb_priv->usb_intf);
+ if (usb_priv->driver_ops)
+ ret = usb_priv->driver_ops->resume(usb_priv->usb_intf);
+ else
+ cnss_pr_dbg("driver_ops is NULL\n");
-out:
return ret;
}
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
index be66fd626095..51358bdc9303 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -2428,6 +2428,24 @@ struct elem_info wlfw_host_cap_req_msg_v01_ei[] = {
mem_cfg_mode),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_duration_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u16),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1D,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_duration),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.tlv_type = QMI_COMMON_TLV_TYPE,
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
index c264373518b0..959c7d11b34a 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -625,9 +625,11 @@ struct wlfw_host_cap_req_msg_v01 {
u32 mem_bucket;
u8 mem_cfg_mode_valid;
u8 mem_cfg_mode;
+ u8 cal_duration_valid;
+ u16 cal_duration;
};
-#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 194
extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
struct wlfw_host_cap_resp_msg_v01 {
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 0a4bd73caae5..6f55ab4f7959 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -889,7 +889,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) {
unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
- BUG_ON(pull_to <= skb_headlen(skb));
+ BUG_ON(pull_to < skb_headlen(skb));
__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
}
if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {