• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Broadcom Dongle Host Driver (DHD)
3  *
4  * Copyright (C) 1999-2018, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions
16  * of the license of that module.  An independent module is a module which is
17  * not derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: dhd_csi.c 606280 2015-12-15 05:28:25Z $
25  */
26 #include <osl.h>
27 
28 #include <bcmutils.h>
29 
30 #include <bcmendian.h>
31 #include <linuxver.h>
32 #include <linux/list.h>
33 #include <linux/sort.h>
34 #include <dngl_stats.h>
35 #include <wlioctl.h>
36 
37 #include <bcmevent.h>
38 #include <dhd.h>
39 #include <dhd_dbg.h>
40 #include <dhd_csi.h>
41 
42 #define NULL_CHECK(p, s, err)                                                  \
43     do {                                                                       \
44         if (!(p)) {                                                            \
45             printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s));             \
46             err = BCME_ERROR;                                                  \
47             return err;                                                        \
48         }                                                                      \
49     } while (0)
50 
51 #define TIMESPEC_TO_US(ts)                                                     \
52     (((uint64)(ts).tv_sec * USEC_PER_SEC) + (ts).tv_nsec / NSEC_PER_USEC)
53 
54 #define NULL_ADDR "\x00\x00\x00\x00\x00\x00"
55 
dhd_csi_event_handler(dhd_pub_t * dhd,wl_event_msg_t * event,void * event_data)56 int dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event,
57                           void *event_data)
58 {
59     int ret = BCME_OK;
60     bool is_new = TRUE;
61     cfr_dump_data_t *p_event;
62     cfr_dump_list_t *ptr, *next, *new;
63 
64     NULL_CHECK(dhd, "dhd is NULL", ret);
65 
66     DHD_TRACE(("Enter %s\n", __FUNCTION__));
67 
68     if (!event_data) {
69         DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
70         return -EINVAL;
71     }
72     p_event = (cfr_dump_data_t *)event_data;
73 
74     /* check if this addr exist */
75     if (!list_empty(&dhd->csi_list)) {
76         list_for_each_entry_safe(ptr, next, &dhd->csi_list, list)
77         {
78             if (bcmp(&ptr->entry.header.peer_macaddr,
79                      &p_event->header.peer_macaddr, ETHER_ADDR_LEN) == 0) {
80                 int pos = 0, dump_len = 0, remain = 0;
81                 is_new = FALSE;
82                 DHD_INFO(("CSI data exist\n"));
83                 if (p_event->header.status == 0) {
84                     bcopy(&p_event->header, &ptr->entry.header,
85                           sizeof(cfr_dump_header_t));
86                     dump_len = p_event->header.cfr_dump_length;
87                     if (dump_len < MAX_EVENT_SIZE) {
88                         bcopy(&p_event->data, &ptr->entry.data, dump_len);
89                     } else {
90                         /* for big csi data */
91                         uint8 *p = (uint8 *)&ptr->entry.data;
92                         remain = p_event->header.remain_length;
93                         if (remain) {
94                             pos = dump_len - remain - MAX_EVENT_SIZE;
95                             p += pos;
96                             bcopy(&p_event->data, p, MAX_EVENT_SIZE);
97                         } else {
98                             /* copy rest of csi data */
99                             pos = dump_len - (dump_len % MAX_EVENT_SIZE);
100                             p += pos;
101                             bcopy(&p_event->data, p,
102                                   (dump_len % MAX_EVENT_SIZE));
103                         }
104                     }
105                     return BCME_OK;
106                 }
107             }
108         }
109     }
110     if (is_new) {
111         if (dhd->csi_count < MAX_CSI_NUM) {
112             new = (cfr_dump_list_t *)MALLOCZ(dhd->osh, sizeof(cfr_dump_list_t));
113             if (!new) {
114                 DHD_ERROR(("Malloc cfr dump list error\n"));
115                 return BCME_NOMEM;
116             }
117             bcopy(&p_event->header, &new->entry.header,
118                   sizeof(cfr_dump_header_t));
119             DHD_INFO(
120                 ("New entry data size %d\n", p_event->header.cfr_dump_length));
121             /* for big csi data */
122             if (p_event->header.remain_length) {
123                 DHD_TRACE(("remain %d\n", p_event->header.remain_length));
124                 bcopy(&p_event->data, &new->entry.data, MAX_EVENT_SIZE);
125             } else {
126                 bcopy(&p_event->data, &new->entry.data,
127                       p_event->header.cfr_dump_length);
128             }
129             INIT_LIST_HEAD(&(new->list));
130             list_add_tail(&(new->list), &dhd->csi_list);
131             dhd->csi_count++;
132         } else {
133             DHD_TRACE(("Over maximum CSI Number 8. SKIP it.\n"));
134         }
135     }
136     return ret;
137 }
138 
dhd_csi_init(dhd_pub_t * dhd)139 int dhd_csi_init(dhd_pub_t *dhd)
140 {
141     int err = BCME_OK;
142 
143     NULL_CHECK(dhd, "dhd is NULL", err);
144     INIT_LIST_HEAD(&dhd->csi_list);
145     dhd->csi_count = 0;
146 
147     return err;
148 }
149 
dhd_csi_deinit(dhd_pub_t * dhd)150 int dhd_csi_deinit(dhd_pub_t *dhd)
151 {
152     int err = BCME_OK;
153     cfr_dump_list_t *ptr, *next;
154 
155     NULL_CHECK(dhd, "dhd is NULL", err);
156 
157     if (!list_empty(&dhd->csi_list)) {
158         list_for_each_entry_safe(ptr, next, &dhd->csi_list, list)
159         {
160             list_del(&ptr->list);
161             MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t));
162         }
163     }
164     return err;
165 }
166 
dhd_csi_clean_list(dhd_pub_t * dhd)167 void dhd_csi_clean_list(dhd_pub_t *dhd)
168 {
169     cfr_dump_list_t *ptr, *next;
170     int num = 0;
171 
172     if (!dhd) {
173         DHD_ERROR(("NULL POINTER: %s\n", __FUNCTION__));
174         return;
175     }
176 
177     if (!list_empty(&dhd->csi_list)) {
178         list_for_each_entry_safe(ptr, next, &dhd->csi_list, list)
179         {
180             if (ptr->entry.header.remain_length == 0) {
181                 list_del(&ptr->list);
182                 num++;
183                 MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t));
184             }
185         }
186     }
187     dhd->csi_count = 0;
188     DHD_TRACE(("Clean up %d record\n", num));
189 }
190 
dhd_csi_dump_list(dhd_pub_t * dhd,char * buf)191 int dhd_csi_dump_list(dhd_pub_t *dhd, char *buf)
192 {
193     int ret = BCME_OK;
194     cfr_dump_list_t *ptr, *next;
195     uint8 *pbuf = buf;
196     int num = 0;
197     int length = 0;
198 
199     NULL_CHECK(dhd, "dhd is NULL", ret);
200 
201     /* check if this addr exist */
202     if (!list_empty(&dhd->csi_list)) {
203         list_for_each_entry_safe(ptr, next, &dhd->csi_list, list)
204         {
205             if (ptr->entry.header.remain_length) {
206                 DHD_ERROR(
207                     ("data not ready %d\n", ptr->entry.header.remain_length));
208                 continue;
209             }
210             bcopy(&ptr->entry.header, pbuf, sizeof(cfr_dump_header_t));
211             length += sizeof(cfr_dump_header_t);
212             pbuf += sizeof(cfr_dump_header_t);
213             DHD_TRACE(
214                 ("Copy data size %d\n", ptr->entry.header.cfr_dump_length));
215             bcopy(&ptr->entry.data, pbuf, ptr->entry.header.cfr_dump_length);
216             length += ptr->entry.header.cfr_dump_length;
217             pbuf += ptr->entry.header.cfr_dump_length;
218             num++;
219         }
220     }
221     DHD_TRACE(("dump %d record %d bytes\n", num, length));
222 
223     return length;
224 }
225