diff options
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/caif/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/ibm/ibmveth.c | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/e1000e/ptp.c | 13 | ||||
| -rw-r--r-- | drivers/net/ethernet/realtek/r8169.c | 2 | ||||
| -rw-r--r-- | drivers/net/usb/hso.c | 18 | ||||
| -rw-r--r-- | drivers/net/wireless/b43/phy_common.c | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/bus.c | 16 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/bus.h | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/main.c | 89 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/main.h | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/pci.c | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/qmi.c | 321 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/qmi.h | 7 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/usb.c | 49 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/wlan_firmware_service_v01.c | 18 | ||||
| -rw-r--r-- | drivers/net/wireless/cnss2/wlan_firmware_service_v01.h | 4 | ||||
| -rw-r--r-- | drivers/net/xen-netfront.c | 2 |
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)) { |
