From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:45:28 +0000 Subject: [PATCH] add boot partition size --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_linux_wq.c | 228 ++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 153 insertions(+), 75 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_linux_wq.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_linux_wq.c index 35d04fc..4253d47 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_linux_wq.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_linux_wq.c @@ -1,16 +1,17 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Broadcom Dongle Host Driver (DHD), Generic work queue framework * Generic interface to handle dhd deferred work events * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,7 +19,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -26,7 +27,7 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: dhd_linux_wq.c 514727 2014-11-12 03:02:48Z $ + * $Id: dhd_linux_wq.c 675839 2016-12-19 03:07:26Z $ */ #include <linux/init.h> @@ -47,28 +48,37 @@ #include <dhd_dbg.h> #include <dhd_linux_wq.h> -struct dhd_deferred_event_t { - u8 event; /* holds the event */ - void *event_data; /* Holds event specific data */ +typedef struct dhd_deferred_event { + u8 event; /* holds the event */ + void *event_data; /* holds event specific data */ event_handler_t event_handler; -}; -#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t) + unsigned long pad; /* for memory alignment to power of 2 */ +} dhd_deferred_event_t; + +#define DEFRD_EVT_SIZE (sizeof(dhd_deferred_event_t)) + +/* + * work events may occur simultaneously. + * can hold upto 64 low priority events and 16 high priority events + */ +#define DHD_PRIO_WORK_FIFO_SIZE (16 * DEFRD_EVT_SIZE) +#define DHD_WORK_FIFO_SIZE (64 * DEFRD_EVT_SIZE) + +#define DHD_FIFO_HAS_FREE_SPACE(fifo) \ + ((fifo) && (kfifo_avail(fifo) >= DEFRD_EVT_SIZE)) +#define DHD_FIFO_HAS_ENOUGH_DATA(fifo) \ + ((fifo) && (kfifo_len(fifo) >= DEFRD_EVT_SIZE)) struct dhd_deferred_wq { - struct work_struct deferred_work; /* should be the first member */ + struct work_struct deferred_work; /* should be the first member */ - /* - * work events may occur simultaneously. - * Can hold upto 64 low priority events and 4 high priority events - */ -#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t)) -#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t)) - struct kfifo *prio_fifo; + struct kfifo *prio_fifo; struct kfifo *work_fifo; u8 *prio_fifo_buf; u8 *work_fifo_buf; spinlock_t work_lock; void *dhd_info; /* review: does it require */ + u32 event_skip_mask; }; static inline struct kfifo* @@ -77,15 +87,11 @@ struct kfifo *fifo; gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) - fifo = kfifo_init(buf, size, flags, lock); -#else fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); if (!fifo) { return NULL; } kfifo_init(fifo, buf, size); -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ return fifo; } @@ -93,10 +99,7 @@ dhd_kfifo_free(struct kfifo *fifo) { kfifo_free(fifo); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) - /* FC11 releases the fifo memory */ kfree(fifo); -#endif } /* deferred work functions */ @@ -117,9 +120,8 @@ work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq), flags); - if (!work) { - DHD_ERROR(("%s: work queue creation failed \n", __FUNCTION__)); + DHD_ERROR(("%s: work queue creation failed\n", __FUNCTION__)); goto return_null; } @@ -130,10 +132,12 @@ /* allocate buffer to hold prio events */ fifo_size = DHD_PRIO_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + fifo_size = is_power_of_2(fifo_size) ? fifo_size : + roundup_pow_of_two(fifo_size); buf = (u8*)kzalloc(fifo_size, flags); if (!buf) { - DHD_ERROR(("%s: prio work fifo allocation failed \n", __FUNCTION__)); + DHD_ERROR(("%s: prio work fifo allocation failed\n", + __FUNCTION__)); goto return_null; } @@ -146,10 +150,11 @@ /* allocate buffer to hold work events */ fifo_size = DHD_WORK_FIFO_SIZE; - fifo_size = is_power_of_2(fifo_size)? fifo_size : roundup_pow_of_two(fifo_size); + fifo_size = is_power_of_2(fifo_size) ? fifo_size : + roundup_pow_of_two(fifo_size); buf = (u8*)kzalloc(fifo_size, flags); if (!buf) { - DHD_ERROR(("%s: work fifo allocation failed \n", __FUNCTION__)); + DHD_ERROR(("%s: work fifo allocation failed\n", __FUNCTION__)); goto return_null; } @@ -161,13 +166,14 @@ } work->dhd_info = dhd_info; - DHD_ERROR(("%s: work queue initialized \n", __FUNCTION__)); + work->event_skip_mask = 0; + DHD_ERROR(("%s: work queue initialized\n", __FUNCTION__)); return work; return_null: - - if (work) + if (work) { dhd_deferred_work_deinit(work); + } return NULL; } @@ -177,9 +183,9 @@ { struct dhd_deferred_wq *deferred_work = work; - if (!deferred_work) { - DHD_ERROR(("%s: deferred work has been freed alread \n", __FUNCTION__)); + DHD_ERROR(("%s: deferred work has been freed already\n", + __FUNCTION__)); return; } @@ -190,13 +196,29 @@ * free work event fifo. * kfifo_free frees locally allocated fifo buffer */ - if (deferred_work->prio_fifo) + if (deferred_work->prio_fifo) { dhd_kfifo_free(deferred_work->prio_fifo); + } - if (deferred_work->work_fifo) + if (deferred_work->work_fifo) { dhd_kfifo_free(deferred_work->work_fifo); + } kfree(deferred_work); +} + +/* select kfifo according to priority */ +static inline struct kfifo * +dhd_deferred_work_select_kfifo(struct dhd_deferred_wq *deferred_wq, + u8 priority) +{ + if (priority == DHD_WQ_WORK_PRIORITY_HIGH) { + return deferred_wq->prio_fifo; + } else if (priority == DHD_WQ_WORK_PRIORITY_LOW) { + return deferred_wq->work_fifo; + } else { + return NULL; + } } /* @@ -207,19 +229,33 @@ dhd_deferred_schedule_work(void *workq, void *event_data, u8 event, event_handler_t event_handler, u8 priority) { - struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *) workq; - struct dhd_deferred_event_t deferred_event; - int status; + struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)workq; + struct kfifo *fifo; + dhd_deferred_event_t deferred_event; + int bytes_copied = 0; if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); ASSERT(0); return DHD_WQ_STS_UNINITIALIZED; } if (!event || (event >= DHD_MAX_WQ_EVENTS)) { - DHD_ERROR(("%s: Unknown event \n", __FUNCTION__)); + DHD_ERROR(("%s: unknown event, event=%d\n", __FUNCTION__, + event)); return DHD_WQ_STS_UNKNOWN_EVENT; + } + + if (!priority || (priority >= DHD_WQ_MAX_PRIORITY)) { + DHD_ERROR(("%s: unknown priority, priority=%d\n", + __FUNCTION__, priority)); + return DHD_WQ_STS_UNKNOWN_PRIORITY; + } + + if ((deferred_wq->event_skip_mask & (1 << event))) { + DHD_ERROR(("%s: Skip event requested. Mask = 0x%x\n", + __FUNCTION__, deferred_wq->event_skip_mask)); + return DHD_WQ_STS_EVENT_SKIPPED; } /* @@ -235,28 +271,29 @@ deferred_event.event_data = event_data; deferred_event.event_handler = event_handler; - if (priority == DHD_WORK_PRIORITY_HIGH) { - status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - } else { - status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event, + fifo = dhd_deferred_work_select_kfifo(deferred_wq, priority); + if (DHD_FIFO_HAS_FREE_SPACE(fifo)) { + bytes_copied = kfifo_in_spinlocked(fifo, &deferred_event, DEFRD_EVT_SIZE, &deferred_wq->work_lock); } - - if (!status) { + if (bytes_copied != DEFRD_EVT_SIZE) { + DHD_ERROR(("%s: failed to schedule deferred work, " + "priority=%d, bytes_copied=%d\n", __FUNCTION__, + priority, bytes_copied)); return DHD_WQ_STS_SCHED_FAILED; } schedule_work((struct work_struct *)deferred_wq); return DHD_WQ_STS_OK; } -static int -dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, struct dhd_deferred_event_t *event) +static bool +dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, + dhd_deferred_event_t *event) { - int status = 0; + int bytes_copied = 0; if (!deferred_wq) { - DHD_ERROR(("%s: work queue not initialized \n", __FUNCTION__)); + DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); return DHD_WQ_STS_UNINITIALIZED; } @@ -269,17 +306,36 @@ ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1); ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1); - /* first read priorit event fifo */ - status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); - - if (!status) { - /* priority fifo is empty. Now read low prio work fifo */ - status = kfifo_out_spinlocked(deferred_wq->work_fifo, event, - DEFRD_EVT_SIZE, &deferred_wq->work_lock); + /* handle priority work */ + if (DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->prio_fifo)) { + bytes_copied = kfifo_out_spinlocked(deferred_wq->prio_fifo, + event, DEFRD_EVT_SIZE, &deferred_wq->work_lock); } - return status; + /* handle normal work if priority work doesn't have enough data */ + if ((bytes_copied != DEFRD_EVT_SIZE) && + DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->work_fifo)) { + bytes_copied = kfifo_out_spinlocked(deferred_wq->work_fifo, + event, DEFRD_EVT_SIZE, &deferred_wq->work_lock); + } + + return (bytes_copied == DEFRD_EVT_SIZE); +} + +static inline void +dhd_deferred_dump_work_event(dhd_deferred_event_t *work_event) +{ + if (!work_event) { + DHD_ERROR(("%s: work_event is null\n", __FUNCTION__)); + return; + } + + DHD_ERROR(("%s: work_event->event = %d\n", __FUNCTION__, + work_event->event)); + DHD_ERROR(("%s: work_event->event_data = %p\n", __FUNCTION__, + work_event->event_data)); + DHD_ERROR(("%s: work_event->event_handler = %p\n", __FUNCTION__, + work_event->event_handler)); } /* @@ -288,9 +344,8 @@ static void dhd_deferred_work_handler(struct work_struct *work) { - struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; - struct dhd_deferred_event_t work_event; - int status; + struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work; + dhd_deferred_event_t work_event; if (!deferred_work) { DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__)); @@ -298,24 +353,47 @@ } do { - status = dhd_get_scheduled_work(deferred_work, &work_event); - DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status)); - if (!status) { - DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status)); + if (!dhd_get_scheduled_work(deferred_work, &work_event)) { + DHD_TRACE(("%s: no event to handle\n", __FUNCTION__)); break; } - if (work_event.event > DHD_MAX_WQ_EVENTS) { - DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event)); - break; + if (work_event.event >= DHD_MAX_WQ_EVENTS) { + DHD_ERROR(("%s: unknown event\n", __FUNCTION__)); + dhd_deferred_dump_work_event(&work_event); + ASSERT(work_event.event < DHD_MAX_WQ_EVENTS); + continue; } if (work_event.event_handler) { work_event.event_handler(deferred_work->dhd_info, work_event.event_data, work_event.event); } else { - DHD_ERROR(("%s: event not defined %d\n", __FUNCTION__, work_event.event)); + DHD_ERROR(("%s: event handler is null\n", + __FUNCTION__)); + dhd_deferred_dump_work_event(&work_event); + ASSERT(work_event.event_handler != NULL); } } while (1); + return; } + +void +dhd_deferred_work_set_skip(void *work, u8 event, bool set) +{ + struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)work; + + if (!deferred_wq || !event || (event >= DHD_MAX_WQ_EVENTS)) { + DHD_ERROR(("%s: Invalid!!\n", __FUNCTION__)); + return; + } + + if (set) { + /* Set */ + deferred_wq->event_skip_mask |= (1 << event); + } else { + /* Clear */ + deferred_wq->event_skip_mask &= ~(1 << event); + } +} -- Gitblit v1.6.2