Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 1 | /* |
Komal Seelam | c12e675 | 2016-02-02 18:17:13 +0530 | [diff] [blame] | 2 | * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 3 | * |
| 4 | * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| 5 | * |
| 6 | * |
| 7 | * Permission to use, copy, modify, and/or distribute this software for |
| 8 | * any purpose with or without fee is hereby granted, provided that the |
| 9 | * above copyright notice and this permission notice appear in all |
| 10 | * copies. |
| 11 | * |
| 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| 13 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| 14 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| 15 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| 16 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| 17 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 18 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 19 | * PERFORMANCE OF THIS SOFTWARE. |
| 20 | */ |
| 21 | |
| 22 | /* |
| 23 | * This file was originally distributed by Qualcomm Atheros, Inc. |
| 24 | * under proprietary terms before Copyright ownership was assigned |
| 25 | * to the Linux Foundation. |
| 26 | */ |
| 27 | |
| 28 | /** |
| 29 | * DOC: wlan_hdd_napi.c |
| 30 | * |
| 31 | * WLAN HDD NAPI interface implementation |
| 32 | */ |
| 33 | #include <smp.h> /* get_cpu */ |
| 34 | |
| 35 | #include "wlan_hdd_napi.h" |
| 36 | #include "cds_api.h" /* cds_get_context */ |
| 37 | #include "hif.h" /* hif_map_service...*/ |
| 38 | #include "wlan_hdd_main.h" /* hdd_err/warn... */ |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 39 | #include "qdf_types.h" /* QDF_MODULE_ID_... */ |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 40 | #include "ce_api.h" |
| 41 | |
| 42 | /* guaranteed to be initialized to zero/NULL by the standard */ |
| 43 | static struct qca_napi_data *hdd_napi_ctx; |
| 44 | |
| 45 | /** |
| 46 | * hdd_napi_get_all() - return the whole NAPI structure from HIF |
| 47 | * |
| 48 | * Gets to the data structure common to all NAPI instances. |
| 49 | * |
| 50 | * Return: |
| 51 | * NULL : probably NAPI not initialized yet. |
| 52 | * <addr>: the address of the whole NAPI structure |
| 53 | */ |
| 54 | struct qca_napi_data *hdd_napi_get_all(void) |
| 55 | { |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 56 | struct qca_napi_data *rp = NULL; |
Komal Seelam | 3d20286 | 2016-02-24 18:43:24 +0530 | [diff] [blame] | 57 | struct hif_opaque_softc *hif; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 58 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 59 | NAPI_DEBUG("-->"); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 60 | |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 61 | hif = cds_get_context(QDF_MODULE_ID_HIF); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 62 | if (unlikely(NULL == hif)) |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 63 | QDF_ASSERT(NULL != hif); /* WARN */ |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 64 | else |
| 65 | rp = hif_napi_get_all(hif); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 66 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 67 | NAPI_DEBUG("<-- [addr=%p]", rp); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 68 | return rp; |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * hdd_napi_get_map() - get a copy of napi pipe map |
| 73 | * |
| 74 | * Return: |
| 75 | * uint32_t : copy of pipe map |
| 76 | */ |
| 77 | static uint32_t hdd_napi_get_map(void) |
| 78 | { |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 79 | uint32_t map = 0; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 80 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 81 | NAPI_DEBUG("-->"); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 82 | /* cache once, use forever */ |
| 83 | if (hdd_napi_ctx == NULL) |
| 84 | hdd_napi_ctx = hdd_napi_get_all(); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 85 | if (hdd_napi_ctx != NULL) |
| 86 | map = hdd_napi_ctx->ce_map; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 87 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 88 | NAPI_DEBUG("<-- [map=0x%08x]", map); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 89 | return map; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * hdd_napi_create() - creates the NAPI structures for a given netdev |
| 94 | * |
| 95 | * Creates NAPI instances. This function is called |
| 96 | * unconditionally during initialization. It creates |
| 97 | * napi structures through the proper HTC/HIF calls. |
| 98 | * The structures are disabled on creation. |
| 99 | * |
| 100 | * Return: |
| 101 | * single-queue: <0: err, >0=id, 0 (should not happen) |
| 102 | * multi-queue: bitmap of created instances (0: none) |
| 103 | */ |
| 104 | int hdd_napi_create(void) |
| 105 | { |
Houston Hoffman | c1f962e | 2016-04-13 16:35:44 -0700 | [diff] [blame] | 106 | struct hif_opaque_softc *hif_ctx; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 107 | int rc = 0; |
| 108 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 109 | NAPI_DEBUG("-->"); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 110 | |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 111 | hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 112 | if (unlikely(NULL == hif_ctx)) { |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 113 | QDF_ASSERT(NULL != hif_ctx); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 114 | rc = -EFAULT; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 115 | } else { |
Houston Hoffman | c1f962e | 2016-04-13 16:35:44 -0700 | [diff] [blame] | 116 | rc = hif_napi_create(hif_ctx, hdd_napi_poll, |
| 117 | QCA_NAPI_BUDGET, |
| 118 | QCA_NAPI_DEF_SCALE); |
| 119 | if (rc < 0) |
| 120 | hdd_err("ERR(%d) creating NAPI instances", |
| 121 | rc); |
| 122 | else |
| 123 | hdd_info("napi instances were created. Map=0x%x", rc); |
| 124 | |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 125 | } |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 126 | NAPI_DEBUG("<-- [rc=%d]", rc); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 127 | |
| 128 | return rc; |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * hdd_napi_destroy() - destroys the NAPI structures for a given netdev |
| 133 | * @force: if set, will force-disable the instance before _del'ing |
| 134 | * |
| 135 | * Destroy NAPI instances. This function is called |
| 136 | * unconditionally during module removal. It destroy |
| 137 | * napi structures through the proper HTC/HIF calls. |
| 138 | * |
| 139 | * Return: |
| 140 | * number of NAPI instances destroyed |
| 141 | */ |
| 142 | int hdd_napi_destroy(int force) |
| 143 | { |
| 144 | int rc = 0; |
| 145 | int i; |
| 146 | uint32_t hdd_napi_map = hdd_napi_get_map(); |
| 147 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 148 | NAPI_DEBUG("--> (force=%d)", force); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 149 | if (hdd_napi_map) { |
Komal Seelam | 3d20286 | 2016-02-24 18:43:24 +0530 | [diff] [blame] | 150 | struct hif_opaque_softc *hif_ctx; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 151 | |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 152 | hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 153 | if (unlikely(NULL == hif_ctx)) |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 154 | QDF_ASSERT(NULL != hif_ctx); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 155 | else |
| 156 | for (i = 0; i < CE_COUNT_MAX; i++) |
| 157 | if (hdd_napi_map & (0x01 << i)) { |
| 158 | if (0 <= hif_napi_destroy( |
| 159 | hif_ctx, |
| 160 | NAPI_PIPE2ID(i), force)) { |
| 161 | rc++; |
| 162 | hdd_napi_map &= ~(0x01 << i); |
| 163 | } else |
| 164 | hdd_err("cannot destroy napi %d: (pipe:%d), f=%d\n", |
| 165 | i, |
| 166 | NAPI_PIPE2ID(i), force); |
| 167 | } |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | /* if all instances are removed, it is likely that hif_context has been |
| 171 | * removed as well, so the cached value of the napi context also needs |
| 172 | * to be removed |
| 173 | */ |
| 174 | if (force) |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 175 | QDF_ASSERT(hdd_napi_map == 0); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 176 | if (0 == hdd_napi_map) |
| 177 | hdd_napi_ctx = NULL; |
| 178 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 179 | NAPI_DEBUG("<-- [rc=%d]", rc); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 180 | return rc; |
| 181 | } |
| 182 | |
| 183 | /** |
| 184 | * hdd_napi_enabled() - checks if NAPI is enabled (for a given id) |
| 185 | * @id: the id of the NAPI to check (any= -1) |
| 186 | * |
| 187 | * Return: |
| 188 | * int: 0 = false (NOT enabled) |
| 189 | * !0 = true (enabbled) |
| 190 | */ |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 191 | int hdd_napi_enabled(int id) |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 192 | { |
Komal Seelam | 3d20286 | 2016-02-24 18:43:24 +0530 | [diff] [blame] | 193 | struct hif_opaque_softc *hif; |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 194 | int rc = 0; /* NOT enabled */ |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 195 | |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 196 | hif = cds_get_context(QDF_MODULE_ID_HIF); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 197 | if (unlikely(NULL == hif)) |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 198 | QDF_ASSERT(hif != NULL); /* WARN_ON; rc = 0 */ |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 199 | else if (-1 == id) |
| 200 | rc = hif_napi_enabled(hif, id); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 201 | else |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 202 | rc = hif_napi_enabled(hif, NAPI_ID2PIPE(id)); |
| 203 | return rc; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 204 | } |
| 205 | |
| 206 | /** |
| 207 | * hdd_napi_event() - relay the event detected by HDD to HIF NAPI decision maker |
| 208 | * @event: event code |
| 209 | * @data : event-specific auxiliary data |
| 210 | * |
| 211 | * Return code does not indicate a change, but whether or not NAPI is |
| 212 | * enabled at the time of the return of the function. That is, if NAPI |
| 213 | * was disabled before the call, and the event does not cause NAPI to be |
| 214 | * enabled, a value of 0 will be returned indicating that it is (still) |
| 215 | * disabled. |
| 216 | * |
| 217 | * Return: |
| 218 | * < 0: error code |
| 219 | * = 0: NAPI state = disabled (after processing the event) |
| 220 | * = 1: NAPI state = enabled (after processing the event) |
| 221 | */ |
| 222 | int hdd_napi_event(enum qca_napi_event event, void *data) |
| 223 | { |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 224 | int rc = -EFAULT; /* assume err */ |
Komal Seelam | 3d20286 | 2016-02-24 18:43:24 +0530 | [diff] [blame] | 225 | struct hif_opaque_softc *hif; |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 226 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 227 | NAPI_DEBUG("-->(event=%d, aux=%p)", event, data); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 228 | |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 229 | hif = cds_get_context(QDF_MODULE_ID_HIF); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 230 | if (unlikely(NULL == hif)) |
Anurag Chouhan | b2dc16f | 2016-02-25 11:47:37 +0530 | [diff] [blame] | 231 | QDF_ASSERT(hif != NULL); |
Orhan K AKYILDIZ | c409461 | 2015-11-11 18:01:15 -0800 | [diff] [blame] | 232 | else |
| 233 | rc = hif_napi_event(hif, event, data); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 234 | |
Houston Hoffman | 43d47fa | 2016-02-24 16:34:30 -0800 | [diff] [blame] | 235 | NAPI_DEBUG("<--[rc=%d]", rc); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 236 | return rc; |
| 237 | } |
| 238 | |
| 239 | /** |
| 240 | * hdd_napi_poll() - NAPI poll function |
| 241 | * @napi : pointer to NAPI struct |
| 242 | * @budget: the pre-declared budget |
| 243 | * |
| 244 | * Implementation of poll function. This function is called |
| 245 | * by kernel during softirq processing. |
| 246 | * |
| 247 | * NOTE FOR THE MAINTAINER: |
| 248 | * Make sure this is very close to the ce_tasklet code. |
| 249 | * |
| 250 | * Return: |
| 251 | * int: the amount of work done ( <= budget ) |
| 252 | */ |
| 253 | int hdd_napi_poll(struct napi_struct *napi, int budget) |
| 254 | { |
Anurag Chouhan | 6d76066 | 2016-02-20 16:05:43 +0530 | [diff] [blame] | 255 | return hif_napi_poll(cds_get_context(QDF_MODULE_ID_HIF), napi, budget); |
Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame] | 256 | } |