Project import generated by Copybara. GitOrigin-RevId: a92375ebc2f1e14ddd0baf546636cf1edb5dac21
diff --git a/arch/arm/configs/ipq5018_sirocco_defconfig b/arch/arm/configs/ipq5018_sirocco_defconfig index 1d1cb53..26ef7e2 100644 --- a/arch/arm/configs/ipq5018_sirocco_defconfig +++ b/arch/arm/configs/ipq5018_sirocco_defconfig
@@ -4469,7 +4469,7 @@ # CONFIG_SQUASHFS_DECOMP_SINGLE is not set # CONFIG_SQUASHFS_DECOMP_MULTI is not set CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y -# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XATTR=y # CONFIG_SQUASHFS_ZLIB is not set # CONFIG_SQUASHFS_LZ4 is not set # CONFIG_SQUASHFS_LZO is not set
diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 33450fa..5b1387c 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
@@ -814,7 +814,7 @@ <0 309 1>, <0 310 1>, <0 311 1>, - <0 312 1>, + <0 334 1>, <0 313 1>, /* o_wcss_apps_intr[25] */ <0 314 1>, @@ -840,7 +840,7 @@ <0 332 1>, <0 333 1>, - <0 334 1>, + <0 312 1>, <0 335 1>, <0 336 1>, <0 337 1>,
diff --git a/arch/arm64/boot/dts/qcom/sirocco-p0.dts b/arch/arm64/boot/dts/qcom/sirocco-p0.dts index 6909b0d..cd7ec02 100644 --- a/arch/arm64/boot/dts/qcom/sirocco-p0.dts +++ b/arch/arm64/boot/dts/qcom/sirocco-p0.dts
@@ -421,6 +421,7 @@ &i2c_0 { pinctrl-0 = <&i2c_pins>; pinctrl-names = "default"; + force-dma-mode; status = "ok"; ina231: ina231@40 {
diff --git a/arch/arm64/configs/ipq5018_sirocco_defconfig b/arch/arm64/configs/ipq5018_sirocco_defconfig index 21ae20c..99fcac2 100644 --- a/arch/arm64/configs/ipq5018_sirocco_defconfig +++ b/arch/arm64/configs/ipq5018_sirocco_defconfig
@@ -4446,7 +4446,7 @@ # CONFIG_SQUASHFS_DECOMP_SINGLE is not set # CONFIG_SQUASHFS_DECOMP_MULTI is not set CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y -# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XATTR=y # CONFIG_SQUASHFS_ZLIB is not set # CONFIG_SQUASHFS_LZ4 is not set # CONFIG_SQUASHFS_LZO is not set
diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c index db6da21..74ad8bf 100644 --- a/drivers/hid/hid-bigbenff.c +++ b/drivers/hid/hid-bigbenff.c
@@ -191,7 +191,7 @@ static void bigben_worker(struct work_struct *work) struct bigben_device, worker); struct hid_field *report_field = bigben->report->field[0]; - if (bigben->removed) + if (bigben->removed || !report_field) return; if (bigben->work_led) {
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index 3f0ed6a..e19e2b5 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c
@@ -58,8 +58,12 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - + struct usb_interface *intf; + + if (!hid_is_usb(hdev)) + return rdesc; + + intf = to_usb_interface(hdev->dev.parent); if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { /* Change usage maximum and logical maximum from 0x7fff to * 0x2fff, so they don't exceed HID_MAX_USAGES */
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c index 902a60e..8c895c8 100644 --- a/drivers/hid/hid-corsair.c +++ b/drivers/hid/hid-corsair.c
@@ -553,7 +553,12 @@ static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id) int ret; unsigned long quirks = id->driver_data; struct corsair_drvdata *drvdata; - struct usb_interface *usbif = to_usb_interface(dev->dev.parent); + struct usb_interface *usbif; + + if (!hid_is_usb(dev)) + return -EINVAL; + + usbif = to_usb_interface(dev->dev.parent); drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata), GFP_KERNEL);
diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index dae1937..0e8f424 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c
@@ -50,7 +50,7 @@ struct elan_drvdata { static int is_not_elan_touchpad(struct hid_device *hdev) { - if (hdev->bus == BUS_USB) { + if (hid_is_usb(hdev)) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); return (intf->altsetting->desc.bInterfaceNumber !=
diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 0d22713..2876cb6 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c
@@ -229,6 +229,9 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id) struct elo_priv *priv; int ret; + if (!hid_is_usb(hdev)) + return -EINVAL; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c index 0a38e8e..403506b 100644 --- a/drivers/hid/hid-holtek-kbd.c +++ b/drivers/hid/hid-holtek-kbd.c
@@ -140,12 +140,17 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type, static int holtek_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id) { - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - int ret = hid_parse(hdev); + struct usb_interface *intf; + int ret; + if (!hid_is_usb(hdev)) + return -EINVAL; + + ret = hid_parse(hdev); if (!ret) ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + intf = to_usb_interface(hdev->dev.parent); if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) { struct hid_input *hidinput; list_for_each_entry(hidinput, &hdev->inputs, list) {
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c index 195b735..b7172c4 100644 --- a/drivers/hid/hid-holtek-mouse.c +++ b/drivers/hid/hid-holtek-mouse.c
@@ -62,6 +62,14 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } +static int holtek_mouse_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + if (!hid_is_usb(hdev)) + return -EINVAL; + return 0; +} + static const struct hid_device_id holtek_mouse_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) }, @@ -83,6 +91,7 @@ static struct hid_driver holtek_mouse_driver = { .name = "holtek_mouse", .id_table = holtek_mouse_devices, .report_fixup = holtek_mouse_report_fixup, + .probe = holtek_mouse_probe, }; module_hid_driver(holtek_mouse_driver);
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 0dc7cdf..2c7e7c0 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c
@@ -769,12 +769,18 @@ static int lg_raw_event(struct hid_device *hdev, struct hid_report *report, static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) { - struct usb_interface *iface = to_usb_interface(hdev->dev.parent); - __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber; + struct usb_interface *iface; + __u8 iface_num; unsigned int connect_mask = HID_CONNECT_DEFAULT; struct lg_drv_data *drv_data; int ret; + if (!hid_is_usb(hdev)) + return -EINVAL; + + iface = to_usb_interface(hdev->dev.parent); + iface_num = iface->cur_altsetting->desc.bInterfaceNumber; + /* G29 only work with the 1st interface */ if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) && (iface_num != 0)) {
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 54d811f..f3cdb19 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c
@@ -1680,7 +1680,7 @@ static int logi_dj_probe(struct hid_device *hdev, case recvr_type_27mhz: no_dj_interfaces = 2; break; case recvr_type_bluetooth: no_dj_interfaces = 2; break; } - if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) { + if (hid_is_usb(hdev)) { intf = to_usb_interface(hdev->dev.parent); if (intf && intf->altsetting->desc.bInterfaceNumber >= no_dj_interfaces) {
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 2666af0..e4e9471 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c
@@ -798,12 +798,18 @@ static int pk_raw_event(struct hid_device *hdev, struct hid_report *report, static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + struct usb_interface *intf; + unsigned short ifnum; unsigned long quirks = id->driver_data; struct pk_device *pk; struct pcmidi_snd *pm = NULL; + if (!hid_is_usb(hdev)) + return -EINVAL; + + intf = to_usb_interface(hdev->dev.parent); + ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + pk = kzalloc(sizeof(*pk), GFP_KERNEL); if (pk == NULL) { hid_err(hdev, "can't alloc descriptor\n");
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c index ffcd444..4b18e1a 100644 --- a/drivers/hid/hid-roccat-arvo.c +++ b/drivers/hid/hid-roccat-arvo.c
@@ -344,6 +344,9 @@ static int arvo_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c index ce5f225..e95d59c 100644 --- a/drivers/hid/hid-roccat-isku.c +++ b/drivers/hid/hid-roccat-isku.c
@@ -324,6 +324,9 @@ static int isku_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 509b9bb..6cf59b5 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c
@@ -749,6 +749,9 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id) { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 0316edf..1896c69 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c
@@ -431,6 +431,9 @@ static int koneplus_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c index 5248b3c..cf8eeb3 100644 --- a/drivers/hid/hid-roccat-konepure.c +++ b/drivers/hid/hid-roccat-konepure.c
@@ -133,6 +133,9 @@ static int konepure_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 9600128..6fb9b95 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -501,6 +501,9 @@ static int kovaplus_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c index 4a88a76..d5ddf0d 100644 --- a/drivers/hid/hid-roccat-lua.c +++ b/drivers/hid/hid-roccat-lua.c
@@ -160,6 +160,9 @@ static int lua_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 989927d..4fcc8e7 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c
@@ -449,6 +449,9 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id) { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-ryos.c b/drivers/hid/hid-roccat-ryos.c index 3956a6c..5bf1971 100644 --- a/drivers/hid/hid-roccat-ryos.c +++ b/drivers/hid/hid-roccat-ryos.c
@@ -141,6 +141,9 @@ static int ryos_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c index 818701f..a784bb4 100644 --- a/drivers/hid/hid-roccat-savu.c +++ b/drivers/hid/hid-roccat-savu.c
@@ -113,6 +113,9 @@ static int savu_probe(struct hid_device *hdev, { int retval; + if (!hid_is_usb(hdev)) + return -EINVAL; + retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c index 2e1c311..cf5992e 100644 --- a/drivers/hid/hid-samsung.c +++ b/drivers/hid/hid-samsung.c
@@ -152,6 +152,9 @@ static int samsung_probe(struct hid_device *hdev, int ret; unsigned int cmask = HID_CONNECT_DEFAULT; + if (!hid_is_usb(hdev)) + return -EINVAL; + ret = hid_parse(hdev); if (ret) { hid_err(hdev, "parse failed\n");
diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c index 95e0807..6f107e3 100644 --- a/drivers/hid/hid-u2fzero.c +++ b/drivers/hid/hid-u2fzero.c
@@ -286,7 +286,7 @@ static int u2fzero_probe(struct hid_device *hdev, unsigned int minor; int ret; - if (!hid_is_using_ll_driver(hdev, &usb_hid_driver)) + if (!hid_is_usb(hdev)) return -EINVAL; dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 8e9c9e6..4edb241 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c
@@ -164,6 +164,9 @@ static int uclogic_probe(struct hid_device *hdev, struct uclogic_drvdata *drvdata = NULL; bool params_initialized = false; + if (!hid_is_usb(hdev)) + return -EINVAL; + /* * libinput requires the pad interface to be on a different node * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index e80c812..ed4ede5 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c
@@ -841,8 +841,7 @@ int uclogic_params_init(struct uclogic_params *params, struct uclogic_params p = {0, }; /* Check arguments */ - if (params == NULL || hdev == NULL || - !hid_is_using_ll_driver(hdev, &usb_hid_driver)) { + if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) { rc = -EINVAL; goto cleanup; }
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index cd71e71..a54a177 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c
@@ -726,7 +726,7 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, * Skip the query for this type and modify defaults based on * interface number. */ - if (features->type == WIRELESS) { + if (features->type == WIRELESS && intf) { if (intf->cur_altsetting->desc.bInterfaceNumber == 0) features->device_type = WACOM_DEVICETYPE_WL_MONITOR; else @@ -2185,7 +2185,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { char *product_name = wacom->hdev->name; - if (hid_is_using_ll_driver(wacom->hdev, &usb_hid_driver)) { + if (hid_is_usb(wacom->hdev)) { struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(intf); product_name = dev->product; @@ -2416,6 +2416,9 @@ static void wacom_wireless_work(struct work_struct *work) wacom_destroy_battery(wacom); + if (!usbdev) + return; + /* Stylus interface */ hdev1 = usb_get_intfdata(usbdev->config->interface[1]); wacom1 = hid_get_drvdata(hdev1); @@ -2695,8 +2698,6 @@ static void wacom_mode_change_work(struct work_struct *work) static int wacom_probe(struct hid_device *hdev, const struct hid_device_id *id) { - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct usb_device *dev = interface_to_usbdev(intf); struct wacom *wacom; struct wacom_wac *wacom_wac; struct wacom_features *features; @@ -2731,8 +2732,14 @@ static int wacom_probe(struct hid_device *hdev, wacom_wac->hid_data.inputmode = -1; wacom_wac->mode_report = -1; - wacom->usbdev = dev; - wacom->intf = intf; + if (hid_is_usb(hdev)) { + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *dev = interface_to_usbdev(intf); + + wacom->usbdev = dev; + wacom->intf = intf; + } + mutex_init(&wacom->lock); INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work); INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3417f7d..65831d9 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c
@@ -280,6 +280,7 @@ struct qup_i2c_dev { void (*read_rx_fifo)(struct qup_i2c_dev *qup); /* function to write tags in tx fifo for i2c read transfer */ void (*write_rx_tags)(struct qup_i2c_dev *qup); + bool force_dma; }; static irqreturn_t qup_i2c_interrupt(int irq, void *dev) @@ -1529,8 +1530,8 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup, total_len += msgs[idx].len; } - if (!no_dma && qup->is_dma && - (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz)) { + if (!no_dma && qup->is_dma && (qup->force_dma || + (total_len > qup->out_fifo_sz || total_len > qup->in_fifo_sz))) { qup->use_dma = true; } else { qup->blk.is_tx_blk_mode = max_tx_len > qup->out_fifo_sz - @@ -1884,6 +1885,9 @@ static int qup_i2c_probe(struct platform_device *pdev) qup->in_blk_sz, qup->in_fifo_sz, qup->out_blk_sz, qup->out_fifo_sz); + qup->force_dma = of_property_read_bool(pdev->dev.of_node, + "force-dma-mode"); + i2c_set_adapdata(&qup->adap, qup); qup->adap.dev.parent = qup->dev; qup->adap.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 8a537fe..48784f8 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c
@@ -2107,8 +2107,6 @@ static int __init sec_key_init(struct device *dev) int err = 0; size_t dma_buf_size = 0; - dev = qdev; - sec_kobj = kobject_create_and_add("sec_key", NULL); if (!sec_kobj) { @@ -2329,8 +2327,6 @@ static int qtiapp_test(struct device *dev, void *input, if (!buf) { pr_err("Failed to allocate page\n"); return -ENOMEM; - } else { - printk("\n memory allocated at physical address 0x%x\n",dma_buf); } /*
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b569b05..8be4c50 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c
@@ -1653,32 +1653,32 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req) struct mmc_card *card = mq->card; struct mmc_host *host = card->host; blk_status_t error = BLK_STS_OK; - int retries = 0; do { u32 status; int err; + int retries = 0; - mmc_blk_rw_rq_prep(mqrq, card, 1, mq); + while (retries++ <= MMC_READ_SINGLE_RETRIES) { + mmc_blk_rw_rq_prep(mqrq, card, 1, mq); - mmc_wait_for_req(host, mrq); + mmc_wait_for_req(host, mrq); - err = mmc_send_status(card, &status); - if (err) - goto error_exit; - - if (!mmc_host_is_spi(host) && - !mmc_blk_in_tran_state(status)) { - err = mmc_blk_fix_state(card, req); + err = mmc_send_status(card, &status); if (err) goto error_exit; + + if (!mmc_host_is_spi(host) && + !mmc_blk_in_tran_state(status)) { + err = mmc_blk_fix_state(card, req); + if (err) + goto error_exit; + } + + if (!mrq->cmd->error) + break; } - if (mrq->cmd->error && retries++ < MMC_READ_SINGLE_RETRIES) - continue; - - retries = 0; - if (mrq->cmd->error || mrq->data->error || (!mmc_host_is_spi(host) &&
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 1bffe3f..1764069 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -89,7 +89,7 @@ bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) goto out; } - cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false); out: spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 11ed515..1415509 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -688,7 +688,7 @@ static int ath11k_config_irq_internal_pci(struct ath11k_base *ab) if (ret < 0) return ret; - vector = (i % num_vectors) + base_vector; + vector = (i % num_vectors); if (i >= ATH11K_EXT_IRQ_GRP_NUM_MAX) break;
diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index ce4a689..54c9b1b 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c
@@ -431,6 +431,11 @@ static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) ATH11K_MEMORY_STATS_DEC(ab, ce_rx_pipe, skb->truesize); + if (!ATH11K_SKB_RXCB(skb)->paddr) { + ath11k_warn(ab, "Invalid paddr in skb received in CE\n"); + continue; + } + dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr, max_nbytes, DMA_FROM_DEVICE); @@ -512,6 +517,11 @@ static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) if (!skb) continue; + if (!ATH11K_SKB_CB(skb)->paddr) { + ath11k_warn(ab, "Invalid padd in Tx skb in CE\n"); + continue; + } + dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); if ((!pipe->send_cb) || ab->hw_params.credit_flow) { @@ -622,6 +632,7 @@ ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) { struct ath11k_ce_ring *ce_ring; dma_addr_t base_addr; + unsigned long off; ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL); if (ce_ring == NULL) @@ -650,12 +661,13 @@ ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz) ce_ring->base_addr_ce_space_unaligned = base_addr; - ce_ring->base_addr_owner_space = PTR_ALIGN( - ce_ring->base_addr_owner_space_unaligned, + ce_ring->base_addr_ce_space = (dma_addr_t) ALIGN( + (unsigned long)ce_ring->base_addr_ce_space_unaligned, CE_DESC_RING_ALIGN); - ce_ring->base_addr_ce_space = ALIGN( - ce_ring->base_addr_ce_space_unaligned, - CE_DESC_RING_ALIGN); + off = (unsigned long)ce_ring->base_addr_ce_space - + (unsigned long)ce_ring->base_addr_ce_space_unaligned; + ce_ring->base_addr_owner_space = (void *) + ((unsigned long)ce_ring->base_addr_owner_space_unaligned + off); return ce_ring; } @@ -1007,8 +1019,8 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) dma_free_coherent(ab->dev, pipe->src_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->src_ring->base_addr_owner_space, - pipe->src_ring->base_addr_ce_space); + pipe->src_ring->base_addr_owner_space_unaligned, + pipe->src_ring->base_addr_ce_space_unaligned); ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc, pipe->src_ring->nentries * desc_sz + CE_DESC_RING_ALIGN); @@ -1021,8 +1033,8 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) dma_free_coherent(ab->dev, pipe->dest_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->dest_ring->base_addr_owner_space, - pipe->dest_ring->base_addr_ce_space); + pipe->dest_ring->base_addr_owner_space_unaligned, + pipe->dest_ring->base_addr_ce_space_unaligned); ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc, pipe->dest_ring->nentries * desc_sz + CE_DESC_RING_ALIGN); @@ -1036,8 +1048,8 @@ void ath11k_ce_free_pipes(struct ath11k_base *ab) dma_free_coherent(ab->dev, pipe->status_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->status_ring->base_addr_owner_space, - pipe->status_ring->base_addr_ce_space); + pipe->status_ring->base_addr_owner_space_unaligned, + pipe->status_ring->base_addr_ce_space_unaligned); ATH11K_MEMORY_STATS_DEC(ab, ce_ring_alloc, pipe->status_ring->nentries * desc_sz + CE_DESC_RING_ALIGN);
diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index c586847..a82285d 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h
@@ -141,7 +141,7 @@ struct ath11k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -151,7 +151,7 @@ struct ath11k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id;
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 00a5994..b5c4c1d 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -325,7 +326,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), .hw_ops = &ipq5018_ops, .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074, - .ring_mask = &ath11k_hw_ring_mask_ipq5018, + .ring_mask = &ath11k_hw_ring_mask_qcn6122, .regs = &ipq5018_regs, .m3_addr = ATH11K_QMI_IPQ5018_M3_DUMP_ADDRESS, .spectral_fft_sz = 2, @@ -363,7 +364,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .is_qdss_support = false, .max_tx_ring = 1, .wakeup_mhi = false, - .reo_status_poll = true, + .reo_status_poll = false, .cfr_support = true, .cfr_dma_hdr_size = sizeof(struct ath11k_cfir_dma_hdr), .cfr_num_stream_bufs = 255, @@ -389,7 +390,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), .hw_ops = &qcn6122_ops, .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122, - .ring_mask = &ath11k_hw_ring_mask_ipq5018, + .ring_mask = &ath11k_hw_ring_mask_qcn6122, .regs = &qcn6122_regs, .m3_addr = ATH11K_QMI_QCN6122_M3_DUMP_ADDRESS, .spectral_fft_sz = 2, @@ -427,7 +428,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .is_qdss_support = true, .max_tx_ring = 1, .wakeup_mhi = false, - .reo_status_poll = true, + .reo_status_poll = false, .cfr_support = true, .cfr_dma_hdr_size = sizeof(struct ath11k_cfir_dma_hdr), .cfr_num_stream_bufs = 255, @@ -899,7 +900,8 @@ int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd) ab->bd_api = 2; if (country_code && strlen(country_code) == 2) { - strcpy(cc, country_code); + memcpy(cc, country_code, 2); + cc[2] = 0; ath11k_country_str_tolower(cc); scnprintf(filename, sizeof(filename), "board-2-%s.bin", cc); @@ -1052,7 +1054,7 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) err_nss_tear: ath11k_nss_teardown(ab); err_dp_pdev_free: - ath11k_dp_pdev_free(ab); + ath11k_dp_pdev_free(ab, true); err_pdev_debug: ath11k_debugfs_pdev_destroy(ab); @@ -1070,7 +1072,7 @@ static void ath11k_core_pdev_destroy(struct ath11k_base *ab) ath11k_nss_set_enabled(ab, false); ath11k_hif_irq_disable(ab); - ath11k_dp_pdev_free(ab); + ath11k_dp_pdev_free(ab, true); ath11k_debugfs_pdev_destroy(ab); } @@ -1369,7 +1371,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) ath11k_spectral_deinit(ab); ath11k_thermal_unregister(ab); ath11k_hif_irq_disable(ab); - ath11k_dp_pdev_free(ab); + ath11k_dp_pdev_free(ab, false); ath11k_hif_stop(ab); ath11k_wmi_detach(ab); ath11k_dp_pdev_reo_cleanup(ab); @@ -1449,6 +1451,7 @@ static void ath11k_core_restart(struct work_struct *work) ath11k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); + complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); complete(&ar->peer_delete_done); complete(&ar->install_key_done);
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 09293d0..e135162 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -127,7 +127,7 @@ struct ath11k_skb_rxcb { bool is_last_msdu; bool is_continuation; bool is_mcbc; - bool is_eapol; + bool is_eapol_tkip; struct hal_rx_desc *rx_desc; u8 err_rel_src; u8 err_code; @@ -363,6 +363,8 @@ struct ath11k_vif { u32 tid_conf_changed[ATH11K_TID_MAX]; struct ath11k_tid_qos_config tid_cfg[ATH11K_TID_MAX]; u32 tids_rst; + u64 tbtt_offset; + struct work_struct update_bcn_template_work; DECLARE_BITMAP(free_groupidx_map, ATH11K_GROUP_KEYS_NUM_MAX); }; @@ -529,6 +531,7 @@ struct ath11k_sta { u64 tx_duration; u32 tx_rts_retry_count; u8 rssi_comb; + u32 tx_retry_count; struct ewma_avg_rssi avg_rssi; struct ath11k_htt_tx_stats *tx_stats; struct ath11k_rx_peer_stats *rx_stats; @@ -559,6 +562,7 @@ struct ath11k_sta { struct ewma_sta_per per; u64 fail_pkts; u64 succ_pkts; + u64 drop_pkts; u64 msdu_cnt[ATH11K_TID_MAX]; u64 mpdu_cnt[ATH11K_TID_MAX]; u64 ppdu_cnt[ATH11K_TID_MAX]; @@ -568,9 +572,11 @@ struct ath11k_sta { struct ewma_sta_ber ber; u64 succ_bytes; u64 fail_bytes; + u64 drop_bytes; /*bytes count for bit error rate computation*/ u32 ber_succ_bytes; u32 ber_fail_bytes; + u32 last_tx_pkt_bw; u8 sta_kickout; unsigned long sta_kickout_timeout; @@ -582,6 +588,9 @@ struct ath11k_sta { struct ath11k_per_peer_cfr_capture cfr_capture; #endif struct ath11k_smart_ant_sta *smart_ant_sta; + struct completion disassoc_comp; + bool tx_disassoc; + u32 bw_last; }; #define ATH11K_HALF_20MHZ_BW 10 @@ -802,10 +811,17 @@ struct ath11k_afc_info { u32 afc_wfa_version; bool is_6g_afc_expiry_event_received; bool is_6g_afc_power_event_received; + bool switch_to_lpi_indication_received; struct ath11k_afc_sp_reg_info *afc_reg_info; bool afc_regdom_configured; }; +enum mon_status_buf_done { + MON_STATUS_BUF_DONE = 0, + MON_STATUS_NO_BUF_DONE = 1, + MON_STATUS_BUF_DONE_NEXT = 2, +}; + struct ath11k { struct ath11k_base *ab; struct ath11k_pdev *pdev; @@ -845,9 +861,11 @@ struct ath11k { u32 max_tx_power; u32 txpower_limit_2g; u32 txpower_limit_5g; + u32 txpower_limit_6g; u32 txpower_scale; u32 power_scale; u32 chan_tx_pwr; + s32 chan_noise_floor; u32 num_stations; u32 max_num_stations; bool monitor_conf_enabled; @@ -972,11 +990,16 @@ struct ath11k { u32 chan_bw_interference_bitmap; bool awgn_intf_handling_in_prog; struct ath11k_rx_buf_id rx_buf_id; + u8 mgmt_retry_limit; /* fw pdev_stats can be requested by get_txpower mac ops too */ struct list_head fw_stats_pdevs; struct completion fw_stats_complete; bool fw_stats_done; + u16 rts_threshold[NUM_NL80211_IFTYPES]; + struct completion ani_status_event; + bool mon_status_skb_zero; + enum mon_status_buf_done mon_status_no_buf_done; }; struct ath11k_band_cap { @@ -1065,7 +1088,9 @@ struct ath11k_soc_dp_stats { u32 err_ring_pkts; u32 invalid_rbm; u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; + u32 rxdma_error_drop[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; + u32 reo_error_drop[HAL_REO_DEST_RING_ERROR_CODE_MAX]; u32 hal_reo_error[DP_REO_DST_RING_MAX]; struct ath11k_soc_dp_tx_err_stats tx_err; struct ath11k_dp_ring_bp_stats bp_stats; @@ -1159,6 +1184,18 @@ struct ath11k_base { struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS]; struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; + + /* + * The rhashtable containing struct ath11k_peer keyed by mac addr + * protected under ab->base_lock spin lock + */ + struct rhashtable *rhead_peer_addr; + struct rhashtable_params rhash_peer_addr_param; + + /* The rhashtable containing struct ath11k_peer keyed by id */ + struct rhashtable *rhead_peer_id; + struct rhashtable_params rhash_peer_id_param; + struct list_head peers; wait_queue_head_t peer_mapping_wq; u8 mac_addr[ETH_ALEN]; @@ -1256,6 +1293,8 @@ struct ath11k_base { struct mutex base_ast_lock; struct work_struct wmi_ast_work; struct list_head wmi_ast_list; + u32 napi_poll_budget; + bool gro_support_enabled; /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *));
diff --git a/drivers/net/wireless/ath/ath11k/debug_nss.c b/drivers/net/wireless/ath/ath11k/debug_nss.c index 74f2131..2899859 100644 --- a/drivers/net/wireless/ath/ath11k/debug_nss.c +++ b/drivers/net/wireless/ath/ath11k/debug_nss.c
@@ -11,6 +11,8 @@ #include "debug.h" #include "debug_nss.h" +extern struct dentry *debugfs_debug_infra; + static unsigned int debug_nss_fill_mpp_dump(struct ath11k_vif *arvif, char *buf, ssize_t size) { @@ -1007,16 +1009,17 @@ void ath11k_debugfs_nss_mesh_vap_create(struct ath11k_vif *arvif) void ath11k_debugfs_nss_soc_create(struct ath11k_base *ab) { - struct dentry *debugfs_dbg_infra; + if (debugfs_debug_infra) + return; - debugfs_dbg_infra = debugfs_create_dir("dbg_infra", debugfs_ath11k); + debugfs_debug_infra = debugfs_create_dir("dbg_infra", debugfs_ath11k); debugfs_create_file("links", 0200, - debugfs_dbg_infra, ab, + debugfs_debug_infra, ab, &fops_nss_links); debugfs_create_file("mpp_mode", 0600, - debugfs_dbg_infra, ab, + debugfs_debug_infra, ab, &fops_nss_mpp_mode); }
diff --git a/drivers/net/wireless/ath/ath11k/debug_smart_ant.c b/drivers/net/wireless/ath/ath11k/debug_smart_ant.c index 808f836..8fa98f2 100644 --- a/drivers/net/wireless/ath/ath11k/debug_smart_ant.c +++ b/drivers/net/wireless/ath/ath11k/debug_smart_ant.c
@@ -56,6 +56,12 @@ static ssize_t ath11k_write_sa_enable_ops(struct file *file, return count; mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + if (enable) { ret = ath11k_wmi_pdev_enable_smart_ant(ar, ATH11K_SMART_ANT_ENABLE, @@ -113,6 +119,14 @@ static ssize_t ath11k_write_sa_tx_ant(struct file *file, if (len < ATH11K_SA_TX_ANT_MIN_LEN) return -EINVAL; + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + mutex_unlock(&ar->conf_mutex); + buf[len] = '\0'; sptr = buf; for (i = 0; i < ETH_ALEN - 1; i++) { @@ -198,6 +212,11 @@ static ssize_t ath11k_write_sa_rx_ant(struct file *file, "Setting Rx antenna to %d\n", rxant); mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } ret = ath11k_wmi_pdev_set_rx_ant(ar, rxant); mutex_unlock(&ar->conf_mutex); @@ -245,6 +264,14 @@ static ssize_t ath11k_write_sa_train_info(struct file *file, char *token, *sptr; char buf[128]; + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + mutex_unlock(&ar->conf_mutex); + if (!ath11k_smart_ant_enabled(ar)) return -ENOTSUPP;
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 2562397..eb15353 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -17,6 +17,7 @@ #include "qmi.h" struct dentry *debugfs_ath11k; +struct dentry *debugfs_debug_infra; static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = { "REO2SW1_RING", @@ -258,9 +259,18 @@ static ssize_t ath11k_write_wmi_ctrl_path_stats(struct file *file, { struct ath11k_vif *arvif = file->private_data; struct wmi_ctrl_path_stats_cmd_param param = {0}; + struct ath11k *ar = arvif->ar; u8 buf[128] = {0}; int ret; + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + mutex_unlock(&ar->conf_mutex); + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count); if (ret < 0) { return ret; @@ -709,10 +719,19 @@ static ssize_t ath11k_write_ampdu_aggr_size(struct file *file, { struct ath11k_vif *arvif = file->private_data; struct ath11k_base *ab = arvif->ar->ab; + struct ath11k *ar = arvif->ar; unsigned int tx_aggr_size = 0; int ret; struct set_custom_aggr_size_params params = {0}; + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + mutex_unlock(&ar->conf_mutex); + if (kstrtouint_from_user(ubuf, count, 0, &tx_aggr_size)) return -EINVAL; @@ -1543,13 +1562,15 @@ static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file, soc_stats->invalid_rbm); len += scnprintf(buf + len, size - len, "RXDMA errors:\n"); for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++) - len += scnprintf(buf + len, size - len, "%s: %u\n", - rxdma_err[i], soc_stats->rxdma_error[i]); + len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n", + rxdma_err[i], soc_stats->rxdma_error[i], + soc_stats->rxdma_error_drop[i]); len += scnprintf(buf + len, size - len, "\nREO errors:\n"); for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++) - len += scnprintf(buf + len, size - len, "%s: %u\n", - reo_err[i], soc_stats->reo_error[i]); + len += scnprintf(buf + len, size - len, "%s: handled %u dropped %u\n", + reo_err[i], soc_stats->reo_error[i], + soc_stats->reo_error_drop[i]); len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n"); len += scnprintf(buf + len, size - len, @@ -2176,7 +2197,7 @@ static ssize_t ath11k_write_aggr_sw_retry_thold(struct file *file, goto exit; } - ret = ath11k_wmi_pdev_set_param(ar, ATH11K_AGGR_SW_RETRY_THRESHOLD, + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_AGG_SW_RETRY_TH, retry_thold, pdev->pdev_id); if (ret) { @@ -2268,6 +2289,12 @@ int ath11k_debugfs_pdev_create(struct ath11k_base *ab) debugfs_create_file("set_fw_recovery", 0600, ab->debugfs_soc, ab, &fops_fw_recovery); + debugfs_create_file("enable_memory_stats", 0600, ab->debugfs_soc, + ab, &fops_enable_memory_stats); + + debugfs_create_file("memory_stats", 0600, ab->debugfs_soc, ab, + &fops_memory_stats); + debugfs_create_file("ce_latency_stats", 0600, ab->debugfs_soc, ab, &fops_ce_latency_stats); debugfs_create_file("fw_dbglog_config", 0600, ab->debugfs_soc, ab, @@ -2342,6 +2369,7 @@ void ath11k_debugfs_destroy() { debugfs_remove_recursive(debugfs_ath11k); debugfs_ath11k = NULL; + debugfs_debug_infra = NULL; } void ath11k_debugfs_fw_stats_init(struct ath11k *ar) @@ -2654,12 +2682,6 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, } } - debugfs_create_file("enable_memory_stats", 0600, ab->debugfs_soc, - ab, &fops_enable_memory_stats); - - debugfs_create_file("memory_stats", 0600, ab->debugfs_soc, ab, - &fops_memory_stats); - #define HTT_RX_FILTER_TLV_LITE_MODE \ (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \ HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \ @@ -2765,6 +2787,12 @@ static ssize_t ath11k_write_simulate_radar(struct file *file, struct ath11k *ar = file->private_data; int ret; + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + ret = ath11k_wmi_simulate_radar(ar); if (ret) return ret; @@ -2848,10 +2876,6 @@ static ssize_t ath11k_write_btcoex(struct file *file, mutex_lock(&ar->conf_mutex); arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); - if (!arvif->is_started) { - ret = -EINVAL; - goto exit; - } if(coex == 1 && !test_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags)) set_bit(ATH11K_FLAG_BTCOEX, &ar->dev_flags); @@ -2941,11 +2965,6 @@ static ssize_t ath11k_write_btcoex_duty_cycle(struct file *file, mutex_lock(&ar->conf_mutex); arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); - if (!arvif->is_started) { - ret = -EINVAL; - goto exit; - } - coex_config.vdev_id = arvif->vdev_id; coex_config.config_type = WMI_COEX_CONFIG_AP_TDM; coex_config.duty_cycle = duty_cycle; @@ -3009,11 +3028,6 @@ static ssize_t ath11k_write_btcoex_algo(struct file *file, mutex_lock(&ar->conf_mutex); arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); - if (!arvif->is_started) { - ret = -EINVAL; - goto exit; - } - ar->coex.coex_algo_type = coex_algo; coex_config.vdev_id = arvif->vdev_id; coex_config.config_type = WMI_COEX_CONFIG_FORCED_ALGO; @@ -3198,6 +3212,12 @@ static ssize_t ath11k_write_ps_state_enable(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + ret = -ENETDOWN; + goto exit; + } + if (ar->ps_state_enable == ps_state_enable) { ret = count; goto exit; @@ -3464,6 +3484,14 @@ static ssize_t ath11k_athdiag_write(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + + mutex_unlock(&ar->conf_mutex); + buf = vmalloc(count); if (!buf) { ret = -ENOMEM; @@ -4345,11 +4373,35 @@ static ssize_t ath11k_read_ani_enable(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - int len = 0; - char buf[32]; + unsigned long time_left; + int ret; + int len; + char buf[128]; - len = scnprintf(buf, sizeof(buf) - len, "%d\n",ar->ani_enabled); + mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ret = -ENETDOWN; + goto unlock; + } + reinit_completion(&ar->ani_status_event); + ret = ath11k_wmi_pdev_get_ani_status(ar); + if (ret) { + ath11k_warn(ar->ab, "failed to get ani status: %d\n", ret); + goto unlock; + } + time_left = wait_for_completion_timeout(&ar->ani_status_event, + 1 * HZ); + if (time_left == 0) { + ret = -ETIMEDOUT; + goto unlock; + } + len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled); + mutex_unlock(&ar->conf_mutex); return simple_read_from_buffer(user_buf, count, ppos, buf, len); + +unlock: + mutex_unlock(&ar->conf_mutex); + return ret; } static ssize_t ath11k_write_ani_enable(struct file *file, @@ -4365,6 +4417,12 @@ static ssize_t ath11k_write_ani_enable(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d is not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + if (ar->ani_enabled == enable) { ret = count; goto exit; @@ -4376,7 +4434,9 @@ static ssize_t ath11k_write_ani_enable(struct file *file, ath11k_warn(ar->ab, "ani_enable failed from debugfs: %d\n", ret); goto exit; } + spin_lock_bh(&ar->data_lock); ar->ani_enabled = enable; + spin_unlock_bh(&ar->data_lock); ret = count; exit: @@ -4420,6 +4480,12 @@ static ssize_t ath11k_write_ani_poll_period(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ANI_POLL_PERIOD, ani_poll_period, ar->pdev->pdev_id); if (ret) { @@ -4470,6 +4536,12 @@ static ssize_t ath11k_write_ani_listen_period(struct file *file, mutex_lock(&ar->conf_mutex); + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, ani_listen_period, ar->pdev->pdev_id); if (ret) { @@ -4893,22 +4965,26 @@ static ssize_t ath11k_debugfs_write_rts_threshold(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - int rts_threshold, ret = 0; + int rts_threshold, ret = 0, vif_type; struct ath11k_vif *arvif; struct ieee80211_vif *vif; + char buf[128] = {0}; - ret = kstrtoint_from_user(user_buf, count, 0, &rts_threshold); - if (ret) + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (ret < 0) + return ret; + + ret = sscanf(buf, "%d %d", &rts_threshold, &vif_type); + if (ret || vif_type >= NUM_NL80211_IFTYPES) return ret; mutex_lock(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { vif = arvif->vif; - if (vif->type != NL80211_IFTYPE_MESH_POINT) { - ar->hw->wiphy->rts_threshold = rts_threshold; + if (vif->type == vif_type) { ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, WMI_VDEV_PARAM_RTS_THRESHOLD, - ar->hw->wiphy->rts_threshold); + rts_threshold); if (ret) { ath11k_warn(ar->ab, "Failed to set rts threshold for vdev %d: %d\n", @@ -4918,6 +4994,7 @@ static ssize_t ath11k_debugfs_write_rts_threshold(struct file *file, } } + ar->rts_threshold[vif_type] = rts_threshold; mutex_unlock(&ar->conf_mutex); return count; } @@ -4927,12 +5004,15 @@ static ssize_t ath11k_debugfs_read_rts_threshold(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - char buf[32] = {0}; - int len = 0; + char buf[2048] = {0}; + int len = 0, i; mutex_lock(&ar->conf_mutex); - len = scnprintf(buf, sizeof(buf) - len, "%d\n", - ar->hw->wiphy->rts_threshold); + len += scnprintf(buf, sizeof(buf) - len, "VIF type\tRTS threshold\n"); + for (i = 0; i < NUM_NL80211_IFTYPES; i++) { + if (ar->rts_threshold[i]) + len += scnprintf(buf + len, sizeof(buf) - len, "%d\t\t%d\n", i, ar->rts_threshold[i]); + } mutex_unlock(&ar->conf_mutex); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -5064,6 +5144,159 @@ static const struct file_operations fops_tx_wmi_mgmt = { .llseek = default_llseek, }; +static ssize_t ath11k_read_napi_poll_budget(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + int len = 0; + char buf[32]; + + len = scnprintf(buf, sizeof(buf) - len, "%u\n", ar->ab->napi_poll_budget); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_napi_poll_budget(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + int ret; + u32 napi_poll_budget = 0; + + if (kstrtou32_from_user(user_buf, count, 0, &napi_poll_budget)) + return -EINVAL; + + if(napi_poll_budget > NAPI_POLL_WEIGHT) + return -EINVAL; + + if(napi_poll_budget < 4) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->ab->napi_poll_budget = napi_poll_budget; + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_napi_poll_budget = { + .read = ath11k_read_napi_poll_budget, + .write = ath11k_write_napi_poll_budget, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath11k_read_gro_support(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + int len = 0; + char buf[32]; + + len = scnprintf(buf, sizeof(buf) - len, "%u\n", + ar->ab->gro_support_enabled); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_gro_support(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + int ret; + bool gro_support = false; + + if (kstrtobool_from_user(user_buf, count, &gro_support)) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->ab->gro_support_enabled = gro_support; + ret = count; + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_gro_support = { + .read = ath11k_read_gro_support, + .write = ath11k_write_gro_support, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath11k_write_mgmt_retry_limit(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + struct ath11k_pdev *pdev = ar->pdev; + u8 retry_limit; + int ret; + + if (kstrtou8_from_user(user_buf, count, 0, &retry_limit)) + return -EINVAL; + + if (retry_limit < ATH11K_MIN_MGMT_RETRY_LIMIT_COUNT || + retry_limit > ATH11K_MAX_MGMT_RETRY_LIMIT_COUNT) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + if (ar->mgmt_retry_limit == retry_limit) { + ret = count; + goto exit; + } + + if (ar->state != ATH11K_STATE_ON) { + ret = -ENETDOWN; + goto exit; + } + + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_MGMT_RETRY_LIMIT, + retry_limit, pdev->pdev_id); + + if (ret) { + ath11k_warn(ar->ab, "failed to set mgmt retry limit: %d\n", ret); + goto exit; + } + + ar->mgmt_retry_limit = retry_limit; + ret = count; + +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static ssize_t ath11k_read_mgmt_retry_limit(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + int len = 0; + char buf[8]; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "%d\n", + ar->mgmt_retry_limit); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_mgmt_retry_limit = { + .read = ath11k_read_mgmt_retry_limit, + .write = ath11k_write_mgmt_retry_limit, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath11k_debugfs_register(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -5106,8 +5339,9 @@ int ath11k_debugfs_register(struct ath11k *ar) ath11k_init_pktlog(ar); ath11k_smart_ant_debugfs_init(ar); init_completion(&ar->tpc_complete); - init_completion(&ab->ani_ofdm_event); - init_completion(&ab->ani_cck_event); + init_completion(&ab->ani_ofdm_event); + init_completion(&ab->ani_cck_event); + init_completion(&ar->ani_status_event); debugfs_create_file("ext_tx_stats", 0644, ar->debug.debugfs_pdev, ar, @@ -5137,6 +5371,12 @@ int ath11k_debugfs_register(struct ath11k *ar) debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar, &fops_ps_state_enable); + debugfs_create_file("napi_poll_budget", 0644, ar->debug.debugfs_pdev, ar, + &fops_napi_poll_budget); + + debugfs_create_file("gro_support_enabled", 0644, ar->debug.debugfs_pdev, + ar, &fops_gro_support); + if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT, ar->ab->wmi_ab.svc_map)) { debugfs_create_file("ps_timekeeper_enable", 0600, @@ -5207,6 +5447,9 @@ int ath11k_debugfs_register(struct ath11k *ar) debugfs_create_file("ftm_resp", 0600, ar->debug.debugfs_pdev, ar, &fops_ftm_resp); + debugfs_create_file("mgmt_retry_limit", 0600, + ar->debug.debugfs_pdev, + ar, &fops_mgmt_retry_limit); if (!ab->userpd_id) { debugfs_create_file("tx_wmi_mgmt", 0600,
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h index bb6ad4c..59d9f5b 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.h +++ b/drivers/net/wireless/ath/ath11k/debugfs.h
@@ -240,6 +240,9 @@ do { \ #define ATH11K_MAX_AGGR_RETRY_COUNT 255 #define ATH11K_AGGR_SW_RETRY_THRESHOLD 50 +#define ATH11K_MIN_MGMT_RETRY_LIMIT_COUNT 1 +#define ATH11K_MAX_MGMT_RETRY_LIMIT_COUNT 16 + #ifdef CONFIG_ATH11K_DEBUGFS int ath11k_debugfs_create(void); void ath11k_debugfs_destroy(void);
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index 19c03e0..c2dea31 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
@@ -6338,6 +6338,13 @@ static ssize_t ath11k_write_htt_stats_reset(struct file *file, return -E2BIG; mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) { + ath11k_warn(ar->ab, "pdev %d not in ON state\n", ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); + return -ENETDOWN; + } + cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET; cfg_params.cfg1 = 1 << (cfg_params.cfg0 + type); ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index 71201e7..2daa806 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -324,9 +324,6 @@ static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, [HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY] = "MEC notify pkt count"}; int idx; - if (!arsta->tx_stats || !arsta->wbm_tx_stats) - return -ENOENT; - buf = kzalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -334,6 +331,12 @@ static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); + + if (!arsta->tx_stats || !arsta->wbm_tx_stats) { + retval = -ENOENT; + goto end; + } + for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) { for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) { stats = &arsta->tx_stats->stats[k]; @@ -477,6 +480,12 @@ static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, mutex_unlock(&ar->conf_mutex); return retval; + +end: + spin_unlock_bh(&ar->data_lock); + mutex_unlock(&ar->conf_mutex); + kfree(buf); + return retval; } static const struct file_operations fops_tx_stats = { @@ -1287,15 +1296,18 @@ ath11k_dbg_sta_dump_driver_tx_pkts_flow(struct file *file, const int size = ATH11K_DRV_TX_STATS_SIZE; char *buf; - if (!arsta->tx_stats) - return -ENOENT; - buf = kzalloc(ATH11K_DRV_TX_STATS_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->ab->base_lock); + + if (!arsta->tx_stats) { + ret_val = -ENOENT; + goto end; + } + len += scnprintf(buf + len, size - len, "Tx packets inflow from mac80211: %u\n", atomic_read(&arsta->drv_tx_pkts.pkts_in)); @@ -1312,6 +1324,11 @@ ath11k_dbg_sta_dump_driver_tx_pkts_flow(struct file *file, mutex_unlock(&ar->conf_mutex); return ret_val; +end: + spin_unlock_bh(&ar->ab->base_lock); + mutex_unlock(&ar->conf_mutex); + kfree(buf); + return ret_val; } static const struct file_operations fops_driver_tx_pkts_flow = { @@ -1330,9 +1347,6 @@ static ssize_t ath11k_dbg_sta_reset_tx_stats(struct file *file, struct ath11k *ar = arsta->arvif->ar; int ret, reset; - if (!arsta->tx_stats || !arsta->wbm_tx_stats) - return -ENOENT; - ret = kstrtoint_from_user(buf, count, 0, &reset); if (ret) return ret; @@ -1341,6 +1355,12 @@ static ssize_t ath11k_dbg_sta_reset_tx_stats(struct file *file, return -EINVAL; spin_lock_bh(&ar->ab->base_lock); + + if (!arsta->tx_stats || !arsta->wbm_tx_stats) { + spin_unlock_bh(&ar->ab->base_lock); + return -ENOENT; + } + memset(arsta->tx_stats, 0, sizeof(*arsta->tx_stats)); atomic_set(&arsta->drv_tx_pkts.pkts_in, 0); atomic_set(&arsta->drv_tx_pkts.pkts_out, 0); @@ -1586,12 +1606,16 @@ static ssize_t ath11k_dbg_sta_read_htt_comm_stats(struct file *file, arsta->fail_pkts); len += scnprintf(buf + len, size - len, "succ_pkts : %llu\n", arsta->succ_pkts); + len += scnprintf(buf + len, size - len, "drop_pkts : %llu\n", + arsta->drop_pkts); len += scnprintf(buf + len, size - len, "PER : %lu\n", ewma_sta_per_read(&arsta->per)); len += scnprintf(buf + len, size - len, "fail_bytes : %llu\n", arsta->fail_bytes); len += scnprintf(buf + len, size - len, "succ_bytes : %llu\n", arsta->succ_bytes); + len += scnprintf(buf + len, size - len, "drop_bytes : %llu\n", + arsta->drop_bytes); len += scnprintf(buf + len, size - len, "BER : %lu\n", ewma_sta_ber_read(&arsta->ber)); @@ -1668,17 +1692,24 @@ static ssize_t ath11k_dbg_sta_read_tx_success_bytes(struct file *file, int len = 0, i, retval = 0; u64 total_succ_bytes; - if (!arsta->tx_stats || !arsta->wbm_tx_stats) { - ath11k_warn(ar->ab, "failed to get tx success bytes"); - return -EINVAL; - } - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); + if (!arsta->tx_stats || !arsta->wbm_tx_stats) { + ath11k_warn(ar->ab, "failed to get tx success bytes"); + retval = -EINVAL; + goto end; + } + stats = &arsta->tx_stats->stats[ATH11K_STATS_TYPE_SUCC]; + if (!stats) { + ath11k_warn(ar->ab, "Stats not present to read Tx success bytes\n"); + retval = -EINVAL; + goto end; + } + total_succ_bytes = stats->gi[ATH11K_COUNTER_TYPE_BYTES][0] + stats->gi[ATH11K_COUNTER_TYPE_BYTES][1] + stats->gi[ATH11K_COUNTER_TYPE_BYTES][2] + @@ -1697,6 +1728,11 @@ static ssize_t ath11k_dbg_sta_read_tx_success_bytes(struct file *file, mutex_unlock(&ar->conf_mutex); return retval; + +end: + spin_unlock_bh(&ar->data_lock); + mutex_unlock(&ar->conf_mutex); + return retval; } static const struct file_operations fops_tx_success_bytes = {
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index bcbc612..9879795 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -251,6 +251,8 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, int max_entries = ath11k_hal_srng_get_max_entries(ab, type); int ret; bool cached; + unsigned long off; + u8 align = HAL_RING_BASE_ALIGN; if (max_entries < 0 || entry_sz < 0) return -EINVAL; @@ -258,6 +260,9 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, if (num_entries > max_entries) num_entries = max_entries; + if (type == HAL_RXDMA_DIR_BUF) + align = HAL_RXDMA_DIR_BUF_RING_BASE_ALIGN; + /* Allocate the reo dst and tx completion rings from cacheable memory */ switch (type) { case HAL_REO_DST: @@ -273,7 +278,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, if (ath11k_nss_offload_enabled(ab)) cached = false; - ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1; + ring->size = (num_entries * entry_sz) + align - 1; if (!cached) { ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size, @@ -289,9 +294,10 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, ATH11K_MEMORY_STATS_INC(ab, dma_alloc, ring->size); - ring->vaddr = PTR_ALIGN(ring->vaddr_unaligned, HAL_RING_BASE_ALIGN); - ring->paddr = ring->paddr_unaligned + ((unsigned long)ring->vaddr - - (unsigned long)ring->vaddr_unaligned); + ring->paddr = (dma_addr_t) ALIGN((unsigned long)ring->paddr_unaligned, + align); + off = (unsigned long)ring->paddr - (unsigned long)ring->paddr_unaligned; + ring->vaddr = (u32 *) ((unsigned long)ring->vaddr_unaligned + off); params.ring_base_vaddr = ring->vaddr; params.ring_base_paddr = ring->paddr; @@ -390,27 +396,7 @@ static void ath11k_dp_handle_reo_status_timer(struct timer_list *timer) struct ath11k_dp *dp = from_timer(dp, timer, reo_status_timer); struct ath11k_base *ab = dp->ab; - spin_lock_bh(&dp->reo_cmd_lock); - dp->reo_status_timer_running = false; - spin_unlock_bh(&dp->reo_cmd_lock); - ath11k_dp_process_reo_status(ab); -} - -void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab) -{ - struct ath11k_dp *dp = &ab->dp; - - if (!ab->hw_params.reo_status_poll) - return; - - spin_lock_bh(&dp->reo_cmd_lock); - if (dp->reo_status_timer_running) { - spin_unlock_bh(&dp->reo_cmd_lock); - return; - } - dp->reo_status_timer_running = true; - spin_unlock_bh(&dp->reo_cmd_lock); mod_timer(&dp->reo_status_timer, jiffies + msecs_to_jiffies(ATH11K_REO_STATUS_POLL_TIMEOUT_MS)); @@ -424,7 +410,6 @@ static void ath11k_dp_stop_reo_status_timer(struct ath11k_base *ab) return; del_timer_sync(&dp->reo_status_timer); - dp->reo_status_timer_running = false; } static void ath11k_dp_init_reo_status_timer(struct ath11k_base *ab) @@ -436,6 +421,10 @@ static void ath11k_dp_init_reo_status_timer(struct ath11k_base *ab) timer_setup(&dp->reo_status_timer, ath11k_dp_handle_reo_status_timer, 0); + + /* Trigger reo status polling periodically */ + mod_timer(&dp->reo_status_timer, jiffies + + msecs_to_jiffies(ATH11K_REO_STATUS_POLL_TIMEOUT_MS)); } static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab) @@ -898,6 +887,10 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, int i = 0, j; int tot_work_done = 0; bool nss_offload; + int original_budget = budget; + + if (budget != ab->napi_poll_budget) + budget = ab->napi_poll_budget; /* Processing of offloaded rings are not required */ nss_offload = ath11k_nss_offload_enabled(ab); @@ -988,11 +981,14 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, /* TODO: Implement handler for other interrupts */ done: + // Don't call napi_complete_done() if there is more work to do + if (tot_work_done >= ab->napi_poll_budget) + tot_work_done = original_budget; return tot_work_done; } EXPORT_SYMBOL(ath11k_dp_service_srng); -void ath11k_dp_pdev_free(struct ath11k_base *ab) +void ath11k_dp_pdev_free(struct ath11k_base *ab, bool ureg_dbgfs) { struct ath11k *ar; int i; @@ -1002,7 +998,8 @@ void ath11k_dp_pdev_free(struct ath11k_base *ab) for (i = 0; i < ab->num_radios; i++) { ar = ab->pdevs[i].ar; ath11k_dp_rx_pdev_free(ab, i); - ath11k_debugfs_unregister(ar); + if (ureg_dbgfs) + ath11k_debugfs_unregister(ar); ath11k_dp_rx_pdev_mon_detach(ar); } } @@ -1057,7 +1054,7 @@ int ath11k_dp_pdev_alloc(struct ath11k_base *ab) return 0; err: - ath11k_dp_pdev_free(ab); + ath11k_dp_pdev_free(ab, true); return ret; } @@ -1243,6 +1240,7 @@ int ath11k_dp_alloc(struct ath11k_base *ab) for (i = 0; i < ab->hw_params.num_dscp_tid_map_tbl; i++) ath11k_hal_tx_set_dscp_tid_map(ab, i); + ab->napi_poll_budget = NAPI_POLL_WEIGHT; /* Init any SOC level resource for DP */ return 0;
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 46a9ad6..5dc9061 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -45,7 +45,7 @@ struct dp_rx_tid { #define DP_MON_PURGE_TIMEOUT_MS 100 #define DP_MON_SERVICE_BUDGET 128 -#define ATH11K_REO_STATUS_POLL_TIMEOUT_MS 10 +#define ATH11K_REO_STATUS_POLL_TIMEOUT_MS 50 struct dp_reo_cache_flush_elem { struct list_head list; @@ -307,7 +307,6 @@ struct ath11k_dp { /* reo status timer and flags */ struct timer_list reo_status_timer; - bool reo_status_timer_running; }; /* HTT definitions */ @@ -1960,7 +1959,7 @@ void ath11k_dp_free(struct ath11k_base *ab); int ath11k_dp_alloc(struct ath11k_base *ab); int ath11k_dp_pdev_alloc(struct ath11k_base *ab); void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab); -void ath11k_dp_pdev_free(struct ath11k_base *ab); +void ath11k_dp_pdev_free(struct ath11k_base *ab, bool ureg_dbgfs); int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, int mac_id, enum hal_ring_type ring_type); int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr); @@ -1985,6 +1984,5 @@ void ath11k_dp_shadow_init_timer(struct ath11k_base *ab, struct ath11k_hp_update_timer *update_timer, u32 interval, u32 ring_id); void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab); -void ath11k_dp_start_reo_status_timer(struct ath11k_base *ab); #endif
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 56f7ce6..6a8809c 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -434,12 +434,12 @@ int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, buf_id = buf_ids[buf_id_index]; idr_replace(&rx_ring->bufs_idr, skb, buf_id); } else { - buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0, - rx_ring->bufs_max * 3, GFP_ATOMIC); + buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 1, + (rx_ring->bufs_max * 3) + 1, GFP_ATOMIC); } spin_unlock_bh(&rx_ring->idr_lock); - if (buf_id < 0) + if (buf_id <= 0) goto fail_free_skb; desc = ath11k_hal_srng_src_get_next_entry(ab, srng); @@ -767,7 +767,7 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, } } -static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, +static int ath11k_dp_reo_cache_flush(struct ath11k_base *ab, struct dp_rx_tid *rx_tid) { struct ath11k_hal_reo_cmd cmd = {0}; @@ -786,8 +786,15 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, NULL); if (ret) ath11k_warn(ab, - "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n", - rx_tid->tid, ret); + "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d) desc_sz(%ld)\n", + rx_tid->tid, ret, desc_sz); + + /* If this fails with ring full condition, then + * no need to retry below as it is expected to + * fail within short time + */ + if (ret == -ENOBUFS) + goto exit; } memset(&cmd, 0, sizeof(cmd)); @@ -797,14 +804,12 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid, HAL_REO_CMD_FLUSH_CACHE, &cmd, ath11k_dp_reo_cmd_free); - if (ret) { + if (ret) ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n", rx_tid->tid, ret); - dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size, - DMA_BIDIRECTIONAL); - kfree(rx_tid->vaddr); - rx_tid->vaddr = NULL; - } + +exit: + return ret; } static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, @@ -843,13 +848,22 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD || time_after(jiffies, elem->ts + msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) { + spin_unlock_bh(&dp->reo_cmd_lock); + if (ath11k_dp_reo_cache_flush(ab, &elem->data)) { + /* In failure case, just update the timestamp + * for flush cache elem and continue + */ + spin_lock_bh(&dp->reo_cmd_lock); + elem->ts = jiffies + + msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS); + ath11k_err(ab, "Failed to send HAL_REO_CMD_FLUSH_CACHE cmd" + "Updating timestamp (%ld) in the list\n", elem->ts); + continue; + } + spin_lock_bh(&dp->reo_cmd_lock); list_del(&elem->list); dp->reo_cmd_cache_flush_count--; - spin_unlock_bh(&dp->reo_cmd_lock); - - ath11k_dp_reo_cache_flush(ab, &elem->data); kfree(elem); - spin_lock_bh(&dp->reo_cmd_lock); } } spin_unlock_bh(&dp->reo_cmd_lock); @@ -1573,95 +1587,96 @@ ath11k_update_per_peer_tx_stats(struct ath11k *ar, ru_start = user_rate->ru_start; ru_tone = user_rate->ru_end; - /* Note: If host configured fixed rates and in some other special - * cases, the broadcast/management frames are sent in different rates. - * Firmware rate's control to be skipped for this? - */ - - if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { - ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); - return; - } - - if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) { - ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); - return; - } - - if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) { - ath11k_warn(ab, "Invalid VHT mcs %d peer stats", mcs); - return; - } - - if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) { - ath11k_warn(ab, "Invalid HT mcs %d nss %d peer stats", - mcs, nss); - return; - } - - if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) { - ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, - flags, - &rate_idx, - &rate); - if (ret < 0) - return; - } - - rcu_read_lock(); - spin_lock_bh(&ab->base_lock); - peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id); - - if (!peer || !peer->sta) { - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); - return; - } - - sta = peer->sta; - arsta = (struct ath11k_sta *)sta->drv_priv; - - memset(&arsta->txrate, 0, sizeof(arsta->txrate)); - - switch (flags) { - case WMI_RATE_PREAMBLE_OFDM: - arsta->txrate.legacy = rate; - break; - case WMI_RATE_PREAMBLE_CCK: - arsta->txrate.legacy = rate; - break; - case WMI_RATE_PREAMBLE_HT: - arsta->txrate.mcs = mcs + 8 * (nss - 1); - arsta->txrate.flags = RATE_INFO_FLAGS_MCS; - if (sgi) - arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case WMI_RATE_PREAMBLE_VHT: - arsta->txrate.mcs = mcs; - arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; - if (sgi) - arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - break; - case WMI_RATE_PREAMBLE_HE: - arsta->txrate.mcs = mcs; - arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; - arsta->txrate.he_dcm = dcm; - arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); - arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc( - (user_rate->ru_end - - user_rate->ru_start) + 1); - break; - } - - arsta->txrate.nss = nss; - arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); - arsta->tx_duration += tx_duration; - memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); - /* PPDU stats reported for mgmt packet doesn't have valid tx bytes. * So skip peer stats update for mgmt packets. */ + if (tid < HTT_PPDU_STATS_NON_QOS_TID) { + /* Note: If host configured fixed rates and in some other special + * cases, the broadcast/management frames are sent in different rates. + * Firmware rate's control to be skipped for this? + */ + + if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { + ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); + return; + } + + if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH11K_HE_MCS_MAX) { + ath11k_warn(ab, "Invalid HE mcs %d peer stats", mcs); + return; + } + + if (flags == WMI_RATE_PREAMBLE_VHT && mcs > ATH11K_VHT_MCS_MAX) { + ath11k_warn(ab, "Invalid VHT mcs %d peer stats", mcs); + return; + } + + if (flags == WMI_RATE_PREAMBLE_HT && (mcs > ATH11K_HT_MCS_MAX || nss < 1)) { + ath11k_warn(ab, "Invalid HT mcs %d nss %d peer stats", + mcs, nss); + return; + } + + if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) { + ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, + flags, + &rate_idx, + &rate); + if (ret < 0) + return; + } + + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); + peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id); + + if (!peer || !peer->sta) { + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + return; + } + + sta = peer->sta; + arsta = (struct ath11k_sta *)sta->drv_priv; + + memset(&arsta->txrate, 0, sizeof(arsta->txrate)); + + switch (flags) { + case WMI_RATE_PREAMBLE_OFDM: + arsta->txrate.legacy = rate; + break; + case WMI_RATE_PREAMBLE_CCK: + arsta->txrate.legacy = rate; + break; + case WMI_RATE_PREAMBLE_HT: + arsta->txrate.mcs = mcs + 8 * (nss - 1); + arsta->txrate.flags = RATE_INFO_FLAGS_MCS; + if (sgi) + arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case WMI_RATE_PREAMBLE_VHT: + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; + if (sgi) + arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case WMI_RATE_PREAMBLE_HE: + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; + arsta->txrate.he_dcm = dcm; + arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi); + arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc( + (user_rate->ru_end - + user_rate->ru_start) + 1); + break; + } + + arsta->txrate.nss = nss; + arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); + arsta->tx_duration += tx_duration; + memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); + memset(peer_stats, 0, sizeof(*peer_stats)); peer_stats->succ_pkts = succ_pkts; peer_stats->succ_bytes = succ_bytes; @@ -1696,12 +1711,12 @@ ath11k_update_per_peer_tx_stats(struct ath11k *ar, if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); + + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); } usr_stats->rate_stats_updated = true; - - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); } static void ath11k_htt_update_ppdu_stats(struct ath11k *ar, @@ -2354,16 +2369,27 @@ static void ath11k_get_dot11_hdr_from_rx_desc(struct ath11k *ar, size_t hdr_len, crypto_len; struct ieee80211_hdr *hdr; u16 fc, qos_ctl = 0; + int expand_by; u8 *crypto_hdr; if (!(status->flag & RX_FLAG_IV_STRIPPED)) { crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype); + if (skb_headroom(msdu) < crypto_len) { + expand_by = crypto_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } crypto_hdr = skb_push(msdu, crypto_len); ath11k_dp_rx_desc_get_crypto_header(ab, rx_desc, crypto_hdr, enctype); } fc = ath11k_dp_rxdesc_get_mpdu_frame_ctrl(ab, rx_desc); hdr_len = ieee80211_hdrlen(fc); + if (skb_headroom(msdu) < hdr_len) { + expand_by = hdr_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } skb_push(msdu, hdr_len); hdr = (struct ieee80211_hdr *)msdu->data; hdr->frame_control = fc; @@ -2399,6 +2425,7 @@ static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar, u8 da[ETH_ALEN]; u8 sa[ETH_ALEN]; u16 qos_ctl = 0; + int expand_by = 0; u8 *qos, *crypto_hdr; bool add_qos_ctrl = false; @@ -2443,6 +2470,11 @@ static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar, } if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) { + expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } if (first_hdr) { memcpy(skb_push(msdu, ath11k_dp_rx_crypto_param_len(ar, enctype)), @@ -2456,13 +2488,28 @@ static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar, } if (!rxcb->is_first_msdu || add_qos_ctrl) { + if (skb_headroom(msdu) < IEEE80211_QOS_CTL_LEN) { + expand_by = IEEE80211_QOS_CTL_LEN - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, IEEE80211_QOS_CTL_LEN), &qos_ctl, IEEE80211_QOS_CTL_LEN); + if (skb_headroom(msdu) < hdr_len) { + expand_by = hdr_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, hdr_len), decap_hdr, hdr_len); return; } + if (skb_headroom(msdu) < hdr_len) { + expand_by = hdr_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); /* original 802.11 header has a different DA and in @@ -2571,6 +2618,7 @@ static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, u8 da[ETH_ALEN]; u8 sa[ETH_ALEN]; void *rfc1042; + int expand_by; struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); struct ath11k_dp_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}}; @@ -2580,6 +2628,11 @@ static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, ether_addr_copy(sa, eth->h_source); rfc.snap_type = eth->h_proto; skb_pull(msdu, sizeof(struct ethhdr)); + if (skb_headroom(msdu) < sizeof(struct ath11k_dp_rfc1042_hdr)) { + expand_by = sizeof(struct ath11k_dp_rfc1042_hdr) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), &rfc, sizeof(struct ath11k_dp_rfc1042_hdr)); ath11k_get_dot11_hdr_from_rx_desc(ar, msdu, rxcb, status, enctype); @@ -2597,6 +2650,11 @@ static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, skb_pull(msdu, sizeof(struct ethhdr)); /* push rfc1042/llc/snap */ + if (skb_headroom(msdu) < sizeof(struct ath11k_dp_rfc1042_hdr)) { + expand_by = sizeof(struct ath11k_dp_rfc1042_hdr) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042, sizeof(struct ath11k_dp_rfc1042_hdr)); @@ -2605,12 +2663,22 @@ static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar, hdr_len = ieee80211_hdrlen(hdr->frame_control); if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) { + expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, ath11k_dp_rx_crypto_param_len(ar, enctype)), (void *)hdr + hdr_len, ath11k_dp_rx_crypto_param_len(ar, enctype)); } + if (skb_headroom(msdu) < hdr_len) { + expand_by = hdr_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); exit: @@ -2631,6 +2699,7 @@ static void ath11k_dp_rx_h_undecap_snap(struct ath11k *ar, struct ieee80211_hdr *hdr; size_t hdr_len; u8 l3_pad_bytes; + int expand_by; struct hal_rx_desc *rx_desc; struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); @@ -2655,12 +2724,22 @@ static void ath11k_dp_rx_h_undecap_snap(struct ath11k *ar, hdr_len = ieee80211_hdrlen(hdr->frame_control); if (!(status->flag & RX_FLAG_IV_STRIPPED)) { + if (skb_headroom(msdu) < ath11k_dp_rx_crypto_param_len(ar, enctype)) { + expand_by = ath11k_dp_rx_crypto_param_len(ar, enctype) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, ath11k_dp_rx_crypto_param_len(ar, enctype)), (void *)hdr + hdr_len, ath11k_dp_rx_crypto_param_len(ar, enctype)); } + if (skb_headroom(msdu) < hdr_len) { + expand_by = hdr_len - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + return; + } memcpy(skb_push(msdu, hdr_len), hdr, hdr_len); } @@ -2689,11 +2768,14 @@ static void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu, case DP_RX_DECAP_TYPE_ETHERNET2_DIX: ehdr = (struct ethhdr *) msdu->data; - /* mac80211 allows fast path only for authorized STA */ - if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) { - ATH11K_SKB_RXCB(msdu)->is_eapol = true; + /* mac80211 allows fast path only for authorized STA and + also not supported for TKIP */ + if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE) || + enctype == HAL_ENCRYPT_TYPE_TKIP_MIC) { + ATH11K_SKB_RXCB(msdu)->is_eapol_tkip = true; ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr, enctype, status); + break; } /* PN for mcast packets will be validated in mac80211; @@ -2824,6 +2906,9 @@ static void ath11k_dp_rx_h_mpdu(struct ath11k *ar, /* PN for multicast packets will be checked in mac80211 */ rxcb = ATH11K_SKB_RXCB(msdu); + + rxcb->is_mcbc = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); + fill_crypto_hdr = rxcb->is_mcbc; if (rxcb->is_mcbc) { rxcb->seq_no = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); @@ -3047,11 +3132,17 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap u8 decap = DP_RX_DECAP_TYPE_RAW; int len; u8 index; + int expand_by; bool is_mcbc = rxcb->is_mcbc; - bool is_eapol = rxcb->is_eapol; + bool is_eapol_tkip = rxcb->is_eapol_tkip; if ((status->encoding == RX_ENC_HE) && !(status->flag & RX_FLAG_RADIOTAP_HE) && !(status->flag & RX_FLAG_SKIP_MONITOR)) { + if (skb_headroom(msdu) < sizeof(known)) { + expand_by = sizeof(known) - skb_headroom(msdu); + if (WARN_ON_ONCE(pskb_expand_head(msdu, expand_by, 0, GFP_ATOMIC))) + goto exit; + } he = skb_push(msdu, sizeof(known)); memcpy(he, &known, sizeof(known)); status->flag |= RX_FLAG_RADIOTAP_HE; @@ -3103,7 +3194,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap * Also, fast_rx expectes the STA to be authorized, hence * eapol packets are sent in slow path. */ - if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol && + if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol_tkip && !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) { rx_status->flag |= RX_FLAG_8023; goto exit; @@ -3285,13 +3376,13 @@ static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, int ret; bool fast_rx; LIST_HEAD(rx_list); + bool gro_support_enabled = ab->gro_support_enabled; if (skb_queue_empty(msdu_list)) return; rcu_read_lock(); - ar = ab->pdevs[mac_id].ar; if (unlikely(!rcu_dereference(ab->pdevs_active[mac_id]))) { __skb_queue_purge(msdu_list); @@ -3325,8 +3416,18 @@ static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, ath11k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_status, &rx_list); } - if (!fast_rx) - netif_receive_skb_list(&rx_list); + if (!fast_rx) { + struct sk_buff *skb, *tmp; + + if (napi && gro_support_enabled) { + list_for_each_entry_safe(skb, tmp, &rx_list, list) { + skb_list_del_init(skb); + napi_gro_receive(napi, skb); + } + } else { + netif_receive_skb_list(&rx_list); + } + } rcu_read_unlock(); } @@ -3397,6 +3498,17 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, ath11k_hal_srng_access_begin(ab, srng); while (likely(desc = (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, srng))) { + + push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, + desc->info0); + + if (unlikely(push_reason == + HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED)) { + ath11k_warn(ab,"Received invalid desc\n"); + ab->soc_stats.hal_reo_error[dp->reo_dst_ring[ring_id].ring_id]++; + continue; + } + cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, desc->buf_addr_info.info1); buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, @@ -3429,8 +3541,6 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, num_buffs_reaped[mac_id]++; - push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, - desc->info0); if (unlikely(push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { dev_kfree_skb_any(msdu); @@ -3569,12 +3679,15 @@ static void ath11k_dp_rx_update_peer_su_stats(struct ath11k *ar, { struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; u32 num_msdu; + u32 bw_offset; if (!rx_stats) return; + arsta->last_tx_pkt_bw = ppdu_info->bw; + bw_offset = arsta->last_tx_pkt_bw * 3; arsta->rssi_comb = ppdu_info->rssi_comb; - ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb); + ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb + bw_offset); if (!ath11k_debugfs_is_extd_rx_stats_enabled(ar)) return; @@ -3974,6 +4087,14 @@ dp_rx_mon_handle_status_buf_done(struct ath11k_base *ab, struct hal_srng *srng, return DP_MON_STATUS_NO_DMA; rxcb = ATH11K_SKB_RXCB(skb); + + if (!rxcb->paddr) { + ath11k_warn(ab, "Invalid paddr at SKB cb \n"); + } else if (paddr != rxcb->paddr) { + ath11k_warn(ab, "Invalid desc and skb fetch %pad rxcb %pad rbm %u cookie %u\n", + &paddr, &(rxcb->paddr), rbm, cookie); + } + dma_sync_single_for_cpu(ab->dev, rxcb->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -4017,6 +4138,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, ath11k_hal_srng_access_begin(ab, srng); while (*budget) { *budget -= 1; + ar->mon_status_no_buf_done = MON_STATUS_BUF_DONE; rx_mon_status_desc = ath11k_hal_srng_src_peek(ab, srng); if (!rx_mon_status_desc) { pmon->mon_status_buf_state = DP_MON_STATUS_REPLINISH; @@ -4046,6 +4168,18 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, rxcb = ATH11K_SKB_RXCB(skb); + if (ar->mon_status_skb_zero) { + ath11k_warn(ab, "Previous mon status skb zero \n"); + ar->mon_status_skb_zero = false; + } + + if (!rxcb->paddr) { + ath11k_warn(ab, "NULL paddr at SKB cb \n"); + } else if (paddr != rxcb->paddr) { + ath11k_warn(ab, "paddr mismatch desc %pad rxcb %pad rbm-%u cookie %u\n", + &paddr, &(rxcb->paddr), rbm, cookie); + } + dma_sync_single_for_cpu(ab->dev, rxcb->paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -4054,6 +4188,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_STATUS_BUFFER_DONE) { + ar->mon_status_no_buf_done = MON_STATUS_NO_BUF_DONE; /* RxDMA status done bit might not be set even * though tp is moved by HW. */ @@ -4075,6 +4210,7 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, if (reap_status == DP_MON_STATUS_NO_DMA) { continue; } else if (reap_status == DP_MON_STATUS_REPLINISH) { + ar->mon_status_no_buf_done = MON_STATUS_BUF_DONE_NEXT; ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n", FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl), buf_id); @@ -4117,6 +4253,9 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, &buf_id); if (!skb) { + ath11k_warn(ab, "failed to allocate skb no buf done %d\n", + ar->mon_status_no_buf_done); + ar->mon_status_skb_zero = true; ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0, HAL_RX_BUF_RBM_SW3_BM); num_buffs_reaped++; @@ -5148,8 +5287,6 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); bool drop = false; - ar->ab->soc_stats.reo_error[rxcb->err_code]++; - switch (rxcb->err_code) { case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO: if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list)) @@ -5169,10 +5306,15 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu, break; } + if (drop) + ar->ab->soc_stats.reo_error_drop[rxcb->err_code]++; + else + ar->ab->soc_stats.reo_error[rxcb->err_code]++; + return drop; } -static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, +static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, struct ieee80211_rx_status *status) { u16 msdu_len; @@ -5186,6 +5328,14 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc); msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc); + + if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE) { + ath11k_warn(ar->ab, "invalid msdu len in tkip mirc err %u\n", msdu_len); + ath11k_dbg_dump(ar->ab, ATH11K_DBG_DATA, NULL, "", desc, + sizeof(struct hal_rx_desc)); + return true; + } + skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len); skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes); @@ -5196,6 +5346,8 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu, ath11k_dp_rx_h_undecap(ar, msdu, desc, HAL_ENCRYPT_TYPE_TKIP_MIC, status, false); + + return false; } static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu, @@ -5208,7 +5360,7 @@ static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu, switch (rxcb->err_code) { case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR: - ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status); + drop = ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status); break; default: /* TODO: Review other rxdma error code to check if anything is
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index bb64b76..d654f92 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -392,6 +392,8 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, /* TODO: Take care of other encap modes as well */ ret = -EINVAL; atomic_inc(&ab->soc_stats.tx_err.misc_fail); + arsta->drop_pkts++; + arsta->drop_bytes += skb->len; goto fail_remove_idr; } @@ -831,6 +833,7 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, status.info = info; rate = arsta->last_txrate; status.rate = &rate; + arsta->tx_retry_count += ts.try_cnt > 1 ? (ts.try_cnt - 1) : 0; if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) { if(arsta->wbm_tx_stats && wbm_status < HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX) @@ -838,10 +841,19 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, } if (ts.status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) { - arsta->fail_pkts += 1; - arsta->per_fail_pkts += 1; - arsta->fail_bytes += msdu->len; - arsta->ber_fail_bytes += msdu->len; + if (ts.status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU) { + arsta->drop_pkts += 1; + arsta->drop_bytes += msdu->len; + spin_unlock_bh(&ab->base_lock); + dev_kfree_skb_any(msdu); + goto exit; + } else { + arsta->fail_pkts += 1; + arsta->per_fail_pkts += 1; + arsta->fail_bytes += msdu->len; + arsta->ber_fail_bytes += msdu->len; + } + if(arsta->per_fail_pkts + arsta->per_succ_pkts >= ATH11K_NUM_PKTS_THRSHLD_FOR_PER) ath11k_sta_stats_update_per(arsta); @@ -895,8 +907,7 @@ static inline bool ath11k_dp_tx_completion_valid(struct hal_wbm_release_ring *de if (FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0) == HAL_WBM_REL_SRC_MODULE_FW) { - status_desc = (struct htt_tx_wbm_completion *)((u8 *)desc) + HTT_TX_WBM_COMP_STATUS_OFFSET; - + status_desc = (struct htt_tx_wbm_completion *)(((u8 *)desc) + HTT_TX_WBM_COMP_STATUS_OFFSET); /* Dont consider HTT_TX_COMP_STATUS_MEC_NOTIFY */ if (FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS, status_desc->info0) == HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY) @@ -1083,10 +1094,6 @@ int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, if (cmd_num == 0) return -EINVAL; - /* Trigger reo status polling if required */ - if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS) - ath11k_dp_start_reo_status_timer(ab); - if (!cb) return 0;
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 875efcb..2ef92cd 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h
@@ -21,7 +21,8 @@ struct ath11k_base; #define HAL_NUM_MPDU_LINKS_PER_QUEUE_DESC 12 #define HAL_MAX_AVAIL_BLK_RES 3 -#define HAL_RING_BASE_ALIGN 8 +#define HAL_RING_BASE_ALIGN 32 +#define HAL_RXDMA_DIR_BUF_RING_BASE_ALIGN 8 #define HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX 32704 /* TODO: Check with hw team on the supported scatter buf size */
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 204d2e1..9741ccf 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -1450,39 +1450,6 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390 = { }, }; -const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq5018 = { - .tx = { - ATH11K_TX_RING_MASK_0, - ATH11K_TX_RING_MASK_1, - ATH11K_TX_RING_MASK_2, - }, - .rx_mon_status = { - 0, 0, 0, - ATH11K_RX_MON_STATUS_RING_MASK_0, - }, - .rx = { - 0, 0, 0, 0, - ATH11K_RX_RING_MASK_0, - ATH11K_RX_RING_MASK_1, - ATH11K_RX_RING_MASK_2, - ATH11K_RX_RING_MASK_3, - }, - .rx_err = { - 0, 0, 0, 0, 0, 0, 0, 0, - ATH11K_RX_ERR_RING_MASK_0, - }, - .rx_wbm_rel = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, - ATH11K_RX_WBM_REL_RING_MASK_0, - }, - .rxdma2host = { - ATH11K_RXDMA2HOST_RING_MASK_0, - }, - .host2rxdma = { - ATH11K_HOST2RXDMA_RING_MASK_0, - }, -}; - /* Target firmware's Copy Engine configuration. */ const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[] = { /* CE0: host->target HTC control and raw streams */ @@ -2197,6 +2164,43 @@ const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_qcn9074[] = { }, }; +const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122 = { + .tx = { + ATH11K_TX_RING_MASK_0, + ATH11K_TX_RING_MASK_1, + ATH11K_TX_RING_MASK_2, + }, + .rx_mon_status = { + 0, 0, 0, + ATH11K_RX_MON_STATUS_RING_MASK_0, + }, + .rx = { + 0, 0, 0, 0, + ATH11K_RX_RING_MASK_0, + ATH11K_RX_RING_MASK_1, + ATH11K_RX_RING_MASK_2, + ATH11K_RX_RING_MASK_3, + }, + .rx_err = { + 0, 0, 0, 0, 0, 0, 0, 0, + ATH11K_RX_ERR_RING_MASK_0, + }, + .rx_wbm_rel = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + ATH11K_RX_WBM_REL_RING_MASK_0, + }, + .reo_status = { + 0, 0, 0, + ATH11K_REO_STATUS_RING_MASK_0, + }, + .rxdma2host = { + ATH11K_RXDMA2HOST_RING_MASK_0, + }, + .host2rxdma = { + ATH11K_HOST2RXDMA_RING_MASK_0, + }, +}; + /* Target firmware's Copy Engine configuration for IPQ5018 */ const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq5018[] = { /* CE0: host->target HTC control and raw streams */
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index bff8ea2..5a34b3b 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -291,7 +291,7 @@ extern const struct ath11k_hw_ops qcn6122_ops; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074; -extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq5018; +extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122; static inline int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index dd9825d..2203e83 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -615,6 +615,7 @@ static void ath11k_pdev_caps_update(struct ath11k *ar) ar->txpower_limit_2g = ar->max_tx_power; ar->txpower_limit_5g = ar->max_tx_power; + ar->txpower_limit_6g = ar->max_tx_power; ar->txpower_scale = WMI_HOST_TP_SCALE_MAX; } @@ -785,6 +786,16 @@ static int ath11k_mac_txpower_recalc(struct ath11k *ar) ar->txpower_limit_5g = txpower; } + if ((ar->hw->wiphy->bands[NL80211_BAND_6GHZ]) && + ar->txpower_limit_6g != txpower) { + param = WMI_PDEV_PARAM_TXPOWER_LIMIT5G; + ret = ath11k_wmi_pdev_set_param(ar, param, + txpower, ar->pdev->pdev_id); + if (ret) + goto fail; + ar->txpower_limit_6g = txpower; + } + return 0; fail: @@ -887,6 +898,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar) spin_lock_bh(&ab->base_lock); list_for_each_entry_safe(peer, tmp, &ab->peers, list) { ath11k_peer_rx_tid_cleanup(ar, peer); + ath11k_peer_rhash_delete(ab, peer); list_del(&peer->list); kfree(peer); } @@ -1229,6 +1241,7 @@ static int __ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif, struct sk_buff u8 *ies; int ret; const u8 *vht_cap_ie; + u64 adjusted_tsf; ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); ies += sizeof(mgmt->u.beacon); @@ -1266,6 +1279,15 @@ static int __ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif, struct sk_buff WMI_BEACON_EMA_PARAM_LAST_TMPL_SHIFT; } + /* Make the TSF offset negative so beacons in the same + * staggered batch have the same TSF. + */ + if (arvif->tbtt_offset) { + adjusted_tsf = cpu_to_le64(0ULL - arvif->tbtt_offset); + mgmt = (void *)bcn->data; + memcpy(&mgmt->u.beacon.timestamp, &adjusted_tsf, sizeof(adjusted_tsf)); + } + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, ema_param); if (ret) @@ -1324,7 +1346,7 @@ static int ath11k_mac_setup_bcn_tmpl_legacy(struct ath11k_vif *arvif) return ret; } -static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) { if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; @@ -3183,7 +3205,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, static void ath11k_mac_op_nss_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 changed) + u64 changed) { struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); @@ -3221,7 +3243,7 @@ static void ath11k_mac_op_nss_bss_info_changed(struct ieee80211_hw *hw, static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); @@ -3239,6 +3261,24 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); + if (changed & BSS_CHANGED_6G_POWER_MODE) { + if (ar->supports_6ghz && + info->chandef.chan->band == NL80211_BAND_6GHZ && + arvif->vdev_type == WMI_VDEV_TYPE_AP && + test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) { + ath11k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx); + ret = ath11k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id, + &arvif->reg_tpc_info); + if (ret) + ath11k_warn(ar->ab, "Failed to set 6GHZ power mode\n"); + else + ieee80211_6ghz_power_mode_switch_done(arvif->vif); + + } else { + ath11k_warn(ar->ab, "Set 6GHZ power mode not applicable\n"); + } + } + if (changed & BSS_CHANGED_FTM_RESPONDER && arvif->ftm_responder != info->ftm_responder && (vif->type == NL80211_IFTYPE_AP || @@ -3433,19 +3473,8 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_TXPOWER) { ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev_id %i txpower %d\n", arvif->vdev_id, info->txpower); - - if (ar->supports_6ghz && info->chandef.chan && - info->chandef.chan->band == NL80211_BAND_6GHZ && - (arvif->vdev_type == WMI_VDEV_TYPE_STA || - arvif->vdev_type == WMI_VDEV_TYPE_AP) && - test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, - ar->ab->wmi_ab.svc_map)) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "discard tx power, change to set TPC power\n"); - } else { - arvif->txpower = info->txpower; - ath11k_mac_txpower_recalc(ar); - } + arvif->txpower = info->txpower; + ath11k_mac_txpower_recalc(ar); } if (changed & BSS_CHANGED_MCAST_RATE && @@ -4031,6 +4060,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *peer_addr; int ret = 0; u32 flags = 0; + unsigned long time_left; /* BIP needs to be done in software */ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || @@ -4108,6 +4138,14 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, else flags |= WMI_KEY_GROUP; + if (arsta && cmd == DISABLE_KEY && arsta->tx_disassoc) { + time_left = wait_for_completion_timeout(&arsta->disassoc_comp, + ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT); + if (!time_left) + ath11k_warn(ab, "disassociation tx completion timeout %pM\n", + sta->addr); + } + ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret); @@ -4759,8 +4797,10 @@ static int ath11k_station_disassoc(struct ath11k *ar, struct ieee80211_sta *sta) { struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; bool peer_dbg_info; int ret = 0; + unsigned long time_left; lockdep_assert_held(&ar->conf_mutex); @@ -4776,6 +4816,14 @@ static int ath11k_station_disassoc(struct ath11k *ar, return ret; } + if (arsta->tx_disassoc) { + time_left = wait_for_completion_timeout(&arsta->disassoc_comp, + ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT); + if (!time_left) + ath11k_warn(ar->ab, "disassociation tx completion timeout sta %pM\n", + sta->addr); + } + ret = ath11k_clear_peer_keys(arvif, sta->addr); if (ret) { ath11k_warn(ar->ab, "failed to clear all peer keys for vdev %i: %d\n", @@ -4796,11 +4844,12 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; const u16 *he_mcs_mask; - u32 changed, bw, nss, smps; + u32 changed, bw, nss, smps, bw_last; int err, num_ht_rates, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; struct peer_assoc_params peer_arg; bool peer_dbg_info, debug; + enum wmi_phy_mode peer_phymode; arsta = container_of(wk, struct ath11k_sta, update_wk); sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); @@ -4821,6 +4870,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) arsta->changed = 0; bw = arsta->bw; + bw_last = arsta->bw_last; nss = arsta->nss; smps = arsta->smps; @@ -4836,11 +4886,59 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) ath11k_mac_max_he_nss(he_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, - WMI_PEER_CHWIDTH, bw); - if (err) - ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", - sta->addr, bw, err); + /* Get the the peer phymode */ + ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); + peer_phymode = peer_arg.peer_phymode; + + if (peer_dbg_info) + ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "mac update sta %pM peer bw %d phymode %d\n", + sta->addr, bw, peer_phymode); + + if (bw > bw_last) { + /* BW is upgraded. In this case we send WMI_PEER_PHYMODE + * followed by WMI_PEER_CHWIDTH + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n", + sta->addr, bw, bw_last); + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_PHYMODE, peer_phymode); + + if (err) { + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", + sta->addr, peer_phymode, err); + goto err_rc_update; + } + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_CHWIDTH, bw); + + if (err) + ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + } else { + /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH + * followed by WMI_PEER_PHYMODE + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d, old BW %d\n", + sta->addr, bw, bw_last); + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_CHWIDTH, bw); + + if (err) { + ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + goto err_rc_update; + } + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_PHYMODE, peer_phymode); + + if (err) + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", + sta->addr, peer_phymode, err); + } } if (changed & IEEE80211_RC_NSS_CHANGED) { @@ -4931,6 +5029,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) } } +err_rc_update: mutex_unlock(&ar->conf_mutex); } @@ -5497,6 +5596,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk); INIT_WORK(&arsta->use_4addr_wk, ath11k_sta_use_4addr_wk); INIT_WORK(&arsta->tid_config_wk, ath11k_sta_tid_cfg_wk); + init_completion(&arsta->disassoc_comp); + arsta->tx_disassoc = false; ret = ath11k_mac_station_add(ar, vif, sta); if (ret) @@ -5520,13 +5621,13 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, if (peer && peer->sta == sta) { ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", vif->addr, arvif->vdev_id); + ath11k_peer_rhash_delete(ar->ab, peer); peer->sta = NULL; list_del(&peer->list); kfree(peer); ar->num_peers--; } spin_unlock_bh(&ar->ab->base_lock); - kfree(arsta->tx_stats); arsta->tx_stats = NULL; kfree(arsta->wbm_tx_stats); @@ -5563,6 +5664,11 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, peer->is_authorized = true; spin_unlock_bh(&ar->ab->base_lock); + spin_lock_bh(&ar->data_lock); + /* Set arsta bw and last bw */ + arsta->bw = arsta->bw_last = sta->bandwidth; + spin_unlock_bh(&ar->data_lock); + if (vif->type == NL80211_IFTYPE_STATION) { ret = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -5725,6 +5831,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, break; } + arsta->bw_last = arsta->bw; arsta->bw = bw; } @@ -6501,6 +6608,8 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, struct ath11k_base *ab = ar->ab; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info; + struct ath11k_peer *peer; + struct ath11k_sta *arsta; dma_addr_t paddr; bool tx_params_valid = false; int buf_id; @@ -6549,6 +6658,18 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, peer_is_in_cfr_unassoc_pool(ar, hdr->addr1)) tx_params_valid = true; + if (ieee80211_has_protected(hdr->frame_control) && + ieee80211_is_disassoc(hdr->frame_control)) { + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr1); + if (peer && peer->sta) { + arsta = (struct ath11k_sta *)peer->sta->drv_priv; + reinit_completion(&arsta->disassoc_comp); + arsta->tx_disassoc = true; + } + spin_unlock_bh(&ar->ab->base_lock); + } + ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb, tx_params_valid); if (ret) { @@ -6666,11 +6787,13 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, u32 info_flags = info->flags; struct ieee80211_sta *sta = control->sta; struct ath11k_sta *arsta = NULL; + struct ieee80211_mgmt *mgmt; bool is_prb_rsp; u16 frm_type = 0; u8 tid, *qos_ctl; bool noack = false; int ret; + u64 adjusted_tsf; if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) { ieee80211_free_txskb(ar->hw, skb); @@ -6690,6 +6813,12 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, } else if (ieee80211_is_mgmt(hdr->frame_control)) { frm_type = FIELD_GET(IEEE80211_FCTL_STYPE, hdr->frame_control); is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); + if (is_prb_rsp && arvif->tbtt_offset) { + mgmt = (struct ieee80211_mgmt *)skb->data; + adjusted_tsf = cpu_to_le64(0ULL - arvif->tbtt_offset); + memcpy(&mgmt->u.probe_resp.timestamp, &adjusted_tsf, + sizeof(adjusted_tsf)); + } ret = ath11k_mac_tx_over_wmi(ar, skb, is_prb_rsp); if (ret) { if (ret != -EBUSY) @@ -6985,6 +7114,22 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) return ret; } +static void ath11k_update_bcn_template_work(struct work_struct *work) +{ + struct ath11k_vif *arvif = container_of(work, struct ath11k_vif, + update_bcn_template_work); + struct ath11k *ar = arvif->ar; + int ret = 0; + + mutex_lock(&ar->conf_mutex); + if (arvif->is_up) + ret = ath11k_mac_setup_bcn_tmpl(arvif); + mutex_unlock(&ar->conf_mutex); + if (ret) + ath11k_warn(ar->ab, "failed to submit beacon template for vdev_id : %d ret : %d\n", + arvif->vdev_id, ret); +} + static void ath11k_mac_op_stop(struct ieee80211_hw *hw) { struct ath11k *ar = hw->priv; @@ -7207,6 +7352,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, INIT_DELAYED_WORK(&arvif->connection_loss_work, ath11k_mac_vif_sta_connection_loss_work); + INIT_WORK(&arvif->update_bcn_template_work, ath11k_update_bcn_template_work); for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { arvif->bitrate_mask.control[i].legacy = 0xffffffff; @@ -7238,8 +7384,12 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, goto err; } - ath11k_debugfs_dbg_mac_filter(arvif); - ath11k_debugfs_wbm_tx_comp_stats(arvif); + if (ar->state != ATH11K_STATE_RESTARTED) { + ath11k_debugfs_dbg_mac_filter(arvif); + ath11k_debugfs_wbm_tx_comp_stats(arvif); + } else { + INIT_LIST_HEAD(&arvif->mac_filters); + } switch (vif->type) { case NL80211_IFTYPE_UNSPECIFIED: @@ -7408,6 +7558,14 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; param_value = ar->hw->wiphy->rts_threshold; + + if (vif->type == NL80211_IFTYPE_MESH_POINT && + !ar->rts_threshold[vif->type]) + ar->rts_threshold[vif->type] = 1; + + if (ar->rts_threshold[vif->type]) + param_value = ar->rts_threshold[vif->type]; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -7429,8 +7587,13 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, goto err_peer_del; } - ath11k_debug_aggr_size_config_init(arvif); - ath11k_debugfs_wmi_ctrl_stats(arvif); + if (ar->state != ATH11K_STATE_RESTARTED) { + ath11k_debug_aggr_size_config_init(arvif); + ath11k_debugfs_wmi_ctrl_stats(arvif); + } else { + INIT_LIST_HEAD(&arvif->ar->debug.wmi_list); + init_completion(&arvif->ar->debug.wmi_ctrl_path_stats_rcvd); + } mutex_unlock(&ar->conf_mutex); @@ -7508,6 +7671,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, } cancel_delayed_work_sync(&arvif->connection_loss_work); + cancel_work_sync(&arvif->update_bcn_template_work); ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); @@ -8532,7 +8696,7 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, bool is_psd_power = false, is_tpe_present = false; s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL], psd_power, tx_power = 0, eirp_power = 0; - u16 oper_freq = 0, start_freq = 0, center_freq = 0; + u16 oper_freq = 0, start_freq = 0, center_freq = 0, op_center_freq = 0; u8 reg_6g_power_mode; enum nl80211_chan_width bw; int cfi; @@ -8658,8 +8822,8 @@ void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar, psd_power = temp_chan->psd; if (reg_6g_power_mode == IEEE80211_REG_SP_AP && ar->afc.is_6g_afc_power_event_received) { - center_freq = ctx->def.center_freq1; - cfi = ieee80211_frequency_to_channel(center_freq); + op_center_freq = ctx->def.center_freq1; + cfi = ieee80211_frequency_to_channel(op_center_freq); bw = ctx->def.width; eirp_power = ath11k_reg_get_afc_eirp_power(ar, bw, @@ -10448,6 +10612,7 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k *ar = hw->priv; + u32 bw_offset = 0; sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); @@ -10460,6 +10625,11 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RTS_RETRIES); } + if (arsta->tx_retry_count) { + sinfo->tx_retries = arsta->tx_retry_count; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + } + if (!arsta->txrate.legacy && !arsta->txrate.nss) return; @@ -10476,11 +10646,11 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.flags = arsta->txrate.flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - /* TODO: Use real NF instead of default one. */ - sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; + bw_offset = arsta->last_tx_pkt_bw * 3; + sinfo->signal = arsta->rssi_comb + ar->chan_noise_floor + bw_offset; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi) + ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi) + ar->chan_noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); if (ath11k_nss_offload_enabled(ar->ab)) @@ -10629,7 +10799,7 @@ static int ath11k_fw_stats_request(struct ath11k *ar, static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - int *dbm) + int *mbm) { struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; @@ -10668,22 +10838,134 @@ static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, } /* tx power is set as 2 units per dBm in FW. */ - *dbm = pdev->chan_tx_power/2; + *mbm = DBM_TO_MBM(pdev->chan_tx_power) / 2; spin_unlock_bh(&ar->data_lock); mutex_unlock(&ar->conf_mutex); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from fw\n", __func__, *dbm); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from fw\n", __func__, *mbm); return 0; err_unlock: mutex_unlock(&ar->conf_mutex); /* We didn't get txpower from FW. Hence, relying on vif->bss_conf.txpower */ - *dbm = vif->bss_conf.txpower; + *mbm = DBM_TO_MBM(vif->bss_conf.txpower); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "%s: txpower: %d from bss_conf\n", __func__, vif->bss_conf.txpower); return 0; } +static int ath11k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath11k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + + ath11k_scan_abort(ar); + + mutex_unlock(&ar->conf_mutex); + + cancel_delayed_work_sync(&ar->scan.timeout); + + return 0; +} + +static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct ath11k *ar = hw->priv; + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct scan_req_params *arg; + int ret; + u32 scan_time_msec; + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + switch (ar->scan.state) { + case ATH11K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); + ar->scan.state = ATH11K_SCAN_STARTING; + ar->scan.is_roc = true; + ar->scan.vdev_id = arvif->vdev_id; + ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; + ret = 0; + break; + case ATH11K_SCAN_STARTING: + case ATH11K_SCAN_RUNNING: + case ATH11K_SCAN_ABORTING: + ret = -EBUSY; + break; + } + spin_unlock_bh(&ar->data_lock); + + if (ret) + goto exit; + + scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2; + + arg = kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + ret = -ENOMEM; + goto exit; + } + + ath11k_wmi_start_scan_init(ar, arg); + arg->chan_list.num_chan = 1; + + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH11K_SCAN_ID; + arg->chan_list.chan[0].freq = chan->center_freq; + arg->dwell_time_active = scan_time_msec; + arg->dwell_time_passive = scan_time_msec; + arg->max_scan_time = scan_time_msec; + arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_flags |= WMI_SCAN_FILTER_PROBE_REQ; + arg->burst_duration = duration; + + ret = ath11k_start_scan(ar, arg); + if (ret) { + ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret); + + spin_lock_bh(&ar->data_lock); + ar->scan.state = ATH11K_SCAN_IDLE; + spin_unlock_bh(&ar->data_lock); + goto exit; + } + + ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); + if (ret == 0) { + ath11k_warn(ar->ab, "failed to switch to channel for roc scan\n"); + ret = ath11k_scan_stop(ar); + if (ret) + ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret); + ret = -ETIMEDOUT; + goto exit; + } + + ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, + msecs_to_jiffies(duration)); + + ret = 0; + +exit: + if (arg) + kfree(arg); + + mutex_unlock(&ar->conf_mutex); + return ret; +} + static const struct ieee80211_ops ath11k_ops = { .tx = ath11k_mac_op_tx, .start = ath11k_mac_op_start, @@ -10722,6 +11004,8 @@ static const struct ieee80211_ops ath11k_ops = { .set_tid_config = ath11k_mac_op_set_tid_config, .reset_tid_config = ath11k_mac_op_reset_tid_config, .sta_set_mgmt_rts_cts = ath11k_mac_op_sta_set_mgmt_rts_cts, + .remain_on_channel = ath11k_mac_op_remain_on_channel, + .cancel_remain_on_channel = ath11k_mac_op_cancel_remain_on_channel, CFG80211_TESTMODE_CMD(ath11k_tm_cmd) #ifdef CONFIG_ATH11K_DEBUGFS .sta_add_debugfs = ath11k_debugfs_sta_op_add, @@ -11113,6 +11397,8 @@ void ath11k_mac_unregister(struct ath11k_base *ab) __ath11k_mac_unregister(ar); } + + ath11k_peer_rhash_tbl_destroy(ab); } static int __ath11k_mac_register(struct ath11k *ar) @@ -11391,6 +11677,10 @@ int ath11k_mac_register(struct ath11k_base *ab) ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + ret = ath11k_peer_rhash_tbl_init(ab); + if (ret) + return ret; + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; @@ -11421,6 +11711,8 @@ int ath11k_mac_register(struct ath11k_base *ab) __ath11k_mac_unregister(ar); } + ath11k_peer_rhash_tbl_destroy(ab); + return ret; } @@ -11487,6 +11779,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab) init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); init_completion(&ar->scan.completed); + init_completion(&ar->scan.on_channel); init_completion(&ar->thermal.wmi_sync); INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 7076e56..475756a 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -133,6 +133,8 @@ struct ath11k_generic_iter { #define IEEE80211_HE_DL_MU_SUPPORT_ENABLE 2 #define IEEE80211_HE_DL_MU_SUPPORT_INVALID 3 +#define ATH11K_DISASSOC_TX_COMPLETION_TIMEOUT (3 * HZ) + extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default; int ath11k_mac_ap_ps_recalc(struct ath11k *ar); @@ -174,4 +176,5 @@ bool ath11k_mac_sta_level_info(struct ath11k_vif *arvif, struct ieee80211_sta *s void ath11k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, void *data); +int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif); #endif
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index a951b7d..d17dff5 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -937,7 +937,7 @@ int ath11k_pci_ext_config_gic_msi_irq(struct ath11k_base *ab, struct platform_de for (j = 0; j < irq_grp->num_irq; j++) { int irq_idx = irq_grp->irqs[j]; - int vector = (i % num_vectors) + base_vector; + int vector = (i % num_vectors); irq_set_status_flags(msi_desc->irq, IRQ_DISABLE_UNLAZY); ret = devm_request_irq(&pdev->dev, msi_desc->irq,
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 81d3df4..b0cc6f8 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -27,25 +27,6 @@ struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id, return NULL; } -static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab, - u8 pdev_idx, const u8 *addr) -{ - struct ath11k_peer *peer; - - lockdep_assert_held(&ab->base_lock); - - list_for_each_entry(peer, &ab->peers, list) { - if (peer->pdev_idx != pdev_idx) - continue; - if (!ether_addr_equal(peer->addr, addr)) - continue; - - return peer; - } - - return NULL; -} - struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab, const u8 *addr) { @@ -53,14 +34,13 @@ struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab, lockdep_assert_held(&ab->base_lock); - list_for_each_entry(peer, &ab->peers, list) { - if (!ether_addr_equal(peer->addr, addr)) - continue; + if (!ab->rhead_peer_addr) + return NULL; - return peer; - } + peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr, + ab->rhash_peer_addr_param); - return NULL; + return peer; } struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, @@ -70,11 +50,13 @@ struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, lockdep_assert_held(&ab->base_lock); - list_for_each_entry(peer, &ab->peers, list) - if (peer_id == peer->peer_id) - return peer; + if (!ab->rhead_peer_id) + return NULL; - return NULL; + peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id, + ab->rhash_peer_id_param); + + return peer; } struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab, @@ -461,6 +443,7 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id) ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n", peer->vdev_id, peer->addr, peer_id); + ath11k_peer_rhash_delete(ab, peer); list_del(&peer->list); kfree(peer); wake_up(&ab->peer_mapping_wq); @@ -502,6 +485,7 @@ void ath11k_peer_unmap_v2_event(struct ath11k_base *ab, u16 peer_id, bool is_wds ar->bss_peer = NULL; free_peer: rcu_read_unlock(); + ath11k_peer_rhash_delete(ab, peer); list_del(&peer->list); kfree(peer); wake_up(&ab->peer_mapping_wq); @@ -607,6 +591,69 @@ static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id, return 0; } +static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab, + struct rhashtable *rtbl, + struct rhash_head *rhead, + struct rhashtable_params *params, + void *key) +{ + struct ath11k_peer *tmp; + + lockdep_assert_held(&ab->base_lock); + + tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params); + + if (!tmp) + return 0; + else if (IS_ERR(tmp)) + return PTR_ERR(tmp); + else + return -EEXIST; +} + +static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab, + struct rhashtable *rtbl, + struct rhash_head *rhead, + struct rhashtable_params *params) +{ + lockdep_assert_held(&ab->base_lock); + + return rhashtable_remove_fast(rtbl, rhead, *params); +} + +static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer) +{ + int ret; + + lockdep_assert_held(&ab->base_lock); + + if (!ab->rhead_peer_id || !ab->rhead_peer_addr) + return -EPERM; + + ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id, + &ab->rhash_peer_id_param, &peer->peer_id); + if (ret) { + ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n", + peer->addr, peer->peer_id, ret); + return ret; + } + + ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr, + &ab->rhash_peer_addr_param, &peer->addr); + if (ret) { + ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n", + peer->addr, peer->peer_id, ret); + goto err_clean; + } + + return 0; + +err_clean: + ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id, + &ab->rhash_peer_id_param); + return ret; +} + void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id) { struct ath11k_peer *peer, *tmp_peer; @@ -634,6 +681,7 @@ void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id) &peer->ast_entry_list, ase_list) ath11k_peer_del_ast(ar, ast_entry); + ath11k_peer_rhash_delete(ab, peer); list_del(&peer->list); kfree(peer); ar->num_peers--; @@ -743,7 +791,7 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, struct ath11k_peer *peer; struct ieee80211_vif *vif = arvif->vif; struct ath11k_sta *arsta; - int ret; + int ret, err_ret; lockdep_assert_held(&ar->conf_mutex); @@ -754,7 +802,7 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, } spin_lock_bh(&ar->ab->base_lock); - peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr); + peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr); if (peer) { spin_unlock_bh(&ar->ab->base_lock); return -EINVAL; @@ -782,22 +830,14 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", param->peer_addr, param->vdev_id); - reinit_completion(&ar->peer_delete_done); + ret = -ENOENT; + goto cleanup; + } - ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, - param->vdev_id); - if (ret) { - ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", - param->vdev_id, param->peer_addr); - return ret; - } - - ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, - param->peer_addr); - if (ret) - return ret; - - return -ENOENT; + ret = ath11k_peer_rhash_add(ar->ab, peer); + if (ret) { + spin_unlock_bh(&ar->ab->base_lock); + goto cleanup; } peer->pdev_idx = ar->pdev_idx; @@ -831,4 +871,211 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, spin_unlock_bh(&ar->ab->base_lock); return 0; + +cleanup: + reinit_completion(&ar->peer_delete_done); + + err_ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, + param->vdev_id); + if (err_ret) { + ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM ret %d\n", + param->vdev_id, param->peer_addr, err_ret); + goto exit; + } + + err_ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, + param->peer_addr); + if (err_ret) + ath11k_warn(ar->ab, "failed wait for peer %pM delete done id %d ret %d\n", + param->peer_addr, param->vdev_id, err_ret); + +exit: + return ret; +} + +int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer) +{ + int ret; + + lockdep_assert_held(&ab->base_lock); + + if (!ab->rhead_peer_id || !ab->rhead_peer_addr) + return -EPERM; + + ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id, + &ab->rhash_peer_id_param); + if (ret) { + ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n", + peer->addr, peer->peer_id, ret); + return ret; + } + + ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr, + &ab->rhash_peer_addr_param); + if (ret) { + ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n", + peer->addr, peer->peer_id, ret); + return ret; + } + + return 0; +} + +static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab) +{ + struct rhashtable_params *param; + struct rhashtable *rhash_id_tbl; + int ret; + size_t size; + + if (ab->rhead_peer_id) + return 0; + + size = sizeof(*ab->rhead_peer_id); + rhash_id_tbl = kzalloc(size, GFP_KERNEL); + if (!rhash_id_tbl) { + ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n", + size); + return -ENOMEM; + } + + param = &ab->rhash_peer_id_param; + + param->key_offset = offsetof(struct ath11k_peer, peer_id); + param->head_offset = offsetof(struct ath11k_peer, rhash_id); + param->key_len = sizeof_field(struct ath11k_peer, peer_id); + param->automatic_shrinking = true; + param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV; + + ret = rhashtable_init(rhash_id_tbl, param); + if (ret) { + ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret); + goto err_free; + } + + spin_lock_bh(&ab->base_lock); + + if (!ab->rhead_peer_id) { + ab->rhead_peer_id = rhash_id_tbl; + } else { + spin_unlock_bh(&ab->base_lock); + ath11k_warn(ab, "already peer rhash id init done id_tbl: %p\n", + ab->rhead_peer_id); + goto cleanup_tbl; + } + + spin_unlock_bh(&ab->base_lock); + + return 0; + +cleanup_tbl: + rhashtable_destroy(rhash_id_tbl); +err_free: + kfree(rhash_id_tbl); + + return ret; +} + +static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab) +{ + struct rhashtable_params *param; + struct rhashtable *rhash_addr_tbl; + int ret; + size_t size; + + if (ab->rhead_peer_addr) + return 0; + + size = sizeof(*ab->rhead_peer_addr); + rhash_addr_tbl = kzalloc(size, GFP_KERNEL); + if (!rhash_addr_tbl) { + ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n", + size); + return -ENOMEM; + } + + param = &ab->rhash_peer_addr_param; + + param->key_offset = offsetof(struct ath11k_peer, addr); + param->head_offset = offsetof(struct ath11k_peer, rhash_addr); + param->key_len = sizeof_field(struct ath11k_peer, addr); + param->automatic_shrinking = true; + param->nelem_hint = TARGET_NUM_PEERS_PDEV; + + ret = rhashtable_init(rhash_addr_tbl, param); + if (ret) { + ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret); + goto err_free; + } + + spin_lock_bh(&ab->base_lock); + + if (!ab->rhead_peer_addr) { + ab->rhead_peer_addr = rhash_addr_tbl; + } else { + spin_unlock_bh(&ab->base_lock); + ath11k_warn(ab, "already peer rhash addr init done\n"); + goto cleanup_tbl; + } + + spin_unlock_bh(&ab->base_lock); + + return 0; + +cleanup_tbl: + rhashtable_destroy(rhash_addr_tbl); +err_free: + kfree(rhash_addr_tbl); + + return ret; +} + +static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab) +{ + if (!ab->rhead_peer_id) + return; + + rhashtable_destroy(ab->rhead_peer_id); + kfree(ab->rhead_peer_id); + ab->rhead_peer_id = NULL; +} + +static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab) +{ + if (!ab->rhead_peer_addr) + return; + + rhashtable_destroy(ab->rhead_peer_addr); + kfree(ab->rhead_peer_addr); + ab->rhead_peer_addr = NULL; +} + +int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab) +{ + int ret; + + ret = ath11k_peer_rhash_id_tbl_init(ab); + if (ret) + return ret; + + ret = ath11k_peer_rhash_addr_tbl_init(ab); + if (ret) + goto cleanup_tbl; + + return 0; + +cleanup_tbl: + ath11k_peer_rhash_id_tbl_destroy(ab); + + return ret; +} + +void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab) +{ + spin_lock_bh(&ab->base_lock); + + ath11k_peer_rhash_id_tbl_destroy(ab); + ath11k_peer_rhash_addr_tbl_destroy(ab); + + spin_unlock_bh(&ab->base_lock); }
diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index e54ced9..aa0835d 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -75,6 +75,10 @@ struct ath11k_peer { /* protected by ab->data_lock */ struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1]; struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1]; + /* peer id based rhashtable list pointer */ + struct rhash_head rhash_id; + /* peer addr based rhashtable list pointer */ + struct rhash_head rhash_addr; /* Info used in MMIC verification of * RX fragments @@ -113,6 +117,9 @@ int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id, const u8 *addr); struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab, int vdev_id); +int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab); +void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab); +int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer); #ifdef CONFIG_ATH11K_NSS_SUPPORT struct ath11k_ast_entry *ath11k_peer_ast_find_by_addr(struct ath11k_base *ab,
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c13bc82..cbcb031 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/elf.h> @@ -4535,9 +4536,8 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) ath11k_core_qmi_firmware_ready(ab); set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); - if (country_code) { - ath11k_reg_update_cc(ab); - } + if (country_code) + ath11k_reg_update_cc(ab, country_code); } break;
diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 281f646..a45182a 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c
@@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" #include "debug.h" @@ -16,8 +17,6 @@ #define ETSI_WEATHER_RADAR_BAND_HIGH 5650 #define ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT 600000 -extern char *country_code; - static const struct ieee80211_regdomain ath11k_world_regd = { .n_reg_rules = 3, .alpha2 = "00", @@ -128,22 +127,21 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) "INIT Country code set to fw failed : %d\n", ret); } -void ath11k_reg_update_cc(struct ath11k_base *ab) +void ath11k_reg_update_cc(struct ath11k_base *ab, const char *country_code) { struct wmi_init_country_params init_country_param; struct ath11k_pdev *pdev; - struct ath11k *ar; int i, ret; + init_country_param.flags = ALPHA_IS_SET; + memcpy(&init_country_param.cc_info.alpha2, country_code, 2); + init_country_param.cc_info.alpha2[2] = 0; + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; - ar = pdev->ar; - init_country_param.flags = ALPHA_IS_SET; - memcpy(&init_country_param.cc_info.alpha2, country_code, 2); - init_country_param.cc_info.alpha2[2] = 0; - ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); + ret = ath11k_wmi_send_init_country_cmd(pdev->ar, init_country_param); if (ret) - ath11k_warn(ar->ab, + ath11k_warn(pdev->ar->ab, "INIT Country code set to fw failed : %d\n", ret); } } @@ -216,6 +214,11 @@ int ath11k_regd_update(struct ath11k *ar, bool init) rtnl_lock(); wiphy_lock(ar->hw->wiphy); + if (ar->afc.is_6g_afc_power_event_received || ar->afc.switch_to_lpi_indication_received) + ar->hw->wiphy->regulatory_flags |= REGULATORY_SET_BY_6GHZ_AFC; + else + ar->hw->wiphy->regulatory_flags &= ~REGULATORY_SET_BY_6GHZ_AFC; + ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy); wiphy_unlock(ar->hw->wiphy); rtnl_unlock(); @@ -884,6 +887,69 @@ void ath11k_reg_get_afc_eirp_power_for_bw(struct ath11k *ar, u16 *start_freq, *tx_power = ath11k_reg_get_afc_eirp_power(ar, bw, cfi); } +int ath11k_reg_switch_to_lpi(struct ath11k_base *ab, struct ath11k_afc_info *afc) +{ + struct ieee80211_regdomain *regd = NULL; + struct ieee80211_regdomain *new_regd = NULL; + struct ieee80211_reg_rule *old_rule, *new_regd_rules; + struct ath11k *ar = container_of(afc, struct ath11k, afc); + int new_reg_rule_cnt = 0, num_regd_rules = 0, num_sp_rules = 0; + int i, k, pdev_idx, ret = 0; + + pdev_idx = ar->pdev_idx; + + if (ab->new_regd[pdev_idx]) { + regd = ab->new_regd[pdev_idx]; + } else { + regd = ab->default_regd[pdev_idx]; + } + + if (!regd) { + ath11k_warn(ab, "Regulatory domain data not present\n"); + return -EINVAL; + } + + num_regd_rules = regd->n_reg_rules; + for (i = 0; i < num_regd_rules; i++) { + old_rule = regd->reg_rules + i; + if (old_rule->mode == NL80211_REG_AP_SP) + num_sp_rules++; + } + + new_reg_rule_cnt = num_regd_rules - num_sp_rules; + + new_regd = kzalloc(sizeof(*new_regd) + + (sizeof(*new_regd_rules) * new_reg_rule_cnt), + GFP_KERNEL); + if (!new_regd) + return -ENOMEM; + + new_regd->n_reg_rules = new_reg_rule_cnt; + memcpy(new_regd->alpha2, regd->alpha2, REG_ALPHA2_LEN + 1); + new_regd->dfs_region = ath11k_map_fw_dfs_region(regd->dfs_region); + k = 0; + for (i = 0; i < num_regd_rules; i++) { + old_rule = regd->reg_rules + i; + + if (old_rule->mode == NL80211_REG_AP_SP) { + continue; + } else { + memcpy((new_regd->reg_rules + k), old_rule, sizeof(*new_regd_rules)); + k++; + } + } + + ar->afc.switch_to_lpi_indication_received = true; + + spin_lock_bh(&ab->base_lock); + kfree(ab->new_regd[pdev_idx]); + ab->new_regd[pdev_idx] = new_regd; + spin_unlock_bh(&ab->base_lock); + + ieee80211_queue_work(ar->hw, &ar->regd_update_work); + return ret; +} + int ath11k_reg_process_afc_power_event(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -964,6 +1030,9 @@ int ath11k_reg_process_afc_power_event(struct ath11k *ar) } } + if (num_new_sp_rules) + ar->afc.switch_to_lpi_indication_received = false; + /* Remove the old sp rule from regd and add the new intersected sp rules */ new_reg_rule_cnt = num_regd_rules - num_old_sp_rules + num_new_sp_rules; ath11k_dbg(ab, ATH11K_DBG_AFC, @@ -972,7 +1041,7 @@ int ath11k_reg_process_afc_power_event(struct ath11k *ar) new_regd = kzalloc(sizeof(*new_regd) + (sizeof(*new_regd_rules) * new_reg_rule_cnt), - GFP_KERNEL); + GFP_ATOMIC); if (!new_regd) { ret = -ENOMEM; goto end; @@ -1060,8 +1129,15 @@ int ath11k_copy_afc_response(struct ath11k *ar, char *afc_resp, u32 len) } status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_ERROR); - memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE); - memcpy(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len); + + if (ab->userpd_id) { + memset_io(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE); + memcpy_toio(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len); + } else { + memset(mem + (slotid * AFC_SLOT_SIZE), 0, AFC_SLOT_SIZE); + memcpy(mem + (slotid * AFC_SLOT_SIZE), afc_resp, len); + } + status[AFC_AUTH_STATUS_OFFSET] = cpu_to_le32(AFC_AUTH_SUCCESS); return 0; @@ -1073,7 +1149,7 @@ int ath11k_reg_afc_start(struct ath11k_base *ab, struct ath11k_afc_info *afc) struct ath11k_afc_req_fixed_params *fixed_param = NULL; int ret = 0; - fixed_param = kzalloc(sizeof(*fixed_param), GFP_KERNEL); + fixed_param = kzalloc(sizeof(*fixed_param), GFP_ATOMIC); if (!fixed_param) return -ENOMEM; @@ -1105,8 +1181,9 @@ int ath11k_process_expiry_event(struct ath11k_base *ab, struct ath11k_afc_info * } break; case REG_AFC_EXPIRY_EVENT_SWITCH_TO_LPI: - /*TBH*/ - break; + ath11k_dbg(ab, ATH11K_DBG_AFC, "AFC switch to LPI indication received\n"); + ret = ath11k_reg_switch_to_lpi(ab, afc); + return ret; default: ath11k_dbg(ab, ATH11K_DBG_AFC, "Invalid AFC expiry event subtype %d\n", afc->event_subtype);
diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index a5dfb89..b4939a2 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h
@@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H @@ -65,6 +66,6 @@ void ath11k_reg_get_afc_eirp_power_for_bw(struct ath11k *ar, u16 *start_freq, u16 *center_freq, int pwr_level, struct cfg80211_chan_def *chan_def, s8 *tx_power); -void ath11k_reg_update_cc(struct ath11k_base *ab); +void ath11k_reg_update_cc(struct ath11k_base *ab, const char *country_code); #endif
diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index bfba684..63edc6e 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c
@@ -61,7 +61,7 @@ void ath11k_fwlog_write(struct ath11k_base *ab, u8 *data, int len) return; } - cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + cfg80211_testmode_event(nl_skb, GFP_ATOMIC, true); } /* Returns true if callee consumes the skb and the skb should be discarded. @@ -141,7 +141,7 @@ bool ath11k_wmi_tm_event_unsegmented(struct ath11k_base *ab, u32 cmd_id, goto out; } - cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false); out: spin_unlock_bh(&ar->data_lock); @@ -265,7 +265,7 @@ bool ath11k_process_tm_event(struct ath11k_base *ab, u32 cmd_id, goto out; } - cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + cfg80211_testmode_event(nl_skb, GFP_ATOMIC, false); out: spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath11k/vendor.c b/drivers/net/wireless/ath/ath11k/vendor.c index 6ba6a92..b1795b2 100644 --- a/drivers/net/wireless/ath/ath11k/vendor.c +++ b/drivers/net/wireless/ath/ath11k/vendor.c
@@ -269,7 +269,7 @@ int ath11k_send_power_update_complete(struct ath11k *ar) ath11k_dbg(ab, ATH11K_DBG_AFC, "Sending power update complete for afc request id %llu status code %d\n", fixed_param.req_id, fixed_param.status_code); - cfg80211_vendor_event(nl_skb, GFP_KERNEL); + cfg80211_vendor_event(nl_skb, GFP_ATOMIC); return 0; } @@ -305,7 +305,7 @@ int ath11k_send_afc_start(struct ath11k *ar, struct ath11k_afc_req_fixed_params goto out; } - cfg80211_vendor_event(nl_skb, GFP_KERNEL); + cfg80211_vendor_event(nl_skb, GFP_ATOMIC); ath11k_dbg(ar->ab, ATH11K_DBG_AFC, "Sending expiry event to higher layer of type %d\n", QCA_WLAN_VENDOR_AFC_EXPIRY_EVENT);
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index c6318d8..462acda 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -23,6 +23,8 @@ #define ATH11K_WMI_STA_KICKOUT_TIMEOUT_MS 5000 #define ATH11K_WMI_STA_KICKOUT_LIMIT 100 +#define ATH11K_TEST_CAL_STATUS(val, idx) ((val >> idx) & 1) + struct wmi_tlv_policy { size_t min_len; }; @@ -154,6 +156,9 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wmi_afc_event_fixed_param) }, [WMI_TAG_AFC_EXPIRY_EVENT_PARAM] = { .min_len = sizeof(struct wmi_afc_expiry_event_param) }, + [WMI_TAG_PDEV_CAL_STATUS_EVENT] + = { .min_len = sizeof(struct wmi_pdev_cal_status_event) }, + }; #define PRIMAP(_hw_mode_) \ @@ -6347,6 +6352,8 @@ static int wmi_process_tx_comp(struct ath11k *ar, struct wmi_tx_compl_event *tx_ struct ieee80211_vif *vif; struct ath11k_vif *arvif; struct ath11k_mgmt_frame_stats *mgmt_stats; + struct ath11k_peer *peer; + struct ath11k_sta *arsta; u16 frm_type; spin_lock_bh(&ar->data_lock); @@ -6386,6 +6393,18 @@ static int wmi_process_tx_comp(struct ath11k *ar, struct wmi_tx_compl_event *tx_ mgmt_stats->tx_compl_fail[frm_type]++; } + if (ieee80211_has_protected(hdr->frame_control) && + ieee80211_is_disassoc(hdr->frame_control)) { + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find_by_addr(ar->ab, hdr->addr1); + if (peer && peer->sta) { + arsta = (struct ath11k_sta *)peer->sta->drv_priv; + complete_all(&arsta->disassoc_comp); + arsta->tx_disassoc = false; + } + spin_unlock_bh(&ar->ab->base_lock); + } + skip_mgmt_stats: spin_unlock_bh(&ar->data_lock); @@ -6457,6 +6476,8 @@ static void ath11k_wmi_event_scan_started(struct ath11k *ar) break; case ATH11K_SCAN_STARTING: ar->scan.state = ATH11K_SCAN_RUNNING; + if (ar->scan.is_roc) + ieee80211_ready_on_channel(ar->hw); complete(&ar->scan.started); break; } @@ -6539,6 +6560,8 @@ static void ath11k_wmi_event_scan_foreign_chan(struct ath11k *ar, u32 freq) case ATH11K_SCAN_RUNNING: case ATH11K_SCAN_ABORTING: ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); + if (ar->scan.is_roc && ar->scan.roc_freq == freq) + complete(&ar->scan.on_channel); break; } } @@ -6863,10 +6886,12 @@ static int ath11k_pull_wds_addr_ev(struct ath11k_base *ab, struct sk_buff *skb, return 0; } -static void ath11k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src, +static void ath11k_wmi_pull_pdev_stats_base(struct ath11k *ar, + const struct wmi_pdev_stats_base *src, struct ath11k_fw_stats_pdev *dst) { dst->ch_noise_floor = src->chan_nf; + ar->chan_noise_floor = src->chan_nf; dst->tx_frame_count = src->tx_frame_count; dst->rx_frame_count = src->rx_frame_count; dst->rx_clear_count = src->rx_clear_count; @@ -7045,7 +7070,7 @@ int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, if (!dst) continue; - ath11k_wmi_pull_pdev_stats_base(&src->base, dst); + ath11k_wmi_pull_pdev_stats_base(ar, &src->base, dst); ath11k_wmi_pull_pdev_stats_tx(&src->tx, dst); ath11k_wmi_pull_pdev_stats_rx(&src->rx, dst); list_add_tail(&dst->list, &stats->pdevs); @@ -8393,7 +8418,6 @@ static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff spin_lock_bh(&ab->base_lock); peer = ath11k_peer_find_by_addr(ab, arg.mac_addr); - if (!peer) { spin_unlock_bh(&ab->base_lock); ath11k_warn(ab, "peer not found %pM\n", @@ -10063,7 +10087,6 @@ ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab, struct sk_buff *s spin_lock_bh(&ab->base_lock); peer = ath11k_peer_find_by_addr(ab, peer_addr); - if (!peer) { ath11k_warn(ab, "peer not found %pM\n", peer_addr); @@ -10074,11 +10097,9 @@ ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab, struct sk_buff *s } ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id); - if (!ar) { ath11k_warn(ab, "invalid vdev id in peer sta ps state change ev %d", peer->vdev_id); - spin_unlock_bh(&ab->base_lock); goto exit; } @@ -10223,6 +10244,130 @@ static void ath11k_wmi_tlv_cfr_cpature_phase_fixed_param(const void *ptr, } } +static int ath11k_wmi_tbtt_offset_subtlv_parser(struct ath11k_base *ab, u16 tag, + u16 len, const void *ptr, + void *data) +{ + int ret = 0; + struct ath11k *ar; + u64 tx_delay = 0; + struct wmi_tbtt_offset_info *tbtt_offset_info; + struct ieee80211_chanctx_conf *conf; + struct ath11k_vif *arvif; + + tbtt_offset_info = (struct wmi_tbtt_offset_info *)ptr; + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, tbtt_offset_info->vdev_id); + if (!ar) { + ath11k_warn(ab, "ar not found, vdev_id %d\n", tbtt_offset_info->vdev_id); + ret = -EINVAL; + goto exit; + } + + arvif = ath11k_mac_get_arvif(ar, tbtt_offset_info->vdev_id); + if (!arvif) { + ath11k_warn(ab, "arvif not found, vdev_id %d\n", + tbtt_offset_info->vdev_id); + ret = -EINVAL; + goto exit; + } + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) { + ret = 0; + goto exit; + } + + arvif->tbtt_offset = tbtt_offset_info->tbtt_offset; + + conf = rcu_dereference(arvif->vif->chanctx_conf); + if (conf && conf->def.chan->band == NL80211_BAND_2GHZ) { + /* 1Mbps Beacon: */ + /* 144 us ( LPREAMBLE) + 48 (PLCP Header) + * + 192 (1Mbps, 24 ytes) + * = 384 us + 2us(MAC/BB DELAY + */ + tx_delay = 386; + } else if (conf && (conf->def.chan->band == NL80211_BAND_5GHZ || + conf->def.chan->band == NL80211_BAND_6GHZ)) { + /* 6Mbps Beacon: */ + /*20(lsig)+2(service)+32(6mbps, 24 bytes) + *= 54us + 2us(MAC/BB DELAY) + */ + tx_delay = 56; + } + arvif->tbtt_offset -= tx_delay; + + ieee80211_queue_work(ar->hw, &arvif->update_bcn_template_work); +exit: + rcu_read_unlock(); + return ret; +} + +static int ath11k_wmi_tbtt_offset_event_parser(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + int ret = 0; + + ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi tbtt offset event tag 0x%x of len %d rcvd\n", + tag, len); + + switch (tag) { + case WMI_TAG_TBTT_OFFSET_EXT_EVENT: + break; + case WMI_TAG_ARRAY_STRUCT: + ret = ath11k_wmi_tlv_iter(ab, ptr, len, + ath11k_wmi_tbtt_offset_subtlv_parser, + data); + break; + default: + ath11k_warn(ab, "Received invalid tag for wmi tbtt offset event\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int ath11k_wmi_pull_tbtt_offset(struct ath11k_base *ab, struct sk_buff *skb, + struct wmi_tbtt_offset_ev_arg *arg) +{ + struct wmi_tbtt_offset_event *ev = NULL; + struct wmi_tbtt_offset_info tbtt_offset_info = {0}; + struct wmi_tlv *tlv; + int ret; + u8 *ptr; + u16 tlv_tag; + + ptr = skb->data; + + if (skb->len < (sizeof(*ev) + TLV_HDR_SIZE)) { + ath11k_warn(ab, "wmi_tbtt_offset event size invalid\n"); + return -EINVAL; + } + + tlv = (struct wmi_tlv *)ptr; + tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header); + ptr += sizeof(*tlv); + + if (tlv_tag == WMI_TAG_TBTT_OFFSET_EXT_EVENT) { + ev = (struct wmi_tbtt_offset_event *)ptr; + } else { + ath11k_warn(ab, "tbtt event received with invalid tag\n"); + return -EINVAL; + } + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tbtt_offset_event_parser, + &tbtt_offset_info); + if (ret) { + ath11k_warn(ab, "failed to parse tbtt tlv %d\n", ret); + return -EINVAL; + } + return 0; +} + static int ath11k_wmi_tlv_cfr_capture_evt_parse(struct ath11k_base *ab, u16 tag, u16 len, const void *ptr, void *data) @@ -10267,6 +10412,16 @@ static void ath11k_wmi_parse_cfr_capture_event(struct ath11k_base *ab, "failed to process cfr cpature ret = %d\n", ret); } +void ath11k_wmi_event_tbttoffset_update(struct ath11k_base *ab, struct sk_buff *skb) +{ + struct wmi_tbtt_offset_ev_arg arg = {}; + int ret; + + ret = ath11k_wmi_pull_tbtt_offset(ab, skb, &arg); + if (ret) + ath11k_warn(ab, "failed to parse tbtt offset event: %d\n", ret); +} + static int ath11k_wmi_peer_ratecode_subtlv_parser(struct ath11k_base *ab, u16 tag, u16 len, const void *ptr, void *data) @@ -10795,6 +10950,87 @@ int ath11k_wmi_send_afc_resp_rx_ind(struct ath11k *ar, int data_type) return ret; } +int ath11k_wmi_pdev_get_ani_status(struct ath11k *ar) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_pdev_get_ani_status_cmd *cmd = NULL; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_get_ani_status_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_PDEV_GET_CAL_STATUS_CONFIG_CMD) | + FIELD_PREP(WMI_TLV_LEN, + sizeof(*cmd) - TLV_HDR_SIZE); + cmd->pdev_id = ar->pdev->pdev_id; + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_GET_CAL_STATUS_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send get cal status cmd\n"); + dev_kfree_skb(skb); + return ret; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "wmi cal status cmd pdev id %d\n", + ar->pdev->pdev_id); + + return 0; +} + +static int ath11k_wmi_event_get_ani_status(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_pdev_cal_status_event *ev; + struct ath11k *ar; + int ret; + + + if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))) + return 0; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv of ani status event: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_PDEV_CAL_STATUS_EVENT]; + + if (!ev) { + ath11k_warn(ab, "failed to fetch ani status ev"); + kfree(tb); + return -EINVAL; + } + + if (ATH11K_TEST_CAL_STATUS(ev->cal_valid_bitmap, WMI_CAL_ANI)) { + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); + if (!ar) { + ath11k_warn(ab, "ani enabled event in invalid pdev %d\n", + ev->pdev_id); + rcu_read_unlock(); + return -EINVAL; + } + spin_lock_bh(&ar->data_lock); + ar->ani_enabled = ATH11K_TEST_CAL_STATUS(ev->cal_status_bitmap, WMI_CAL_ANI); + spin_unlock_bh(&ar->data_lock); + if (!completion_done(&ar->ani_status_event)) + complete(&ar->ani_status_event); + ath11k_dbg(ab, ATH11K_DBG_WMI, + "pdev id %d ani status %d\n", + ev->pdev_id, ar->ani_enabled); + rcu_read_unlock(); + } + return 0; +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -10907,8 +11143,10 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID: ath11k_wmi_obss_color_collision_event(ab, skb); break; - /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: + ath11k_wmi_event_tbttoffset_update(ab, skb); + break; + /* add Unsupported events here */ case WMI_PEER_OPER_MODE_CHANGE_EVENTID: case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: @@ -10959,6 +11197,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_PDEV_ANI_OFDM_LEVEL_EVENTID: ath11k_wmi_event_ani_ofdm_level(ab, skb); break; + case WMI_PDEV_GET_CAL_STATUS_EVENTID: + ath11k_wmi_event_get_ani_status(ab, skb); + break; case WMI_PEER_RATECODE_LIST_EVENTID: ath11k_wmi_event_peer_ratecode_list(ab, skb); break;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9704dba..a3ade7c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -301,6 +301,11 @@ enum wmi_tlv_cmd_id { WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID, WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID, WMI_PDEV_GET_TPC_STATS_CMDID, + WMI_PDEV_ENABLE_DURATION_BASED_TX_MODE_SELECTION_CMDID, + WMI_PDEV_GET_DPD_STATUS_CMDID, + WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID, + WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID, + WMI_PDEV_GET_CAL_STATUS_CMDID, WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_DELETE_CMDID, WMI_VDEV_START_REQUEST_CMDID, @@ -690,6 +695,8 @@ enum wmi_tlv_event_id { WMI_SERVICE_READY_EXT2_EVENTID, WMI_PDEV_MULTIPLE_VDEV_RESTART_RESP_EVENTID, WMI_PDEV_GET_TPC_STATS_EVENTID, + WMI_PDEV_GET_DPD_STATUS_EVENTID, + WMI_PDEV_GET_CAL_STATUS_EVENTID, WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, @@ -1973,6 +1980,9 @@ enum wmi_tlv_tag { WMI_TAG_AFC_6G_CHANNEL_INFO, WMI_TAG_AFC_CHAN_EIRP_POWER_INFO, + WMI_TAG_PDEV_GET_CAL_STATUS_CONFIG_CMD = 0x3DA, + WMI_TAG_PDEV_CAL_STATUS_EVENT, + WMI_TAG_MAX }; @@ -2844,6 +2854,31 @@ struct wmi_p2p_noa_descriptor { u32 start_time; }; +enum wmi_cal_list { + WMI_CAL_ADC, + WMI_CAL_BWFILTER, + WMI_CAL_PDET_AND_PAL, + WMI_CAL_RXDCO, + WMI_CAL_COMB_TXLO_TXIQ_RXIQ, + WMI_CAL_IBF, + WMI_CAL_PA_DROOP, + WMI_CAL_DAC, + WMI_CAL_ANI, + WMI_CAL_NOISE_FLOOR, + WMI_CAL_MAX_CAL_LIST +}; + +struct wmi_pdev_cal_status_event { + u32 pdev_id; + u32 cal_valid_bitmap; + u32 cal_status_bitmap; +} __packed; + +struct wmi_pdev_get_ani_status_cmd { + u32 tlv_header; + u32 pdev_id; +} __packed; + struct wmi_pdev_ani_event { u32 tlv_header; u32 ani_level; @@ -4633,6 +4668,24 @@ struct wmi_vdev_delete_resp_event { u32 vdev_id; } __packed; +struct wmi_tbtt_offset_info { + u32 vdev_id; + u32 tbtt_offset; + u32 tbtt_qtime_low_us; + u32 tbtt_qtime_high_us; +} __packed; + +struct wmi_tbtt_offset_event { + u32 num_vdevs; +} __packed; + +struct wmi_tbtt_offset_ev_arg { + u32 vdev_id; + u32 tbtt_offset; + u32 tbtt_qtime_low_us; + u32 tbtt_qtime_high_us; +} __packed; + #define WMI_REG_CLIENT_MAX 4 struct wmi_reg_chan_list_cc_ext_event { @@ -7209,5 +7262,5 @@ int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar, u32 vdev_id, struct ath11k_reg_tpc_power_info *param); int ath11k_wmi_send_afc_resp_rx_ind(struct ath11k *ar, int data_type); - +int ath11k_wmi_pdev_get_ani_status(struct ath11k *ar); #endif
diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index f3906db..9ed2559 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c
@@ -58,7 +58,7 @@ void ath6kl_tm_rx_event(struct ath6kl *ar, void *buf, size_t buf_len) if (nla_put_u32(skb, ATH6KL_TM_ATTR_CMD, ATH6KL_TM_CMD_TCMD) || nla_put(skb, ATH6KL_TM_ATTR_DATA, buf_len, buf)) goto nla_put_failure; - cfg80211_testmode_event(skb, GFP_KERNEL); + cfg80211_testmode_event(skb, GFP_KERNEL, false); return; nla_put_failure:
diff --git a/drivers/soc/qcom/bt_ipc.c b/drivers/soc/qcom/bt_ipc.c index 57927fc..7e2dd76 100644 --- a/drivers/soc/qcom/bt_ipc.c +++ b/drivers/soc/qcom/bt_ipc.c
@@ -476,14 +476,6 @@ int bt_ipc_sendmsg(struct bt_descriptor *btDesc, unsigned char *buf, int len) static uint32_t RX_CTXT_OFFSET = 0xe000; -static bool is_rx_ctxt_valid(struct context_info * rx_ctxt) -{ - uint8_t ridx = rx_ctxt->sring_buf_info.ridx; - uint32_t rbuf = rx_ctxt->sring_buf_info.rbuf; - return (ridx == 0 && - rbuf == (RX_CTXT_OFFSET + sizeof(*rx_ctxt))); -} - static void bt_ipc_worker(struct work_struct *work) { struct ring_buffer_info *rinfo; @@ -503,14 +495,6 @@ static void bt_ipc_worker(struct work_struct *work) if (unlikely(!atomic_read(&btDesc->state))) { btmem->rx_ctxt = (struct context_info *)(btmem->virt + RX_CTXT_OFFSET); - if (!is_rx_ctxt_valid(btmem->rx_ctxt)) { - // rx_ctrx not valid - // BTSS not ready - // skip this irq - spin_unlock(&btDesc->lock); - enable_irq(ipc->irq); - return; - } } else bt_ipc_process_ack(btDesc); @@ -573,6 +557,9 @@ int bt_ipc_init(struct bt_descriptor *btDesc) INIT_WORK(&ipc->work, bt_ipc_worker); + irq_set_irqchip_state(ipc->irq, IRQCHIP_STATE_PENDING, 0); + irq_set_status_flags(ipc->irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(dev, ipc->irq, NULL, bt_ipc_irq_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "bt_ipc_irq", btDesc);
diff --git a/drivers/soc/qcom/bt_tty.c b/drivers/soc/qcom/bt_tty.c index 78c8a4c..6eca6a3 100644 --- a/drivers/soc/qcom/bt_tty.c +++ b/drivers/soc/qcom/bt_tty.c
@@ -35,6 +35,9 @@ static bool btss_debug; module_param(btss_debug, bool, 0644); +static unsigned short btss_boot_delay = 500; +module_param(btss_boot_delay, ushort, 0644); + unsigned int pid_distinct(struct bt_descriptor *btDesc, enum pid_ops action) { int ret; @@ -77,6 +80,11 @@ unsigned int pid_distinct(struct bt_descriptor *btDesc, enum pid_ops action) pid_cursor->pid = pid; atomic_inc(&pid_cursor->refcnt); list_add_tail(&pid_cursor->list, pid_q); + + if (!atomic_read(&btDesc->state)) { + mdelay(btss_boot_delay); + enable_irq(btDesc->ipc.irq); + } out: return pid_cursor ? atomic_read(&pid_cursor->refcnt) : 0; } @@ -191,36 +199,6 @@ int bt_ioctl_cust_msg(struct tty_struct *tty, unsigned long arg) } static -int bt_rproc_fully_boot(struct bt_descriptor *btDesc, struct rproc *rproc) -{ - int retries = 3; - struct device *dev = &btDesc->pdev->dev; - while (retries) { - unsigned int wait_ms = 200; - const unsigned int interval_ms = wait_ms / 10; - int ret = rproc_boot(rproc); - if (ret) - return ret; - do { - if (atomic_read(&btDesc->state)) - return ret; - wait_ms -= interval_ms; - msleep(interval_ms); - } while(wait_ms >= interval_ms); - - if (!atomic_read(&btDesc->state)) { - rproc_shutdown(rproc); - --retries; - if (retries) - dev_warn(dev, "bt ipc doesn't start, retry\n"); - } - else - return ret; - } - return -ETIMEDOUT; -} - -static int bt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -233,7 +211,7 @@ int bt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) switch (cmd) { case IOCTL_IPC_BOOT: if (arg) { - ret = bt_rproc_fully_boot(btDesc, rproc); + ret = rproc_boot(rproc); if (ret) dev_err(dev, "m0 boot fail, ret = %d\n", ret); else
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index ed46fd7..c7a8c43 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c
@@ -1928,6 +1928,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (w_index != 0x5 || (w_value >> 8)) break; interface = w_value & 0xFF; + if (interface >= MAX_CONFIG_INTERFACES || + !os_desc_cfg->interface[interface]) + break; buf[6] = w_index; count = count_ext_prop(os_desc_cfg, interface);
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 04c142c..ab827c1 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c
@@ -637,14 +637,17 @@ static int rndis_set_response(struct rndis_params *params, rndis_set_cmplt_type *resp; rndis_resp_t *r; + BufLength = le32_to_cpu(buf->InformationBufferLength); + BufOffset = le32_to_cpu(buf->InformationBufferOffset); + if ((BufLength > RNDIS_MAX_TOTAL_SIZE) || + (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE)) + return -EINVAL; + r = rndis_add_response(params, sizeof(rndis_set_cmplt_type)); if (!r) return -ENOMEM; resp = (rndis_set_cmplt_type *)r->buf; - BufLength = le32_to_cpu(buf->InformationBufferLength); - BufOffset = le32_to_cpu(buf->InformationBufferOffset); - #ifdef VERBOSE_DEBUG pr_debug("%s: Length: %d\n", __func__, BufLength); pr_debug("%s: Offset: %d\n", __func__, BufOffset);
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index cabcbb4..3521d04 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c
@@ -1815,8 +1815,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); value = -EINVAL; if (dev->buf) { + spin_unlock_irq(&dev->lock); kfree(kbuf); - goto fail; + return value; } dev->buf = kbuf; @@ -1863,8 +1864,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) value = usb_gadget_probe_driver(&gadgetfs_driver); if (value != 0) { - kfree (dev->buf); - dev->buf = NULL; + spin_lock_irq(&dev->lock); + goto fail; } else { /* at this point "good" hardware has for the first time * let the USB the host see us. alternatively, if users @@ -1881,6 +1882,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) return value; fail: + dev->config = NULL; + dev->hs_config = NULL; + dev->dev = NULL; spin_unlock_irq (&dev->lock); pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev); kfree (dev->buf);
diff --git a/include/linux/hid.h b/include/linux/hid.h index c7044a1..854e68d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h
@@ -829,6 +829,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev, return hdev->ll_driver == driver; } +static inline bool hid_is_usb(struct hid_device *hdev) +{ + return hid_is_using_ll_driver(hdev, &usb_hid_driver); +} + #define PM_HINT_FULLON 1<<5 #define PM_HINT_NORMAL 1<<1
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 9535b62..39a1ed5 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h
@@ -58,6 +58,7 @@ extern struct net_device *br_port_dev_get(struct net_device *dev, struct sk_buff *skb, unsigned int cookie); extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr); +extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid); extern void br_dev_update_stats(struct net_device *dev, struct rtnl_link_stats64 *nlstats); extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 2f3f85f..723d002 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h
@@ -1342,6 +1342,11 @@ struct cfg80211_color_change_settings { u8 color; }; +struct cfg80211_6ghz_power_mode_settings { + u8 he_6ghz_pwr_mode; + struct cfg80211_beacon_data beacon_next; +}; + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #define CFG80211_MAX_NUM_DIFFERENT_BI 16 @@ -4096,6 +4101,7 @@ struct mgmt_frame_regs { * @set_unsol_bcast_probe_resp: Set unsolicited broadcast probe response * transmission parameters. * @color_change: initiate a color change (with color change). + * @power_mode_change_6ghz: initiate power mode change for 6 GHZ. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -4432,6 +4438,8 @@ struct cfg80211_ops { int (*color_change)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_color_change_settings *params); + int (*power_mode_change_6ghz)(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_6ghz_power_mode_settings *params); }; /* @@ -6828,7 +6836,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, int vendor_event_idx, int approxlen, gfp_t gfp); -void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp); +void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp, bool testlogs); /** * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply @@ -6958,7 +6966,7 @@ cfg80211_vendor_event_alloc_ucast(struct wiphy *wiphy, */ static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp) { - __cfg80211_send_event_skb(skb, gfp); + __cfg80211_send_event_skb(skb, gfp, false); } #ifdef CONFIG_NL80211_TESTMODE @@ -7059,9 +7067,10 @@ cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp) * by cfg80211_testmode_alloc_event_skb(), as an event. It always * consumes it. */ -static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) +static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp, + bool testlogs) { - __cfg80211_send_event_skb(skb, gfp); + __cfg80211_send_event_skb(skb, gfp, testlogs); } #define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd), @@ -7825,6 +7834,14 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, u8 count, bool quiet); +/*cfg80211_6ghz_power_mode_notify - Notify new HE 6GHZ power mode + * @dev: the device on which power mode change is done + * @gfp: allocation flags + * @cmd: the actual event to be notified + */ +void cfg80211_6ghz_power_mode_notify(struct net_device *dev, + gfp_t gfp, enum nl80211_commands cmd); + /** * ieee80211_operating_class_to_band - convert operating class to band * @@ -8433,4 +8450,14 @@ static inline void cfg80211_color_change_notify(struct net_device *dev) 0, 0); } +/*cfg80211_6ghz_power_mode_change_notify -notify 6GHZ power mode change + * @dev: the device on which the power mode change is done + * + * Inform the userspace about the successful change in 6GHZ power mode + */ +static inline void cfg80211_6ghz_power_mode_change_notify(struct net_device *dev) +{ + cfg80211_6ghz_power_mode_notify(dev, GFP_KERNEL, + NL80211_CMD_POWER_MODE_CHANGE_COMPLETED); +} #endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 96b25c1..6136b3f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h
@@ -360,7 +360,8 @@ enum ieee80211_bss_change { BSS_CHANGED_HE_OBSS_PD = 1<<28, BSS_CHANGED_HE_BSS_COLOR = 1<<29, BSS_CHANGED_FILS_DISCOVERY = 1<<30, - BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31, + BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1ULL<<31, + BSS_CHANGED_6G_POWER_MODE = 1ULL<<32, /* when adding here, make sure to change ieee80211_reconfig */ }; @@ -1829,6 +1830,7 @@ struct ieee80211_vif { bool color_change_active; u8 color_change_color; u8 bmiss_threshold; + bool noqueue_enable; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); @@ -4067,10 +4069,10 @@ struct ieee80211_ops { void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, - u32 changed); + u64 changed); void (*nss_bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 changed); + u64 changed); int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -5257,6 +5259,16 @@ void ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter); void ieee80211_csa_finish(struct ieee80211_vif *vif); /** + * ieee80211_6ghz_power_mode_switch_done - notify mac80211 about power mode + * change. + * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * + * After power change for 6 GHZ interface successful, this function must + * be called by the driver to notify mac80211 about power mode change. + */ +void ieee80211_6ghz_power_mode_switch_done (struct ieee80211_vif *vif); + +/** * ieee80211_beacon_cntdwn_is_complete - find out if countdown reached 1 * @vif: &struct ieee80211_vif pointer from the add_interface callback. *
diff --git a/include/net/regulatory.h b/include/net/regulatory.h index ddbf9e7..12266ef 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h
@@ -176,6 +176,7 @@ enum ieee80211_regulatory_flags { REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), REGULATORY_IGNORE_STALE_KICKOFF = BIT(6), REGULATORY_WIPHY_SELF_MANAGED = BIT(7), + REGULATORY_SET_BY_6GHZ_AFC = BIT(8), }; struct ieee80211_freq_range {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index e8ccb6f..06f1dfc 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h
@@ -51,6 +51,7 @@ #define NL80211_MULTICAST_GROUP_VENDOR "vendor" #define NL80211_MULTICAST_GROUP_NAN "nan" #define NL80211_MULTICAST_GROUP_TESTMODE "testmode" +#define NL80211_MULTICAST_GROUP_TESTLOGS "testlogs" #define NL80211_EDMG_BW_CONFIG_MIN 4 #define NL80211_EDMG_BW_CONFIG_MAX 15 @@ -1213,7 +1214,11 @@ * @NL80211_CMD_AWGN_DETECT: Once AWGN interference is detected on the operating * channel, userspace is notified with the interference bitmap using * %NL80211_ATTR_AWGN_INTERFERENCE_BITMAP - + * @NL80211_CMD_SET_6GHZ_POWER_MODE: User can set HE 6 GHZ power mode using userspace + * application controlling AP cli(i.e hostapd_cli).This command is used to set this + * power mode to the driver. + * @NL80211_CMD_POWER_MODE_CHANGE_COMPLETED: Notify the successful 6GHZ power mode change + * to userspace to update its power mode * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1459,6 +1464,9 @@ enum nl80211_commands { NL80211_CMD_COLOR_CHANGE_ANNOUNCEMENT_COMPLETED, NL80211_CMD_AWGN_DETECT, + NL80211_CMD_SET_6GHZ_POWER_MODE, + NL80211_CMD_POWER_MODE_CHANGE_COMPLETED, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -4033,6 +4041,7 @@ enum nl80211_reg_initiator { NL80211_REGDOM_SET_BY_USER, NL80211_REGDOM_SET_BY_DRIVER, NL80211_REGDOM_SET_BY_COUNTRY_IE, + NL80211_REGDOM_SET_BY_AFC, }; /**
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 79682c2..4c7f75f 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c
@@ -914,6 +914,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param) opt = fs_parse(fc, &cgroup1_fs_parameters, param, &result); if (opt == -ENOPARAM) { if (strcmp(param->key, "source") == 0) { + if (param->type != fs_value_is_string) + return invalf(fc, "Non-string source"); if (fc->source) return invalf(fc, "Multiple sources not supported"); fc->source = param->string;
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 639d5e7..332cc2b 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c
@@ -398,6 +398,7 @@ static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t by return 0; pipe->nrbufs++; buf->ops = &page_cache_pipe_buf_ops; + buf->flags = 0; get_page(buf->page = page); buf->offset = offset; buf->len = bytes; @@ -523,6 +524,7 @@ static size_t push_pipe(struct iov_iter *i, size_t size, if (!page) break; pipe->nrbufs++; + pipe->bufs[idx].flags = 0; pipe->bufs[idx].ops = &default_pipe_buf_ops; pipe->bufs[idx].page = page; pipe->bufs[idx].offset = 0;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 353690b..a9d1a05 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c
@@ -686,6 +686,24 @@ void br_refresh_fdb_entry(struct net_device *dev, const char *addr) } EXPORT_SYMBOL_GPL(br_refresh_fdb_entry); +/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */ +void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid) +{ + struct net_bridge_fdb_entry *fdb; + struct net_bridge_port *p = br_port_get_rcu(dev); + + if (!p || p->state == BR_STATE_DISABLED) + return; + + rcu_read_lock(); + fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid); + if (likely(fdb)) { + fdb->updated = jiffies; + } + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(br_fdb_entry_refresh); + /* Look up the MAC address in the device's bridge fdb table */ struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev, const char *addr, __u16 vid)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index c2ee61b..eb90194 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c
@@ -842,14 +842,16 @@ void br_dev_update_stats(struct net_device *dev, return; br = netdev_priv(dev); - stats = per_cpu_ptr(br->stats, 0); + stats = this_cpu_ptr(br->stats); + local_bh_disable(); u64_stats_update_begin(&stats->syncp); stats->rx_packets += nlstats->rx_packets; stats->rx_bytes += nlstats->rx_bytes; stats->tx_packets += nlstats->tx_packets; stats->tx_bytes += nlstats->tx_bytes; u64_stats_update_end(&stats->syncp); + local_bh_enable(); } EXPORT_SYMBOL_GPL(br_dev_update_stats);
diff --git a/net/core/skbuff_recycle.h b/net/core/skbuff_recycle.h index ab14aec..c93c87c 100644 --- a/net/core/skbuff_recycle.h +++ b/net/core/skbuff_recycle.h
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, 2022, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -43,7 +43,7 @@ #define SKB_RECYCLE_SIZE 2304 #define SKB_RECYCLE_MIN_SIZE SKB_RECYCLE_SIZE #define SKB_RECYCLE_MAX_SIZE (3904 - NET_SKB_PAD) -#define SKB_RECYCLE_MAX_SKBS 1024 +#define SKB_RECYCLE_MAX_SKBS 8192 #define SKB_RECYCLE_SPARE_MAX_SKBS 256
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 480d0b2..8b72b31 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c
@@ -2722,6 +2722,7 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u rv = 1; } else if (im) { if (src_addr) { + spin_lock_bh(&im->lock); for (psf = im->sources; psf; psf = psf->sf_next) { if (psf->sf_inaddr == src_addr) break; @@ -2732,6 +2733,7 @@ int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u im->sfcount[MCAST_EXCLUDE]; else rv = im->sfcount[MCAST_EXCLUDE] != 0; + spin_unlock_bh(&im->lock); } else rv = 1; /* unspecified source; tentatively allow */ }
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 07504da..7611a1a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c
@@ -927,19 +927,26 @@ static int ieee80211_set_fils_discovery(struct wiphy *wiphy, struct ieee80211_fils_discovery *fd; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!params->tmpl || !params->tmpl_len) - return -EINVAL; - fd = &sdata->vif.bss_conf.fils_discovery; fd->min_interval = params->min_interval; fd->max_interval = params->max_interval; old = sdata_dereference(sdata->u.ap.fils_discovery, sdata); + + if (!fd->max_interval) { + new = NULL; + goto free_old_fils; + } + + if (!params->tmpl || !params->tmpl_len) + return -EINVAL; + new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL); if (!new) return -ENOMEM; new->len = params->tmpl_len; memcpy(new->data, params->tmpl, params->tmpl_len); +free_old_fils: rcu_assign_pointer(sdata->u.ap.fils_discovery, new); if (old) @@ -957,17 +964,24 @@ ieee80211_set_unsol_bcast_probe_resp(struct wiphy *wiphy, struct unsol_bcast_probe_resp_data *new, *old = NULL; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!params->tmpl || !params->tmpl_len) - return -EINVAL; - sdata->vif.bss_conf.unsol_bcast_probe_resp_interval = params->interval; old = sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp, sdata); + + if (!params->interval) { + new = NULL; + goto free_old_ubpr; + } + + if (!params->tmpl || !params->tmpl_len) + return -EINVAL; + new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL); if (!new) return -ENOMEM; new->len = params->tmpl_len; memcpy(new->data, params->tmpl, params->tmpl_len); +free_old_ubpr: rcu_assign_pointer(sdata->u.ap.unsol_bcast_probe_resp, new); if (old) @@ -2923,18 +2937,18 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, static int ieee80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm) + int *mbm) { struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); if (local->ops->get_txpower) - return drv_get_txpower(local, sdata, dbm); + return drv_get_txpower(local, sdata, mbm); if (!local->use_chanctx) - *dbm = local->hw.conf.power_level; + *mbm = DBM_TO_MBM(local->hw.conf.power_level); else - *dbm = sdata->vif.bss_conf.txpower; + *mbm = DBM_TO_MBM(sdata->vif.bss_conf.txpower); return 0; } @@ -3451,6 +3465,39 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) } } +void ieee80211_power_mode_switch_work(struct work_struct *work) +{ + int ret; + u32 changed = 0; + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + power_mode_switch_work); + struct ieee80211_local *local = sdata->local; + + sdata_lock(sdata); + mutex_lock(&local->mtx); + + if (sdata->vif.csa_active || !sdata->u.ap.next_beacon) + goto unlock; + + ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, + NULL, NULL); + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + + if (ret < 0) { + goto unlock; + } + changed = ret; + + ieee80211_bss_info_change_notify(sdata, changed); + cfg80211_6ghz_power_mode_change_notify(sdata->dev); + +unlock: + mutex_unlock(&local->mtx); + sdata_unlock(sdata); +} + void ieee80211_csa_finalize_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = @@ -4343,6 +4390,62 @@ static int ieee80211_set_sar_specs(struct wiphy *wiphy, return local->ops->set_sar_specs(&local->hw, sar); } +void ieee80211_6ghz_power_mode_switch_done(struct ieee80211_vif *vif) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + + ieee80211_queue_work(&sdata->local->hw, &sdata->power_mode_switch_work); +} +EXPORT_SYMBOL(ieee80211_6ghz_power_mode_switch_done); + +static int ieee80211_set_power_mode_changed_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_6ghz_power_mode_settings *params) +{ + + if (sdata->vif.type != NL80211_IFTYPE_AP) + return -EOPNOTSUPP; + + sdata->u.ap.next_beacon = + cfg80211_beacon_dup(¶ms->beacon_next); + + if (!sdata->u.ap.next_beacon) + return -ENOMEM; + + return 0; +} + +static int +ieee80211_6ghz_power_mode_change(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_6ghz_power_mode_settings *params) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + u64 changed = 0; + + sdata_assert_lock(sdata); + mutex_lock(&local->mtx); + + if (sdata->vif.csa_active) { + err = -EBUSY; + goto out; + } + + err = ieee80211_set_power_mode_changed_beacon(sdata, params); + if (err) + goto out; + + wdev->reg_6g_power_mode = params->he_6ghz_pwr_mode; + + changed = BSS_CHANGED_6G_POWER_MODE; + ieee80211_bss_info_change_notify(sdata, changed); +out: + mutex_unlock(&local->mtx); + + return err; +} + static int ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, u32 *changed) { @@ -4661,4 +4764,5 @@ const struct cfg80211_ops mac80211_config_ops = { .set_fils_discovery = ieee80211_set_fils_discovery, .set_unsol_bcast_probe_resp = ieee80211_set_unsol_bcast_probe_resp, .color_change = ieee80211_color_change, + .power_mode_change_6ghz = ieee80211_6ghz_power_mode_change, };
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 491661a..01b1851 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c
@@ -329,6 +329,32 @@ static ssize_t ieee80211_if_parse_bmiss_threshold(struct ieee80211_sub_if_data * IEEE80211_IF_FILE_RW(bmiss_threshold); +static ssize_t ieee80211_if_fmt_noqueue_enable(const struct ieee80211_sub_if_data *sdata, + char *buf, int buflen) +{ + return snprintf(buf, buflen, "%u\n", sdata->vif.noqueue_enable); +} + +static ssize_t ieee80211_if_parse_noqueue_enable(struct ieee80211_sub_if_data *sdata, + const char *buf, int buflen) +{ + int ret; + u8 val; + + ret = kstrtou8(buf, 0, &val); + if (ret) + return ret; + + if (val > 1) + return -EINVAL; + + sdata->vif.noqueue_enable = val; + + return buflen; +} + +IEEE80211_IF_FILE_RW(noqueue_enable); + static ssize_t ieee80211_if_parse_wmm_param(struct ieee80211_sub_if_data *sdata, const char *user_buf, int count) @@ -839,6 +865,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(multicast_to_unicast, 0600); DEBUGFS_ADD_MODE(bmiss_threshold, 0600); DEBUGFS_ADD_MODE(wmm_param, 0200); + DEBUGFS_ADD_MODE(noqueue_enable, 0600); } static void add_vlan_files(struct ieee80211_sub_if_data *sdata) @@ -861,6 +888,7 @@ static void add_mesh_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(estab_plinks, 0400); DEBUGFS_ADD_MODE(bmiss_threshold, 0600); DEBUGFS_ADD_MODE(wmm_param, 0200); + DEBUGFS_ADD_MODE(noqueue_enable, 0600); } static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index c9cc451..1883e6c 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c
@@ -68,6 +68,9 @@ int drv_add_interface(struct ieee80211_local *local, if (ret == 0) sdata->flags |= IEEE80211_SDATA_IN_DRIVER; + if (sdata->vif.type == NL80211_IFTYPE_AP) + sdata->vif.noqueue_enable = true; + return ret; }
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 386059a..20f4e92 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h
@@ -150,7 +150,7 @@ static inline int drv_config(struct ieee80211_local *local, u32 changed) static inline void drv_bss_info_changed(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { might_sleep(); @@ -181,7 +181,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, static inline void drv_nss_bss_info_changed(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *info, - u32 changed) + u64 changed) { might_sleep();
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e4f3dcc..e9e6e16 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h
@@ -247,6 +247,8 @@ struct ieee80211_rx_data { u32 tkip_iv32; u16 tkip_iv16; + u16 last_legacy_rate_idx; + enum nl80211_band last_legacy_band; }; struct ieee80211_csa_settings { @@ -952,6 +954,7 @@ struct ieee80211_sub_if_data { struct cfg80211_chan_def csa_chandef; struct work_struct color_change_finalize_work; + struct work_struct power_mode_switch_work; struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ @@ -1658,7 +1661,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed); + u64 changed); void ieee80211_nss_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_configure_filter(struct ieee80211_local *local); @@ -1787,6 +1790,7 @@ int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, /* channel switch handling */ void ieee80211_csa_finalize_work(struct work_struct *work); +void ieee80211_power_mode_switch_work(struct work_struct *work); int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params); /* awgn interference handling */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ba47dd0..25701fa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c
@@ -490,6 +490,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do } cancel_work_sync(&sdata->color_change_finalize_work); + cancel_work_sync(&sdata->power_mode_switch_work); /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { @@ -1623,6 +1624,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work); + INIT_WORK(&sdata->power_mode_switch_work, ieee80211_power_mode_switch_work); INIT_LIST_HEAD(&sdata->assigned_chanctx_list); INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index e453a9b..224e801 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c
@@ -200,7 +200,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) } void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed) + u64 changed) { struct ieee80211_local *local = sdata->local;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index fc465bf..cd316b0 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c
@@ -299,6 +299,7 @@ void ieee80211s_update_metric(struct ieee80211_local *local, { struct ieee80211_tx_info *txinfo = st->info; int failed = 0; + u32 fail_avg; struct rate_info rinfo; failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); @@ -316,6 +317,11 @@ void ieee80211s_update_metric(struct ieee80211_local *local, sta->mesh->fail_cnt = 0; } + fail_avg = ewma_mesh_fail_avg_read(&sta->mesh->fail_avg); + if (!fail_avg) + /* init it at a low value - 0 is tricky */ + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1); + /* moving average, scaled to 100. * feed failure as 100 and success as 0 */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index efc6cf6..b71c3ca 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c
@@ -3927,6 +3927,14 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, status = IEEE80211_SKB_RXCB((rx->skb)); sband = rx->local->hw.wiphy->bands[status->band]; + if (!status || !sband) { + printk(KERN_ERR "status %pM or sband %pM is Null rate_idx %u legacy_band %d\n", + status, sband, rx->last_legacy_rate_idx, rx->last_legacy_band); + if (status) { + printk(KERN_ERR "STATUS idx %d\n", status->rate_idx); + printk(KERN_ERR "rate %pM\n", &sband->bitrates[status->rate_idx]); + } + } if (status->encoding == RX_ENC_LEGACY) rate = &sband->bitrates[status->rate_idx]; @@ -4576,6 +4584,16 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, return; } + /* Get the multicat broadcast stats */ + ieee80211_mc_bc_stats(((struct ethhdr *)rx->skb->data)->h_dest, rx); + + if (!ieee80211_mc_bc_rx_limit(((struct ethhdr *)rx->skb->data)->h_dest, + rx)) { + /* free the omitted skb's before returning from here */ + dev_kfree_skb(skb); + return; + } + /* deliver to local stack */ skb->protocol = eth_type_trans(skb, fast_rx->dev); memset(skb->cb, 0, sizeof(skb->cb)); @@ -4585,7 +4603,6 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, netif_receive_skb(skb); atomic_inc(&sta->rx_netif_pkts); - } static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, @@ -4760,54 +4777,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, /* push the addresses in front */ memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); - skb->dev = fast_rx->dev; - - ieee80211_rx_stats(fast_rx->dev, skb->len); - - /* The seqno index has the same property as needed - * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS - * for non-QoS-data frames. Here we know it's a data - * frame, so count MSDUs. - */ - u64_stats_update_begin(&stats->syncp); - stats->msdu[rx->seqno_idx]++; - stats->bytes += orig_len; - u64_stats_update_end(&stats->syncp); - - if (fast_rx->internal_forward) { - struct sk_buff *xmit_skb = NULL; - if (is_multicast_ether_addr(addrs.da)) { - xmit_skb = skb_copy(skb, GFP_ATOMIC); - } else if (!ether_addr_equal(addrs.da, addrs.sa) && - sta_info_get(rx->sdata, addrs.da)) { - xmit_skb = skb; - skb = NULL; - } - - if (xmit_skb) { - /* - * Send to wireless media and increase priority by 256 - * to keep the received priority instead of - * reclassifying the frame (see cfg80211_classify8021d). - */ - xmit_skb->priority += 256; - xmit_skb->protocol = htons(ETH_P_802_3); - skb_reset_network_header(xmit_skb); - skb_reset_mac_header(xmit_skb); - dev_queue_xmit(xmit_skb); - } - - if (!skb) - return true; - } - - /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, fast_rx->dev); - memset(skb->cb, 0, sizeof(skb->cb)); - if (rx->list) - list_add_tail(&skb->list, rx->list); - else - netif_receive_skb(skb); + ieee80211_rx_8023(rx, fast_rx, orig_len); return true; drop: @@ -4915,6 +4885,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct list_head *list) { struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; __le16 fc; @@ -4929,6 +4900,14 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.local = local; rx.list = list; + if (status && status->encoding == RX_ENC_LEGACY) { + rx.last_legacy_rate_idx = status->rate_idx; + rx.last_legacy_band = status->band; + } + + if (!status) + pr_err("STATUS not found\n"); + if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) I802_DEBUG_INC(local->dot11ReceivedFragmentCount);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 644a7de..517da04 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c
@@ -2138,7 +2138,7 @@ u8 sta_info_tx_streams(struct sta_info *sta) } static struct ieee80211_sta_rx_stats * -sta_get_last_rx_stats(struct sta_info *sta) +sta_get_last_rx_stats(struct sta_info *sta, bool is_rx_bitrate) { struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; struct ieee80211_local *local = sta->local; @@ -2147,15 +2147,17 @@ sta_get_last_rx_stats(struct sta_info *sta) if (ieee80211_hw_check(&local->hw, SUPPORTS_NSS_OFFLOAD)) return stats; - if (!ieee80211_hw_check(&local->hw, USES_RSS)) + if (!ieee80211_hw_check(&local->hw, USES_RSS) || !sta->pcpu_rx_stats) return stats; for_each_possible_cpu(cpu) { struct ieee80211_sta_rx_stats *cpustats; + u16 rate; cpustats = per_cpu_ptr(sta->pcpu_rx_stats, cpu); + rate = READ_ONCE(cpustats->last_rate); - if(!cpustats->last_rx) + if(!cpustats->last_rx || (is_rx_bitrate && (rate == STA_STATS_RATE_INVALID))) continue; if (time_after(cpustats->last_rx, stats->last_rx)) @@ -2219,7 +2221,7 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate, static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) { - u16 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate); + u16 rate = READ_ONCE(sta_get_last_rx_stats(sta, true)->last_rate); if (rate == STA_STATS_RATE_INVALID) return -EINVAL; @@ -2319,7 +2321,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, int i, ac, cpu; struct ieee80211_sta_rx_stats *last_rxstats; - last_rxstats = sta_get_last_rx_stats(sta); + last_rxstats = sta_get_last_rx_stats(sta, false); sinfo->generation = sdata->local->sta_generation; @@ -2599,7 +2601,7 @@ u32 sta_get_expected_throughput(struct sta_info *sta) unsigned long ieee80211_sta_last_active(struct sta_info *sta) { - struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta); + struct ieee80211_sta_rx_stats *stats = sta_get_last_rx_stats(sta, false); if (!sta->status_stats.last_ack || time_after(stats->last_rx, sta->status_stats.last_ack))
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 912019c..a6c0174 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c
@@ -414,8 +414,12 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) if (ac_queue == queue || (sdata->vif.cab_queue == queue && local->queue_stop_reasons[ac_queue] == 0 && - skb_queue_empty(&local->pending[ac_queue]))) + skb_queue_empty(&local->pending[ac_queue]))) { + if (sdata->vif.noqueue_enable) + continue; + netif_wake_subqueue(sdata->dev, ac); + } } } } @@ -514,6 +518,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, for (ac = 0; ac < n_acs; ac++) { if (sdata->vif.hw_queue[ac] == queue || sdata->vif.cab_queue == queue) { + if (!local->ops->wake_tx_queue && sdata->vif.noqueue_enable) + continue; + if (!local->ops->wake_tx_queue) { netif_stop_subqueue(sdata->dev, ac); continue;
diff --git a/net/wireless/core.c b/net/wireless/core.c index 57e7703..4a59bf6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c
@@ -334,11 +334,17 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) struct wireless_dev *wdev, *tmp; ASSERT_RTNL(); - lockdep_assert_wiphy(&rdev->wiphy); list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { - if (wdev->nl_owner_dead) + if (wdev->nl_owner_dead) { + if (wdev->netdev) + dev_close(wdev->netdev); + + wiphy_lock(&rdev->wiphy); + cfg80211_leave(rdev, wdev); rdev_del_virtual_intf(rdev, wdev); + wiphy_unlock(&rdev->wiphy); + } } } @@ -350,9 +356,7 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) destroy_work); rtnl_lock(); - wiphy_lock(&rdev->wiphy); cfg80211_destroy_ifaces(rdev); - wiphy_unlock(&rdev->wiphy); rtnl_unlock(); }
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 472549a..dd890dc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c
@@ -47,7 +47,8 @@ enum nl80211_multicast_groups { NL80211_MCGRP_MLME, NL80211_MCGRP_VENDOR, NL80211_MCGRP_NAN, - NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ + NL80211_MCGRP_TESTMODE, + NL80211_MCGRP_TESTLOGS /* keep last - ifdef! */ }; static const struct genl_multicast_group nl80211_mcgrps[] = { @@ -58,7 +59,8 @@ static const struct genl_multicast_group nl80211_mcgrps[] = { [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR }, [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN }, #ifdef CONFIG_NL80211_TESTMODE - [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE } + [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }, + [NL80211_MCGRP_TESTLOGS] = { .name = NL80211_MULTICAST_GROUP_TESTLOGS } #endif }; @@ -3021,6 +3023,7 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, { struct netlink_ext_ack *extack = info->extack; struct nlattr **attrs = info->attrs; + struct wireless_dev *wdev = info->user_ptr[1]; enum nl80211_regulatory_power_modes mode = NL80211_REG_AP_LPI; u32 control_freq; @@ -3033,10 +3036,12 @@ int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, control_freq += nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ_OFFSET]); - if (info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]) + if (info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]) { mode = nla_get_u8(info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]); - else - mode = chandef->mode; + } else { + if (wdev) + mode = wdev->reg_6g_power_mode; + } memset(chandef, 0, sizeof(*chandef)); @@ -3632,12 +3637,12 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag } if (rdev->ops->get_tx_power) { - int dbm, ret; + int mbm, ret; - ret = rdev_get_tx_power(rdev, wdev, &dbm); + ret = rdev_get_tx_power(rdev, wdev, &mbm); if (ret == 0 && nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, - DBM_TO_MBM(dbm))) + mbm)) goto nla_put_failure; } @@ -3986,7 +3991,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) return err; } -static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +static int _nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; @@ -3995,9 +4000,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; - /* to avoid failing a new interface creation due to pending removal */ - cfg80211_destroy_ifaces(rdev); - memset(¶ms, 0, sizeof(params)); if (!info->attrs[NL80211_ATTR_IFNAME]) @@ -4085,6 +4087,21 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } +static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + int ret; + + /* to avoid failing a new interface creation due to pending removal */ + cfg80211_destroy_ifaces(rdev); + + wiphy_lock(&rdev->wiphy); + ret = _nl80211_new_interface(skb, info); + wiphy_unlock(&rdev->wiphy); + + return ret; +} + static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -5245,6 +5262,11 @@ static int nl80211_set_fils_discovery(struct sk_buff *skb, if (ret) return ret; + fd.max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]); + if (!fd.max_interval) { + goto set_fils; + } + if (!tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN] || !tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX] || !tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]) @@ -5253,8 +5275,8 @@ static int nl80211_set_fils_discovery(struct sk_buff *skb, fd.tmpl_len = nla_len(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]); fd.tmpl = nla_data(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]); fd.min_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN]); - fd.max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]); +set_fils: wdev_lock(wdev); ret = rdev_set_fils_discovery(rdev, dev, &fd); wdev_unlock(wdev); @@ -5283,14 +5305,19 @@ nl80211_set_unsol_bcast_probe_resp(struct sk_buff *skb, struct genl_info *info) if (ret) return ret; + params.interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]); + + if (!params.interval) + goto set_ubpr; + if (!tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] || !tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]) return -EINVAL; params.tmpl = nla_data(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]); params.tmpl_len = nla_len(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]); - params.interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]); +set_ubpr: wdev_lock(wdev); ret = rdev_set_unsol_bcast_probe_resp(rdev, dev, ¶ms); wdev_unlock(wdev); @@ -10698,7 +10725,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, } EXPORT_SYMBOL(__cfg80211_alloc_event_skb); -void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp) +void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp, bool testlogs) { struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; void *hdr = ((void **)skb->cb)[1]; @@ -10719,6 +10746,9 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp) if (data->nla_type == NL80211_ATTR_VENDOR_DATA) mcgrp = NL80211_MCGRP_VENDOR; + if (testlogs) + mcgrp = NL80211_MCGRP_TESTLOGS; + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, mcgrp, gfp); } @@ -15001,6 +15031,74 @@ static int nl80211_set_tid_config(struct sk_buff *skb, return ret; } +static int nl80211_6ghz_power_mode_change(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct cfg80211_6ghz_power_mode_settings params = {}; + struct net_device *dev = info->user_ptr[1]; + struct ieee80211_channel *chan; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_chan_def *chan_def = &wdev->chandef; + const struct ieee80211_reg_rule *reg_rule; + u32 width; + int i, err, num_20mhz_channels, center_freq; + + if (!rdev->ops->power_mode_change_6ghz) + return -EOPNOTSUPP; + + if (wdev->iftype != NL80211_IFTYPE_AP) + return -EOPNOTSUPP; + + if (!info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]) + return -EINVAL; + + params.he_6ghz_pwr_mode = nla_get_u8(info->attrs[NL80211_ATTR_6G_REG_POWER_MODE]); + + if (params.he_6ghz_pwr_mode < NL80211_REG_AP_LPI || + params.he_6ghz_pwr_mode > NL80211_REG_AP_VLP || + params.he_6ghz_pwr_mode == wdev->reg_6g_power_mode) { + GENL_SET_ERR_MSG(info, "Invalid 6GHZ power mode configuration\n"); + return -EINVAL; + } + + if (chan_def->width == NL80211_CHAN_WIDTH_20) { + width = 20; + } else if (chan_def->width == NL80211_CHAN_WIDTH_40) { + width = 40; + } else if (chan_def->width == NL80211_CHAN_WIDTH_80) { + width = 80; + } else if (chan_def->width == NL80211_CHAN_WIDTH_160) { + width = 160; + } else { + GENL_SET_ERR_MSG(info, "Unsupported channel width for configuring power mode\n"); + return -EINVAL; + } + + num_20mhz_channels = width / 20 ; + + for (i = 0; i < num_20mhz_channels; i++) { + center_freq = chan_def->chan->center_freq + i * 20; + chan = ieee80211_get_6g_channel_khz(&rdev->wiphy, + MHZ_TO_KHZ(center_freq), + params.he_6ghz_pwr_mode); + + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { + GENL_SET_ERR_MSG(info, "Current channel does not support configured power mode\n"); + return -ENOTSUPP; + } + } + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next); + if (err) + return err; + + wdev_lock(wdev); + err = rdev_6g_power_mode_change(rdev, dev, ¶ms); + wdev_unlock(wdev); + + return err; +} + static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -15088,6 +15186,7 @@ static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) #define NL80211_FLAG_CLEAR_SKB 0x20 +#define NL80211_FLAG_NO_WIPHY_MTX 0x40 static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) @@ -15139,7 +15238,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, info->user_ptr[0] = rdev; } - if (rdev) { + if (rdev && !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) { wiphy_lock(&rdev->wiphy); /* we keep the mutex locked until post_doit */ __release(&rdev->wiphy.mtx); @@ -15164,7 +15263,8 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, } } - if (info->user_ptr[0]) { + if (info->user_ptr[0] && + !(ops->internal_flags & NL80211_FLAG_NO_WIPHY_MTX)) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; /* we kept the mutex locked since pre_doit */ @@ -15330,7 +15430,9 @@ static const struct genl_ops nl80211_ops[] = { .doit = nl80211_new_interface, .flags = GENL_UNS_ADMIN_PERM, .internal_flags = NL80211_FLAG_NEED_WIPHY | - NL80211_FLAG_NEED_RTNL, + NL80211_FLAG_NEED_RTNL | + /* we take the wiphy mutex later ourselves */ + NL80211_FLAG_NO_WIPHY_MTX, }, { .cmd = NL80211_CMD_DEL_INTERFACE, @@ -15625,7 +15727,9 @@ static const struct genl_ops nl80211_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_wiphy_netns, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_WIPHY, + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL | + NL80211_FLAG_NO_WIPHY_MTX, }, { .cmd = NL80211_CMD_GET_SURVEY, @@ -16090,6 +16194,14 @@ static const struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, + { + .cmd = NL80211_CMD_SET_6GHZ_POWER_MODE, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = nl80211_6ghz_power_mode_change, + .flags = GENL_UNS_ADMIN_PERM, + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_NEED_RTNL, + }, }; static struct genl_family nl80211_fam __ro_after_init = { @@ -17775,6 +17887,46 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev, } EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); +void cfg80211_6ghz_power_mode_notify(struct net_device *dev, + gfp_t gfp, enum nl80211_commands cmd) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct sk_buff *msg; + void *hdr; + u8 he_6ghz_power_mode = wdev->reg_6g_power_mode; + + ASSERT_WDEV_LOCK(wdev); + trace_cfg80211_6ghz_power_mode_notify(dev, cmd, he_6ghz_power_mode); + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + if(nla_put_u32(msg, NL80211_ATTR_6G_REG_POWER_MODE, he_6ghz_power_mode)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, gfp); + return; + +nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_6ghz_power_mode_notify); + void cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, enum nl80211_commands cmd, u8 count, u64 color_bitmap)
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 5f5b9c3..efc83d4 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h
@@ -573,12 +573,12 @@ static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, } static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, int *dbm) + struct wireless_dev *wdev, int *mbm) { int ret; trace_rdev_get_tx_power(&rdev->wiphy, wdev); - ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm); - trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); + ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, mbm); + trace_rdev_return_int_int(&rdev->wiphy, ret, MBM_TO_DBM(*mbm)); return ret; } @@ -1382,6 +1382,19 @@ static inline int rdev_set_unsol_bcast_probe_resp(struct cfg80211_registered_dev return ret; } +static inline int rdev_6g_power_mode_change(struct cfg80211_registered_device *rdev, + struct net_device *dev, + struct cfg80211_6ghz_power_mode_settings *params) +{ + int ret; + + trace_rdev_power_mode_change(&rdev->wiphy, dev, params); + ret = rdev->ops->power_mode_change_6ghz(&rdev->wiphy, dev, params); + trace_rdev_return_int(&rdev->wiphy, ret); + + return ret; +} + static inline int rdev_color_change(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_color_change_settings *params)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6d70f11..9b4763f 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c
@@ -3159,7 +3159,10 @@ static void reg_process_self_managed_hint(struct wiphy *wiphy) request.wiphy_idx = get_wiphy_idx(wiphy); request.alpha2[0] = regd->alpha2[0]; request.alpha2[1] = regd->alpha2[1]; - request.initiator = NL80211_REGDOM_SET_BY_DRIVER; + if (wiphy->regulatory_flags & REGULATORY_SET_BY_6GHZ_AFC) + request.initiator = NL80211_REGDOM_SET_BY_AFC; + else + request.initiator = NL80211_REGDOM_SET_BY_DRIVER; nl80211_send_wiphy_reg_change_event(&request); }
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 9d34885..3a70072 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h
@@ -3612,6 +3612,26 @@ TRACE_EVENT(rdev_set_unsol_bcast_probe_resp, __entry->interval, __entry->tmpl_len) ); +TRACE_EVENT(rdev_power_mode_change, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_6ghz_power_mode_settings *params), + TP_ARGS(wiphy, netdev, params), + TP_STRUCT__entry( + WIPHY_ENTRY + NETDEV_ENTRY + __field(u8, pwr_mode) + ), + TP_fast_assign( + WIPHY_ASSIGN; + NETDEV_ASSIGN; + __entry->pwr_mode = params->he_6ghz_pwr_mode; + ), + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT + ", pwr_mode: %u", + WIPHY_PR_ARG, NETDEV_PR_ARG, + __entry->pwr_mode) +); + TRACE_EVENT(rdev_color_change, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, struct cfg80211_color_change_settings *params), @@ -3636,6 +3656,25 @@ TRACE_EVENT(rdev_color_change, __entry->count) ); +TRACE_EVENT(cfg80211_6ghz_power_mode_notify, + TP_PROTO(struct net_device *netdev, + enum nl80211_commands cmd, + u8 he_6ghz_power_mode), + TP_ARGS(netdev, cmd,he_6ghz_power_mode), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(enum nl80211_commands,cmd) + __field(u8,he_6ghz_power_mode) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->cmd = cmd; + __entry->he_6ghz_power_mode = he_6ghz_power_mode; + ), + TP_printk(NETDEV_PR_FMT ", cmd: %x, he_6ghz_power_mode: %u", + NETDEV_PR_ARG, __entry->cmd, __entry->he_6ghz_power_mode) +); + TRACE_EVENT(cfg80211_bss_color_notify, TP_PROTO(struct net_device *netdev, enum nl80211_commands cmd,
diff --git a/net/wireless/util.c b/net/wireless/util.c index a55f41a..5d8cb26 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c
@@ -1379,7 +1379,7 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) 25599, /* 4.166666... */ 17067, /* 2.777777... */ 12801, /* 2.083333... */ - 11769, /* 1.851851... */ + 11377, /* 1.851725... */ 10239, /* 1.666666... */ 8532, /* 1.388888... */ 7680, /* 1.250000... */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index a8320dc..baa7511 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c
@@ -964,7 +964,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, /* well... oh well */ data->txpower.fixed = 1; data->txpower.disabled = rfkill_blocked(rdev->rfkill); - data->txpower.value = val; + data->txpower.value = MBM_TO_DBM(val); data->txpower.flags = IW_TXPOW_DBM; return 0;