2 * RPC layer. It links to bus layer with transport layer(bus dependent)
3 * Broadcom 802.11abg Networking Device Driver
5 * Copyright (C) 2012, Broadcom Corporation
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
9 * the contents of this file may not be disclosed to third parties, copied
10 * or duplicated in any form, in whole or in part, without the prior
11 * written permission of Broadcom Corporation.
13 * $Id: bcm_rpc.c 358609 2012-09-24 21:59:30Z $
19 #include <bcmendian.h>
23 #include <bcm_rpc_tp.h>
28 #if (!defined(WLC_HIGH) && !defined(WLC_LOW))
31 #if defined(WLC_HIGH) && defined(WLC_LOW)
35 /* RPC may use OS APIs directly to avoid overloading osl.h
36 * HIGH_ONLY supports NDIS and LINUX so far. can be ported to other OS if needed
39 #if !defined(NDIS) && !defined(linux)
40 #error "RPC only supports NDIS and LINUX in HIGH driver"
44 #error "RPC only supports HNDRTE in LOW driver"
47 /* use local flag BCMDBG_RPC so that it can be turned on without global BCMDBG */
54 /* #define BCMDBG_RPC */
56 static uint32 rpc_msg_level
= RPC_ERROR_VAL
;
57 /* Print error messages even for non-debug drivers
58 * NOTE: RPC_PKTLOG_VAL can be added in bcm_rpc_pktlog_init()
61 /* osl_msg_level is a bitvector with defs in wlioctl.h */
62 #define RPC_ERR(args) do {if (rpc_msg_level & RPC_ERROR_VAL) printf args;} while (0)
65 #define RPC_TRACE(args) do {if (rpc_msg_level & RPC_TRACE_VAL) printf args;} while (0)
66 #define RPC_PKTTRACE_ON() (rpc_msg_level & RPC_PKTTRACE_VAL)
69 #define RPC_TRACE(args) do {if (rpc_msg_level & RPC_TRACE_VAL) printf args;} while (0)
70 #define RPC_PKTTRACE_ON() (FALSE)
71 #define prhex(a, b, c) do { } while (0) /* prhex is not defined under */
72 #define RPC_PKTLOG_ON() (FALSE)
74 #define RPC_TRACE(args)
75 #define RPC_PKTTRACE_ON() (FALSE)
76 #define RPC_PKTLOG_ON() (FALSE)
77 #define prhex(a, b, c) do { } while (0) /* prhex is not defined under */
78 #endif /* BCMDBG_ERR */
79 #endif /* BCMDBG_RPC */
82 #define RPC_PKTLOG_ON() (rpc_msg_level & RPC_PKTLOG_VAL)
84 #define RPC_PKTLOG_ON() (FALSE)
85 #endif /* BCMDBG_RPC */
87 #ifndef BCM_RPC_REORDER_LIMIT
89 #define BCM_RPC_REORDER_LIMIT 40 /* limit to toss hole to avoid overflow reorder queque */
91 #define BCM_RPC_REORDER_LIMIT 30
93 #endif /* BCM_RPC_REORDER_LIMIT */
95 /* OS specific files for locks */
96 #define RPC_INIT_WAIT_TIMEOUT_MSEC 2000
97 #ifndef RPC_RETURN_WAIT_TIMEOUT_MSEC
98 #if defined(NDIS) && !defined(SDIO_BMAC)
99 #define RPC_RETURN_WAIT_TIMEOUT_MSEC 800 /* NDIS OIDs timeout in 1 second.
100 * This timeout needs to be smaller than that
103 #define RPC_RETURN_WAIT_TIMEOUT_MSEC 3200
105 #endif /* RPC_RETURN_WAIT_TIMEOUT_MSEC */
107 /* RPC Frame formats */
108 /* |--------------||-------------|
109 * RPC Header RPC Payload
112 * |-------|--------|----------------|
114 * Type Session Transaction ID
120 * Data and Return RPC payload is RPC all dependent
122 * Management frame formats:
123 * |--------|--------|--------|--------|
125 * Header Action Version Reason
127 * Version is included only for following actions:
134 * Reason sent only by BMAC for following actions:
139 typedef uint32 rpc_header_t
;
141 #define RPC_HDR_LEN sizeof(rpc_header_t)
142 #define RPC_ACN_LEN sizeof(uint32)
143 #define RPC_VER_LEN sizeof(EPI_VERSION_NUM)
144 #define RPC_RC_LEN sizeof(uint32)
145 #define RPC_CHIPID_LEN sizeof(uint32)
147 #define RPC_HDR_TYPE(_rpch) (((_rpch) >> 24) & 0xff)
148 #define RPC_HDR_SESSION(_rpch) (((_rpch) >> 16) & 0xff)
149 #define RPC_HDR_XACTION(_rpch) ((_rpch) & 0xffff) /* When the type is data or return */
151 #define NAME_ENTRY(x) #x
153 /* RPC Header defines -- attached to every RPC call */
155 RPC_TYPE_UNKNOWN
, /* Unknown header type */
156 RPC_TYPE_DATA
, /* RPC call that go straight through */
157 RPC_TYPE_RTN
, /* RPC calls that are syncrhonous */
158 RPC_TYPE_MGN
, /* RPC state management */
168 /* Management actions */
172 RPC_CONNECT
, /* Master (high) to slave (low). Slave to copy current
173 * session id and transaction id (mostly 0)
175 RPC_CONNECT_ACK
, /* Ack from LOW_RPC */
176 RPC_DOWN
, /* Down the other-end. The actual action is
179 RPC_CONNECT_NACK
, /* Nack from LOW_RPC. This indicates potentially that
180 * dongle could already be running
182 RPC_RESET
/* Resync using other end's session id (mostly HIGH->LOW)
183 * Also, reset the oe_trans, and trans to 0
199 #define HDR_STATE_MISMATCH 0x1
200 #define HDR_SESSION_MISMATCH 0x2
201 #define HDR_XACTION_MISMATCH 0x4
204 #define RPC_PKTLOG_DATASIZE 4
208 uint32 data
[RPC_PKTLOG_DATASIZE
]; /* First few bytes of the payload only */
210 #endif /* BCMDBG_RPC */
213 static void bcm_rpc_dump_state(uint32 arg
, uint argc
, char *argv
[]);
215 static void bcm_rpc_fatal_dump(void *arg
);
219 static void _bcm_rpc_dump_pktlog(rpc_info_t
*rpci
);
221 static void bcm_rpc_dump_pktlog_high(rpc_info_t
*rpci
);
223 static void bcm_rpc_dump_pktlog_low(uint32 arg
, uint argc
, char *argv
[]);
225 #endif /* BCMDBG_RPC */
228 /* This lock is needed to handle the Receive Re-order queue that guarantees
229 * in-order receive as it was observed that in NDIS at least, USB subsystem does
233 #define RPC_RO_LOCK(ri) NdisAcquireSpinLock(&(ri)->reorder_lock)
234 #define RPC_RO_UNLOCK(ri) NdisReleaseSpinLock(&(ri)->reorder_lock)
236 #define RPC_RO_LOCK(ri) spin_lock_irqsave(&(ri)->reorder_lock, (ri)->reorder_flags);
237 #define RPC_RO_UNLOCK(ri) spin_unlock_irqrestore(&(ri)->reorder_lock, (ri)->reorder_flags);
240 #define RPC_RO_LOCK(ri) do { } while (0)
241 #define RPC_RO_UNLOCK(ri) do { } while (0)
242 #endif /* WLC_HIGH */
245 void *pdev
; /* Per-port driver handle for rx callback */
246 struct rpc_transport_info
*rpc_th
; /* transport layer handle */
249 rpc_dispatch_cb_t dispatchcb
; /* callback when data is received */
250 void *ctx
; /* Callback context */
252 rpc_down_cb_t dncb
; /* callback when RPC goes down */
253 void *dnctx
; /* Callback context */
255 rpc_resync_cb_t resync_cb
; /* callback when host reenabled and dongle
256 * was not rebooted. Uses dnctx
258 rpc_txdone_cb_t txdone_cb
; /* when non-null, called when a tx has completed. */
259 uint8 rpc_tp_hdr_len
; /* header len for rpc and tp layer */
261 uint8 session
; /* 255 sessions enough ? */
262 uint16 trans
; /* More than 255 can't be pending */
263 uint16 oe_trans
; /* OtherEnd tran id, dongle->host */
264 uint16 rtn_trans
; /* BMAC: callreturn Id dongle->host */
265 uint16 oe_rtn_trans
; /* HIGH: received BMAC callreturn id */
267 rpc_buf_t
*rtn_rpcbuf
; /* RPC ID for return transaction */
270 uint reset
; /* # of resets */
271 uint cnt_xidooo
; /* transactionID out of order */
272 uint cnt_rx_drop_hole
; /* number of rcp calls dropped due to reorder overflow */
273 uint cnt_reorder_overflow
; /* number of time the reorder queue overflowed,
284 struct rpc_pktlog
*send_log
;
285 uint16 send_log_idx
; /* Point to the next slot to fill-in */
286 uint16 send_log_num
; /* Number of entries */
288 struct rpc_pktlog
*recv_log
;
289 uint16 recv_log_idx
; /* Point to the next slot to fill-in */
290 uint16 recv_log_num
; /* Number of entries */
291 #endif /* BCMDBG_RPC */
295 NDIS_SPIN_LOCK reorder_lock
; /* TO RAISE the IRQ */
296 bool reorder_lock_alloced
;
297 bool down_oe_pending
;
300 spinlock_t reorder_lock
;
303 #endif /* WLC_HIGH */
304 /* Protect against rx reordering */
305 rpc_buf_t
*reorder_pktq
;
307 uint reorder_depth_max
;
312 static void bcm_rpc_tx_complete(void *ctx
, rpc_buf_t
*buf
, int status
);
313 static void bcm_rpc_buf_recv(void *context
, rpc_buf_t
*);
314 static void bcm_rpc_process_reorder_queue(rpc_info_t
*rpci
);
315 static bool bcm_rpc_buf_recv_inorder(rpc_info_t
*rpci
, rpc_buf_t
*rpc_buf
, mbool hdr_invalid
);
318 static rpc_buf_t
*bcm_rpc_buf_recv_high(struct rpc_info
*rpci
, rpc_type_t type
, rpc_acn_t acn
,
320 static int bcm_rpc_resume_oe(struct rpc_info
*rpci
);
322 static int bcm_rpc_hello(rpc_info_t
*rpci
);
325 static rpc_buf_t
*bcm_rpc_buf_recv_low(struct rpc_info
*rpci
, rpc_header_t header
,
326 rpc_acn_t acn
, rpc_buf_t
*rpc_buf
);
327 #endif /* WLC_HIGH */
328 static int bcm_rpc_up(rpc_info_t
*rpci
);
329 static uint16
bcm_rpc_reorder_next_xid(struct rpc_info
*rpci
);
333 static void bcm_rpc_pktlog_init(rpc_info_t
*rpci
);
334 static void bcm_rpc_pktlog_deinit(rpc_info_t
*rpci
);
335 static struct rpc_pktlog
*bcm_rpc_prep_entry(struct rpc_info
* rpci
, rpc_buf_t
*b
,
336 struct rpc_pktlog
*cur
, bool tx
);
337 static void bcm_rpc_add_entry_tx(struct rpc_info
* rpci
, struct rpc_pktlog
*cur
);
338 static void bcm_rpc_add_entry_rx(struct rpc_info
* rpci
, struct rpc_pktlog
*cur
);
339 #endif /* BCMDBG_RPC */
342 /* Header and componet retrieval functions */
343 static INLINE rpc_header_t
344 bcm_rpc_header(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
346 rpc_header_t
*rpch
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
347 return ltoh32(*rpch
);
350 static INLINE rpc_acn_t
351 bcm_rpc_mgn_acn(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
353 rpc_header_t
*rpch
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
355 return (rpc_acn_t
)ltoh32(*rpch
);
359 bcm_rpc_mgn_ver(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
361 rpc_header_t
*rpch
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
363 return ltoh32(*rpch
);
366 static INLINE rpc_rc_t
367 bcm_rpc_mgn_reason(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
369 rpc_header_t
*rpch
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
370 return (rpc_rc_t
)ltoh32(*rpch
);
375 bcm_rpc_mgn_chipid(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
377 rpc_header_t
*rpch
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
379 return ltoh32(*rpch
);
381 #endif /* WLC_HIGH */
384 bcm_rpc_hdr_xaction_validate(struct rpc_info
*rpci
, rpc_header_t header
, uint32
*xaction
,
389 type
= RPC_HDR_TYPE(header
);
390 *xaction
= RPC_HDR_XACTION(header
);
392 /* High driver does not check the return transaction to be in order */
393 if (type
!= RPC_TYPE_MGN
&&
395 type
!= RPC_TYPE_RTN
&&
397 *xaction
!= rpci
->oe_trans
) {
400 RPC_ERR(("Transaction mismatch: expected:0x%x got:0x%x type: %d\n",
401 rpci
->oe_trans
, *xaction
, type
));
404 return HDR_XACTION_MISMATCH
;
411 bcm_rpc_hdr_session_validate(struct rpc_info
*rpci
, rpc_header_t header
)
414 if (RPC_HDR_TYPE(header
) == RPC_TYPE_MGN
)
418 if (rpci
->session
!= RPC_HDR_SESSION(header
))
419 return HDR_SESSION_MISMATCH
;
424 bcm_rpc_hdr_state_validate(struct rpc_info
*rpci
, rpc_header_t header
)
426 uint type
= RPC_HDR_TYPE(header
);
428 if ((type
== RPC_TYPE_UNKNOWN
) || (type
> RPC_TYPE_MGN
))
429 return HDR_STATE_MISMATCH
;
431 /* Everything allowed during this transition time */
432 if (rpci
->state
== ASLEEP
)
435 /* Only managment frames allowed before ESTABLISHED state */
436 if ((rpci
->state
!= ESTABLISHED
) && (type
!= RPC_TYPE_MGN
)) {
437 RPC_ERR(("bcm_rpc_header_validate: State mismatch: state:%d type:%d\n",
439 return HDR_STATE_MISMATCH
;
446 bcm_rpc_hdr_validate(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
, uint32
*xaction
,
449 /* First the state against the type */
451 rpc_header_t header
= bcm_rpc_header(rpci
, rpc_buf
);
453 mboolset(ret
, bcm_rpc_hdr_state_validate(rpci
, header
));
454 mboolset(ret
, bcm_rpc_hdr_xaction_validate(rpci
, header
, xaction
, verbose
));
455 mboolset(ret
, bcm_rpc_hdr_session_validate(rpci
, header
));
461 BCMATTACHFN(bcm_rpc_attach
)(void *pdev
, osl_t
*osh
, struct rpc_transport_info
*rpc_th
,
464 struct rpc_info
*rpci
;
467 UNUSED_PARAMETER(devid
);
468 #endif /* WLC_HIGH */
470 if ((rpci
= (struct rpc_info
*)MALLOC(osh
, sizeof(struct rpc_info
))) == NULL
)
473 bzero(rpci
, sizeof(struct rpc_info
));
477 rpci
->rpc_th
= rpc_th
;
478 rpci
->session
= 0x69;
480 /* initialize lock and queue */
481 rpci
->rpc_osh
= rpc_osl_attach(osh
);
483 if (rpci
->rpc_osh
== NULL
) {
484 RPC_ERR(("bcm_rpc_attach: osl attach failed\n"));
488 bcm_rpc_tp_register_cb(rpc_th
, bcm_rpc_tx_complete
, rpci
,
489 bcm_rpc_buf_recv
, rpci
, rpci
->rpc_osh
);
491 rpci
->version
= EPI_VERSION_NUM
;
493 rpci
->rpc_tp_hdr_len
= RPC_HDR_LEN
+ bcm_rpc_buf_tp_header_len(rpci
->rpc_th
);
495 #if defined(WLC_HIGH) && defined(NDIS)
499 if (bcm_rpc_up(rpci
)) {
500 RPC_ERR(("bcm_rpc_attach: rpc_up failed\n"));
505 *devid
= (uint16
)rpci
->chipid
;
510 bcm_rpc_detach(rpci
);
515 bcm_rpc_reorder_next_xid(struct rpc_info
*rpci
)
519 uint16 cur_xid
= rpci
->oe_trans
;
521 uint16 min_delta
= 0xffff;
524 ASSERT(rpci
->rpc_th
);
525 for (buf
= rpci
->reorder_pktq
;
527 buf
= bcm_rpc_buf_next_get(rpci
->rpc_th
, buf
)) {
528 header
= bcm_rpc_header(rpci
, buf
);
529 xid
= RPC_HDR_XACTION(header
);
530 delta
= xid
- cur_xid
;
532 if (delta
< min_delta
) {
542 BCMATTACHFN(bcm_rpc_detach
)(struct rpc_info
*rpci
)
549 if (rpci
->reorder_pktq
) {
551 ASSERT(rpci
->rpc_th
);
552 while ((node
= rpci
->reorder_pktq
)) {
553 rpci
->reorder_pktq
= bcm_rpc_buf_next_get(rpci
->rpc_th
,
555 bcm_rpc_buf_next_set(rpci
->rpc_th
, node
, NULL
);
556 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC)
557 PKTFREE(rpci
->osh
, node
, FALSE
);
559 bcm_rpc_tp_buf_free(rpci
->rpc_th
, node
);
560 #endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY || BCM_RPC_ROC */
562 ASSERT(rpci
->reorder_pktq
== NULL
);
563 rpci
->reorder_depth
= 0;
564 rpci
->reorder_depth_max
= 0;
569 if (rpci
->reorder_lock_alloced
)
570 NdisFreeSpinLock(&rpci
->reorder_lock
);
572 #endif /* WLC_HIGH */
574 /* rpc is going away, cut off registered cbs from rpc_tp layer */
575 bcm_rpc_tp_deregister_cb(rpci
->rpc_th
);
578 bcm_rpc_tp_txflowctlcb_deinit(rpci
->rpc_th
);
582 rpc_osl_detach(rpci
->rpc_osh
);
584 MFREE(rpci
->osh
, rpci
, sizeof(struct rpc_info
));
589 bcm_rpc_buf_alloc(struct rpc_info
*rpci
, int datalen
)
592 int len
= datalen
+ RPC_HDR_LEN
;
594 ASSERT(rpci
->rpc_th
);
595 rpc_buf
= bcm_rpc_tp_buf_alloc(rpci
->rpc_th
, len
);
600 /* Reserve space for RPC Header */
601 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_HDR_LEN
);
607 bcm_rpc_buf_header_len(struct rpc_info
*rpci
)
609 return rpci
->rpc_tp_hdr_len
;
613 bcm_rpc_buf_free(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
615 bcm_rpc_tp_buf_free(rpci
->rpc_th
, rpc_buf
);
619 bcm_rpc_rxcb_init(struct rpc_info
*rpci
, void *ctx
, rpc_dispatch_cb_t cb
,
620 void *dnctx
, rpc_down_cb_t dncb
, rpc_resync_cb_t resync_cb
, rpc_txdone_cb_t txdone_cb
)
622 rpci
->dispatchcb
= cb
;
626 rpci
->resync_cb
= resync_cb
;
627 rpci
->txdone_cb
= txdone_cb
;
631 bcm_rpc_rxcb_deinit(struct rpc_info
*rpci
)
636 rpci
->dispatchcb
= NULL
;
640 rpci
->resync_cb
= NULL
;
643 struct rpc_transport_info
*
644 bcm_rpc_tp_get(struct rpc_info
*rpci
)
649 /* get original os handle */
651 bcm_rpc_osh_get(struct rpc_info
*rpci
)
659 bcm_rpc_tp_tx_encap(struct rpc_info
*rpci
, rpc_buf_t
*rpc_buf
)
664 rpc_len
= pkttotlen(rpci
->osh
, rpc_buf
);
665 tp_lenp
= (uint32
*)bcm_rpc_buf_push(rpci
->rpc_th
, rpc_buf
, BCM_RPC_TP_ENCAP_LEN
);
666 *tp_lenp
= htol32(rpc_len
);
671 rpc_header_prep(struct rpc_info
*rpci
, rpc_header_t
*header
, uint type
, uint action
)
678 /* Mgmt action follows the header */
679 if (type
== RPC_TYPE_MGN
) {
680 *(header
+ 1) = htol32(action
);
682 if (action
== RPC_CONNECT
|| action
== RPC_RESET
|| action
== RPC_HELLO
)
683 *(header
+ 2) = htol32(rpci
->version
);
687 else if (type
== RPC_TYPE_RTN
)
688 v
|= (rpci
->rtn_trans
);
693 v
|= (rpci
->session
<< 16);
697 RPC_TRACE(("rpc_header_prep: type:0x%x action: %d trans:0x%x\n",
698 type
, action
, rpci
->trans
));
701 #if defined(WLC_HIGH) && defined(NDIS)
704 bcm_rpc_hello(struct rpc_info
*rpci
)
706 int ret
= -1, count
= 10;
708 rpc_header_t
*header
;
710 RPC_OSL_LOCK(rpci
->rpc_osh
);
711 rpci
->state
= WAIT_HELLO
;
712 rpci
->wait_init
= TRUE
;
713 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
715 while (ret
&& (count
-- > 0)) {
717 /* Allocate a frame, prep it, send and wait */
718 rpc_buf
= bcm_rpc_tp_buf_alloc(rpci
->rpc_th
, RPC_HDR_LEN
+ RPC_ACN_LEN
+ RPC_VER_LEN
724 header
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
726 rpc_header_prep(rpci
, header
, RPC_TYPE_MGN
, RPC_HELLO
);
728 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, rpc_buf
)) {
729 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
733 RPC_ERR(("%s: waiting to receive hello\n", __FUNCTION__
));
735 RPC_OSL_WAIT(rpci
->rpc_osh
, RPC_INIT_WAIT_TIMEOUT_MSEC
, NULL
);
737 RPC_TRACE(("%s: wait done, ret = %d\n", __FUNCTION__
, ret
));
739 /* See if we timed out or actually initialized */
740 RPC_OSL_LOCK(rpci
->rpc_osh
);
741 if (rpci
->state
== HELLO_RECEIVED
)
743 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
747 /* See if we timed out or actually initialized */
748 RPC_OSL_LOCK(rpci
->rpc_osh
);
749 rpci
->wait_init
= FALSE
;
750 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
755 #endif /* WLC_HIGH && NDIS */
759 bcm_rpc_up(struct rpc_info
*rpci
)
762 rpc_header_t
*header
;
765 /* Allocate a frame, prep it, send and wait */
766 rpc_buf
= bcm_rpc_tp_buf_alloc(rpci
->rpc_th
, RPC_HDR_LEN
+ RPC_ACN_LEN
+ RPC_VER_LEN
772 header
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
774 rpc_header_prep(rpci
, header
, RPC_TYPE_MGN
, RPC_CONNECT
);
776 RPC_OSL_LOCK(rpci
->rpc_osh
);
777 rpci
->state
= WAIT_INITIALIZING
;
778 rpci
->wait_init
= TRUE
;
781 if (!rpci
->reorder_lock_alloced
) {
782 NdisAllocateSpinLock(&rpci
->reorder_lock
);
783 rpci
->reorder_lock_alloced
= TRUE
;
786 spin_lock_init(&rpci
->reorder_lock
);
789 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
791 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, rpc_buf
)) {
792 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
796 /* Wait for state to change to established. The receive thread knows what to do */
797 RPC_ERR(("%s: waiting to be connected\n", __FUNCTION__
));
799 ret
= RPC_OSL_WAIT(rpci
->rpc_osh
, RPC_INIT_WAIT_TIMEOUT_MSEC
, NULL
);
801 RPC_TRACE(("%s: wait done, ret = %d\n", __FUNCTION__
, ret
));
804 rpci
->wait_init
= FALSE
;
808 /* See if we timed out or actually initialized */
809 RPC_OSL_LOCK(rpci
->rpc_osh
);
810 if (rpci
->state
== ESTABLISHED
)
814 rpci
->wait_init
= FALSE
;
815 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
818 bcm_rpc_pktlog_init(rpci
);
825 bcm_rpc_is_asleep(struct rpc_info
*rpci
)
827 return (rpci
->state
== ASLEEP
);
831 bcm_rpc_sleep(struct rpc_info
*rpci
)
833 if (!rpci
->suspend_enable
)
835 bcm_rpc_tp_sleep(rpci
->rpc_th
);
836 rpci
->state
= ASLEEP
;
837 /* Ignore anything coming after this */
848 bcm_rpc_shutdown(struct rpc_info
*rpci
)
853 ret
= bcm_rpc_tp_shutdown(rpci
->rpc_th
);
854 rpci
->state
= DISCONNECTED
;
861 bcm_rpc_resume(struct rpc_info
*rpci
, int *fw_reload
)
863 if (!rpci
->suspend_enable
)
866 bcm_rpc_tp_resume(rpci
->rpc_th
, fw_reload
);
875 rpci
->state
= ESTABLISHED
;
877 if (bcm_rpc_resume_oe(rpci
) == 0) {
882 RPC_TRACE(("bcm_rpc_resume done, state %d\n", rpci
->state
));
883 return (rpci
->state
== ESTABLISHED
);
887 bcm_rpc_resume_oe(struct rpc_info
*rpci
)
890 rpc_header_t
*header
;
893 /* Allocate a frame, prep it, send and wait */
894 rpc_buf
= bcm_rpc_tp_buf_alloc(rpci
->rpc_th
, RPC_HDR_LEN
+ RPC_ACN_LEN
+ RPC_VER_LEN
);
899 header
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
901 rpc_header_prep(rpci
, header
, RPC_TYPE_MGN
, RPC_RESET
);
903 RPC_OSL_LOCK(rpci
->rpc_osh
);
904 rpci
->state
= WAIT_RESUME
;
905 rpci
->wait_init
= TRUE
;
906 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
908 /* Don't care for the return value */
909 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, rpc_buf
)) {
910 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
914 /* Wait for state to change to established. The receive thread knows what to do */
915 RPC_ERR(("%s: waiting to be resumed\n", __FUNCTION__
));
917 ret
= RPC_OSL_WAIT(rpci
->rpc_osh
, RPC_INIT_WAIT_TIMEOUT_MSEC
, NULL
);
919 RPC_TRACE(("%s: wait done, ret = %d\n", __FUNCTION__
, ret
));
922 rpci
->wait_init
= FALSE
;
926 /* See if we timed out or actually initialized */
927 RPC_OSL_LOCK(rpci
->rpc_osh
);
928 if (rpci
->state
== ESTABLISHED
)
932 rpci
->wait_init
= FALSE
;
933 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
939 bcm_rpc_up(struct rpc_info
*rpci
)
941 rpci
->state
= WAIT_INITIALIZING
;
944 bcm_rpc_pktlog_init(rpci
);
945 hndrte_cons_addcmd("rpcpktdump", bcm_rpc_dump_pktlog_low
, (uint32
)rpci
);
947 hndrte_cons_addcmd("rpcdump", bcm_rpc_dump_state
, (uint32
)rpci
);
952 bcm_rpc_connect_resp(struct rpc_info
*rpci
, rpc_acn_t acn
, uint32 reason
)
955 rpc_header_t
*header
;
957 /* Allocate a frame, prep it, send and wait */
958 rpc_buf
= bcm_rpc_tp_buf_alloc(rpci
->rpc_th
, RPC_HDR_LEN
+ RPC_ACN_LEN
+
959 RPC_RC_LEN
+ RPC_VER_LEN
+ RPC_CHIPID_LEN
);
961 RPC_ERR(("%s: bcm_rpc_tp_buf_alloc() failed\n", __FUNCTION__
));
965 header
= (rpc_header_t
*)bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
);
967 rpc_header_prep(rpci
, header
, RPC_TYPE_MGN
, acn
);
969 *(header
+ 2) = ltoh32(rpci
->version
);
970 *(header
+ 3) = ltoh32(reason
);
972 *(header
+ 4) = ltoh32(BCMCHIPID
);
973 #endif /* BCMCHIPID */
974 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, rpc_buf
)) {
975 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
981 #endif /* WLC_HIGH */
984 bcm_rpc_watchdog(struct rpc_info
*rpci
)
986 static uint32 uptime
= 0;
989 /* rpc watchdog is called every 5 msec in the low driver */
990 static uint32 count
= 0;
992 if (count
% 200 == 0) {
995 if (uptime
% 60 == 0)
996 RPC_ERR(("rpc uptime %d minutes\n", (uptime
/ 60)));
1000 if (uptime
% 60 == 0) {
1001 RPC_ERR(("rpc uptime %d minutes\n", (uptime
/ 60)));
1004 bcm_rpc_tp_watchdog(rpci
->rpc_th
);
1008 bcm_rpc_down(struct rpc_info
*rpci
)
1010 RPC_ERR(("%s\n", __FUNCTION__
));
1013 bcm_rpc_pktlog_deinit(rpci
);
1016 RPC_OSL_LOCK(rpci
->rpc_osh
);
1017 if (rpci
->state
!= DISCONNECTED
&& rpci
->state
!= ASLEEP
) {
1018 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1020 bcm_rpc_fatal_dump(rpci
);
1022 bcm_rpc_dump_state((uint32
)rpci
, 0, NULL
);
1024 RPC_OSL_LOCK(rpci
->rpc_osh
);
1025 rpci
->state
= DISCONNECTED
;
1026 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1028 (rpci
->dncb
)(rpci
->dnctx
);
1029 bcm_rpc_tp_down(rpci
->rpc_th
);
1032 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1035 #if defined(USBAP) && (defined(WLC_HIGH) && !defined(WLC_LOW))
1036 /* For USBAP external image, reboot system upon RPC error instead of just turning RPC down */
1037 #include <siutils.h>
1039 bcm_rpc_err_down(struct rpc_info
*rpci
)
1041 si_t
*sih
= si_kattach(SI_OSH
);
1043 RPC_ERR(("%s: rebooting system due to RPC error.\n", __FUNCTION__
));
1044 si_watchdog(sih
, 1);
1047 #define bcm_rpc_err_down bcm_rpc_down
1051 bcm_rpc_tx_complete(void *ctx
, rpc_buf_t
*buf
, int status
)
1053 struct rpc_info
*rpci
= (struct rpc_info
*)ctx
;
1055 RPC_TRACE(("%s: status 0x%x\n", __FUNCTION__
, status
));
1057 ASSERT(rpci
&& rpci
->rpc_th
);
1060 if (rpci
->txdone_cb
) {
1061 /* !!must pull off the rpc/tp header after dbus is done for wl driver */
1062 rpci
->txdone_cb(rpci
->ctx
, buf
);
1064 bcm_rpc_tp_buf_free(rpci
->rpc_th
, buf
);
1069 bcm_rpc_call(struct rpc_info
*rpci
, rpc_buf_t
*b
)
1071 rpc_header_t
*header
;
1074 struct rpc_pktlog cur
;
1077 RPC_TRACE(("%s:\n", __FUNCTION__
));
1079 RPC_OSL_LOCK(rpci
->rpc_osh
);
1080 if (rpci
->state
!= ESTABLISHED
) {
1082 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1085 header
= (rpc_header_t
*)bcm_rpc_buf_push(rpci
->rpc_th
, b
, RPC_HDR_LEN
);
1086 rpc_header_prep(rpci
, header
, RPC_TYPE_DATA
, 0);
1087 bcm_rpc_tp_tx_encap(rpci
, b
);
1088 if (rpci
->txdone_cb
) {
1089 /* !!must pull off the rpc/tp header after dbus is done for wl driver */
1090 rpci
->txdone_cb(rpci
->ctx
, b
);
1094 bcm_rpc_buf_free(rpci
, b
);
1098 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1101 /* Prepare the current log entry but add only if the TX was successful */
1102 /* This is done here before DATA pointer gets modified */
1103 if (RPC_PKTLOG_ON())
1104 bcm_rpc_prep_entry(rpci
, b
, &cur
, TRUE
);
1107 header
= (rpc_header_t
*)bcm_rpc_buf_push(rpci
->rpc_th
, b
, RPC_HDR_LEN
);
1109 rpc_header_prep(rpci
, header
, RPC_TYPE_DATA
, 0);
1112 if (RPC_PKTTRACE_ON()) {
1114 prhex("RPC Call ", bcm_rpc_buf_data(rpci
->rpc_th
, b
),
1115 bcm_rpc_buf_len_get(rpci
->rpc_th
, b
));
1118 #endif /* BCMDBG_RPC */
1120 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, b
)) {
1121 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
1123 if (rpci
->txdone_cb
) {
1124 rpci
->txdone_cb(rpci
->ctx
, b
);
1126 bcm_rpc_tp_buf_free(rpci
->rpc_th
, b
);
1128 bcm_rpc_err_down(rpci
);
1132 RPC_OSL_LOCK(rpci
->rpc_osh
);
1134 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1136 #ifdef BCMDBG_RPC /* Since successful add the entry */
1137 if (RPC_PKTLOG_ON()) {
1138 bcm_rpc_add_entry_tx(rpci
, &cur
);
1147 bcm_rpc_call_with_return(struct rpc_info
*rpci
, rpc_buf_t
*b
)
1149 rpc_header_t
*header
;
1150 rpc_buf_t
*retb
= NULL
;
1153 struct rpc_pktlog cur
;
1155 bool timedout
= FALSE
;
1156 uint32 start_wait_time
;
1158 RPC_TRACE(("%s:\n", __FUNCTION__
));
1160 RPC_OSL_LOCK(rpci
->rpc_osh
);
1161 if (rpci
->state
!= ESTABLISHED
) {
1162 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1163 RPC_ERR(("%s: RPC call before ESTABLISHED state\n", __FUNCTION__
));
1164 bcm_rpc_buf_free(rpci
, b
);
1167 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1170 /* Prepare the current log entry but add only if the TX was successful */
1171 /* This is done here before DATA pointer gets modified */
1172 if (RPC_PKTLOG_ON())
1173 bcm_rpc_prep_entry(rpci
, b
, &cur
, TRUE
);
1176 header
= (rpc_header_t
*)bcm_rpc_buf_push(rpci
->rpc_th
, b
, RPC_HDR_LEN
);
1178 rpc_header_prep(rpci
, header
, RPC_TYPE_RTN
, 0);
1180 RPC_OSL_LOCK(rpci
->rpc_osh
);
1182 ASSERT(rpci
->rtn_rpcbuf
== NULL
);
1183 rpci
->wait_return
= TRUE
;
1184 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1186 /* Prep the return packet BEFORE sending the buffer and also within spinlock
1189 if ((ret
= bcm_rpc_tp_recv_rtn(rpci
->rpc_th
)) != BCME_OK
) {
1190 RPC_ERR(("%s: bcm_rpc_tp_recv_rtn() failed\n", __FUNCTION__
));
1192 RPC_OSL_LOCK(rpci
->rpc_osh
);
1193 rpci
->wait_return
= FALSE
;
1194 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1195 if ((ret
!= BCME_NORESOURCE
) && (ret
!= BCME_BUSY
))
1196 bcm_rpc_err_down(rpci
);
1202 if (RPC_PKTTRACE_ON()) {
1204 prhex("RPC Call With Return Buf", bcm_rpc_buf_data(rpci
->rpc_th
, b
),
1205 bcm_rpc_buf_len_get(rpci
->rpc_th
, b
));
1208 #endif /* BCMDBG_RPC */
1210 if (bcm_rpc_tp_buf_send(rpci
->rpc_th
, b
)) {
1211 RPC_ERR(("%s: bcm_rpc_bus_buf_send() failed\n", __FUNCTION__
));
1213 RPC_OSL_LOCK(rpci
->rpc_osh
);
1214 rpci
->wait_return
= FALSE
;
1215 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1216 bcm_rpc_err_down(rpci
);
1220 bcm_rpc_tp_agg_set(rpci
->rpc_th
, BCM_RPC_TP_HOST_AGG_AMPDU
, FALSE
);
1222 start_wait_time
= OSL_SYSUPTIME();
1223 ret
= RPC_OSL_WAIT(rpci
->rpc_osh
, RPC_RETURN_WAIT_TIMEOUT_MSEC
, &timedout
);
1225 /* When RPC_OSL_WAIT returns because of signal pending. wait for the signal to
1228 RPC_OSL_LOCK(rpci
->rpc_osh
);
1229 while ((ret
< 0) && ((OSL_SYSUPTIME() - start_wait_time
) <= RPC_RETURN_WAIT_TIMEOUT_MSEC
)) {
1230 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1231 ret
= RPC_OSL_WAIT(rpci
->rpc_osh
, RPC_RETURN_WAIT_TIMEOUT_MSEC
, &timedout
);
1232 RPC_OSL_LOCK(rpci
->rpc_osh
);
1235 if (ret
|| timedout
) {
1236 RPC_ERR(("%s: RPC call trans 0x%x return wait err %d timedout %d limit %d(ms)\n",
1237 __FUNCTION__
, (rpci
->trans
- 1), ret
, timedout
,
1238 RPC_RETURN_WAIT_TIMEOUT_MSEC
));
1239 rpci
->wait_return
= FALSE
;
1240 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1242 printf("Failed trans 0x%x len %d data 0x%x\n",
1246 bcm_rpc_dump_pktlog_high(rpci
);
1248 bcm_rpc_err_down(rpci
);
1252 /* See if we timed out or actually initialized */
1253 ASSERT(rpci
->rtn_rpcbuf
!= NULL
); /* Make sure we've got the response */
1254 retb
= rpci
->rtn_rpcbuf
;
1255 rpci
->rtn_rpcbuf
= NULL
;
1256 rpci
->wait_return
= FALSE
; /* Could have woken up by timeout */
1257 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1259 #ifdef BCMDBG_RPC /* Since successful add the entry */
1260 if (RPC_PKTLOG_ON())
1261 bcm_rpc_add_entry_tx(rpci
, &cur
);
1266 #endif /* WLC_HIGH */
1270 bcm_rpc_call_return(struct rpc_info
*rpci
, rpc_buf_t
*b
)
1272 rpc_header_t
*header
;
1274 RPC_TRACE(("%s\n", __FUNCTION__
));
1276 header
= (rpc_header_t
*)bcm_rpc_buf_push(rpci
->rpc_th
, b
, RPC_HDR_LEN
);
1278 rpc_header_prep(rpci
, header
, RPC_TYPE_RTN
, 0);
1281 if (RPC_PKTTRACE_ON()) {
1283 prhex("RPC Call Return Buf", bcm_rpc_buf_data(rpci
->rpc_th
, b
),
1284 bcm_rpc_buf_len_get(rpci
->rpc_th
, b
));
1287 #endif /* BCMDBG_RPC */
1289 /* If the TX fails, it's sender's responsibilty */
1290 if (bcm_rpc_tp_send_callreturn(rpci
->rpc_th
, b
)) {
1291 RPC_ERR(("%s: bcm_rpc_tp_buf_send() call failed\n", __FUNCTION__
));
1292 bcm_rpc_err_down(rpci
);
1299 #endif /* WLC_LOW */
1301 /* This is expected to be called at DPC of the bus driver ? */
1303 bcm_rpc_buf_recv(void *context
, rpc_buf_t
*rpc_buf
)
1306 struct rpc_info
*rpci
= (struct rpc_info
*)context
;
1307 mbool hdr_invalid
= 0;
1308 ASSERT(rpci
&& rpci
->rpc_th
);
1310 RPC_TRACE(("%s:\n", __FUNCTION__
));
1314 /* Only if the header itself checks out , and only xaction does not */
1315 hdr_invalid
= bcm_rpc_hdr_validate(rpci
, rpc_buf
, &xaction
, TRUE
);
1317 if (mboolisset(hdr_invalid
, HDR_XACTION_MISMATCH
) &&
1318 !mboolisset(hdr_invalid
, ~HDR_XACTION_MISMATCH
)) {
1319 rpc_buf_t
*node
= rpci
->reorder_pktq
;
1321 rpci
->reorder_depth
++;
1322 if (rpci
->reorder_depth
> rpci
->reorder_depth_max
)
1323 rpci
->reorder_depth_max
= rpci
->reorder_depth
;
1325 /* Catch roll-over or retries */
1326 rpci
->reorder_pktq
= rpc_buf
;
1329 bcm_rpc_buf_next_set(rpci
->rpc_th
, rpc_buf
, node
);
1331 /* if we have held too many packets, move past the hole */
1332 if (rpci
->reorder_depth
> BCM_RPC_REORDER_LIMIT
) {
1333 uint16 next_xid
= bcm_rpc_reorder_next_xid(rpci
);
1335 RPC_ERR(("%s: reorder queue depth %d, skipping ID 0x%x to 0x%x\n",
1336 __FUNCTION__
, rpci
->reorder_depth
,
1337 rpci
->oe_trans
, next_xid
));
1338 rpci
->cnt_reorder_overflow
++;
1339 rpci
->cnt_rx_drop_hole
+= (uint
)(next_xid
- rpci
->oe_trans
);
1340 rpci
->oe_trans
= next_xid
;
1341 bcm_rpc_process_reorder_queue(rpci
);
1347 /* Bail out if failed */
1348 if (!bcm_rpc_buf_recv_inorder(rpci
, rpc_buf
, hdr_invalid
))
1351 /* see if we can make progress on the reorder backlog */
1352 bcm_rpc_process_reorder_queue(rpci
);
1355 RPC_RO_UNLOCK(rpci
);
1359 bcm_rpc_process_reorder_queue(rpc_info_t
*rpci
)
1362 mbool hdr_invalid
= 0;
1364 while (rpci
->reorder_pktq
) {
1366 rpc_buf_t
*buf
= rpci
->reorder_pktq
;
1367 rpc_buf_t
*prev
= rpci
->reorder_pktq
;
1368 while (buf
!= NULL
) {
1369 rpc_buf_t
*next
= bcm_rpc_buf_next_get(rpci
->rpc_th
, buf
);
1370 hdr_invalid
= bcm_rpc_hdr_validate(rpci
, buf
, &xaction
, FALSE
);
1372 if (!mboolisset(hdr_invalid
, HDR_XACTION_MISMATCH
)) {
1373 bcm_rpc_buf_next_set(rpci
->rpc_th
, buf
, NULL
);
1375 if (buf
== rpci
->reorder_pktq
)
1376 rpci
->reorder_pktq
= next
;
1378 bcm_rpc_buf_next_set(rpci
->rpc_th
, prev
, next
);
1379 rpci
->reorder_depth
--;
1381 /* Bail out if failed */
1382 if (!bcm_rpc_buf_recv_inorder(rpci
, buf
, hdr_invalid
))
1393 /* bail if not found */
1402 bcm_rpc_buf_recv_inorder(rpc_info_t
*rpci
, rpc_buf_t
*rpc_buf
, mbool hdr_invalid
)
1404 rpc_header_t header
;
1405 rpc_acn_t acn
= RPC_NULL
;
1407 ASSERT(rpci
&& rpci
->rpc_th
);
1409 RPC_TRACE(("%s: got rpc_buf %p len %d data %p\n", __FUNCTION__
,
1410 rpc_buf
, bcm_rpc_buf_len_get(rpci
->rpc_th
, rpc_buf
),
1411 bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
)));
1414 if (RPC_PKTTRACE_ON()) {
1416 prhex("RPC Rx Buf", bcm_rpc_buf_data(rpci
->rpc_th
, rpc_buf
),
1417 bcm_rpc_buf_len_get(rpci
->rpc_th
, rpc_buf
));
1420 #endif /* BCMDBG_RPC */
1422 header
= bcm_rpc_header(rpci
, rpc_buf
);
1424 RPC_OSL_LOCK(rpci
->rpc_osh
);
1427 RPC_ERR(("%s: bcm_rpc_hdr_validate failed on 0x%08x 0x%x\n", __FUNCTION__
,
1428 header
, hdr_invalid
));
1429 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC)
1430 if (RPC_HDR_TYPE(header
) != RPC_TYPE_RTN
) {
1432 PKTFRMNATIVE(rpci
->osh
, rpc_buf
);
1434 PKTFREE(rpci
->osh
, rpc_buf
, FALSE
);
1437 bcm_rpc_tp_buf_free(rpci
->rpc_th
, rpc_buf
);
1438 #endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC) */
1439 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1443 RPC_TRACE(("%s state:0x%x type:0x%x session:0x%x xacn:0x%x\n", __FUNCTION__
, rpci
->state
,
1444 RPC_HDR_TYPE(header
), RPC_HDR_SESSION(header
), RPC_HDR_XACTION(header
)));
1446 if (bcm_rpc_buf_len_get(rpci
->rpc_th
, rpc_buf
) > RPC_HDR_LEN
)
1447 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_HDR_LEN
);
1449 /* if the head packet ends with rpc_hdr, free and advance to next packet in chain */
1452 ASSERT(bcm_rpc_buf_len_get(rpci
->rpc_th
, rpc_buf
) == RPC_HDR_LEN
);
1453 next_p
= (rpc_buf_t
*)PKTNEXT(rpci
->osh
, rpc_buf
);
1455 RPC_TRACE(("%s: following pkt chain to pkt %p len %d\n", __FUNCTION__
,
1456 next_p
, bcm_rpc_buf_len_get(rpci
->rpc_th
, next_p
)));
1458 PKTSETNEXT(rpci
->osh
, rpc_buf
, NULL
);
1459 bcm_rpc_tp_buf_free(rpci
->rpc_th
, rpc_buf
);
1461 if (rpc_buf
== NULL
) {
1462 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1467 switch (RPC_HDR_TYPE(header
)) {
1469 acn
= bcm_rpc_mgn_acn(rpci
, rpc_buf
);
1470 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_ACN_LEN
);
1471 RPC_TRACE(("Mgn: %x\n", acn
));
1475 rpci
->oe_rtn_trans
= RPC_HDR_XACTION(header
) + 1;
1479 rpci
->oe_trans
= RPC_HDR_XACTION(header
) + 1;
1486 rpc_buf
= bcm_rpc_buf_recv_high(rpci
, RPC_HDR_TYPE(header
), acn
, rpc_buf
);
1488 rpc_buf
= bcm_rpc_buf_recv_low(rpci
, header
, acn
, rpc_buf
);
1490 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1493 bcm_rpc_tp_buf_free(rpci
->rpc_th
, rpc_buf
);
1499 bcm_rpc_buf_recv_mgn_high(struct rpc_info
*rpci
, rpc_acn_t acn
, rpc_buf_t
*rpc_buf
)
1501 rpc_rc_t reason
= RPC_RC_ACK
;
1504 RPC_ERR(("%s: Recvd:%x Version: 0x%x\nState: %x Session:%d\n", __FUNCTION__
,
1505 acn
, rpci
->version
, rpci
->state
, rpci
->session
));
1508 if (acn
== RPC_CONNECT_ACK
|| acn
== RPC_CONNECT_NACK
) {
1510 if (acn
== RPC_HELLO
|| acn
== RPC_CONNECT_ACK
|| acn
== RPC_CONNECT_NACK
) {
1512 version
= bcm_rpc_mgn_ver(rpci
, rpc_buf
);
1513 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_VER_LEN
);
1515 reason
= bcm_rpc_mgn_reason(rpci
, rpc_buf
);
1516 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_RC_LEN
);
1518 RPC_ERR(("%s: Reason: %x Dongle Version: 0x%x\n", __FUNCTION__
,
1525 /* If the original thread has not given up,
1526 * then change the state and wake it up
1528 if (rpci
->state
== WAIT_HELLO
) {
1529 rpci
->state
= HELLO_RECEIVED
;
1531 RPC_ERR(("%s: Hello Received!\n", __FUNCTION__
));
1532 if (rpci
->wait_init
)
1533 RPC_OSL_WAKE(rpci
->rpc_osh
);
1537 case RPC_CONNECT_ACK
:
1538 /* If the original thread has not given up,
1539 * then change the state and wake it up
1541 if (rpci
->state
!= UNINITED
) {
1542 rpci
->state
= ESTABLISHED
;
1543 rpci
->chipid
= bcm_rpc_mgn_chipid(rpci
, rpc_buf
);
1544 bcm_rpc_buf_pull(rpci
->rpc_th
, rpc_buf
, RPC_CHIPID_LEN
);
1546 RPC_ERR(("%s: Connected!\n", __FUNCTION__
));
1547 if (rpci
->wait_init
)
1548 RPC_OSL_WAKE(rpci
->rpc_osh
);
1550 ASSERT(reason
!= RPC_RC_VER_MISMATCH
);
1553 case RPC_CONNECT_NACK
:
1554 /* Connect failed. Just bail out by waking the thread */
1555 RPC_ERR(("%s: Connect failed !!!\n", __FUNCTION__
));
1556 if (rpci
->wait_init
)
1557 RPC_OSL_WAKE(rpci
->rpc_osh
);
1561 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1564 RPC_OSL_LOCK(rpci
->rpc_osh
);
1574 bcm_rpc_buf_recv_high(struct rpc_info
*rpci
, rpc_type_t type
, rpc_acn_t acn
, rpc_buf_t
*rpc_buf
)
1576 RPC_TRACE(("%s: acn %d\n", __FUNCTION__
, acn
));
1580 if (rpci
->wait_return
) {
1581 rpci
->rtn_rpcbuf
= rpc_buf
;
1582 /* This buffer will be freed in bcm_rpc_tp_recv_rtn() */
1584 RPC_OSL_WAKE(rpci
->rpc_osh
);
1585 } else if (rpci
->state
!= DISCONNECTED
)
1586 RPC_ERR(("%s: Received return buffer but no one waiting\n", __FUNCTION__
));
1590 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC)
1591 bcm_rpc_buf_recv_mgn_high(rpci
, acn
, rpc_buf
);
1593 PKTFRMNATIVE(rpci
->osh
, rpc_buf
);
1595 PKTFREE(rpci
->osh
, rpc_buf
, FALSE
);
1598 bcm_rpc_buf_recv_mgn_high(rpci
, acn
, rpc_buf
);
1599 #endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC) */
1603 ASSERT(rpci
->state
== ESTABLISHED
);
1605 /* Prepare the current log entry but add only if the TX was successful */
1606 /* This is done here before DATA pointer gets modified */
1607 if (RPC_PKTLOG_ON()) {
1608 struct rpc_pktlog cur
;
1609 bcm_rpc_prep_entry(rpci
, rpc_buf
, &cur
, FALSE
);
1610 bcm_rpc_add_entry_rx(rpci
, &cur
);
1612 #endif /* BCMDBG_RPC */
1613 if (rpci
->dispatchcb
) {
1615 #if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) || defined(BCM_RPC_ROC)
1616 PKTTONATIVE(rpci
->osh
, rpc_buf
);
1617 #endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY || BCM_RPC_ROC */
1619 (rpci
->dispatchcb
)(rpci
->ctx
, rpc_buf
);
1620 /* The dispatch routine will free the buffer */
1623 RPC_ERR(("%s: no rpcq callback, drop the pkt\n", __FUNCTION__
));
1635 bcm_rpc_buf_recv_mgn_low(struct rpc_info
*rpci
, uint8 session
, rpc_acn_t acn
, rpc_buf_t
*rpc_buf
)
1640 RPC_TRACE(("%s: Recvd:%x Version: 0x%x\nState: %x Session:%d\n", __FUNCTION__
,
1642 rpci
->version
, rpci
->state
, rpci
->session
));
1644 if (acn
== RPC_HELLO
) {
1645 bcm_rpc_connect_resp(rpci
, RPC_HELLO
, RPC_RC_HELLO
);
1646 } else if (acn
== RPC_CONNECT
|| acn
== RPC_RESET
) {
1647 version
= bcm_rpc_mgn_ver(rpci
, rpc_buf
);
1649 RPC_ERR(("%s: Host Version: 0x%x\n", __FUNCTION__
, version
));
1651 ASSERT(rpci
->state
!= UNINITED
);
1653 if (version
!= rpci
->version
) {
1654 RPC_ERR(("RPC Establish failed due to version mismatch\n"));
1655 RPC_ERR(("Expected: 0x%x Got: 0x%x\n", rpci
->version
, version
));
1656 RPC_ERR(("Connect failed !!!\n"));
1658 rpci
->state
= WAIT_INITIALIZING
;
1659 bcm_rpc_connect_resp(rpci
, RPC_CONNECT_NACK
, RPC_RC_VER_MISMATCH
);
1663 /* When receiving CONNECT/RESET from HIGH, just
1664 * resync to the HIGH's session and reset the transactions
1666 if ((acn
== RPC_CONNECT
) && (rpci
->state
== ESTABLISHED
))
1667 reason
= RPC_RC_RECONNECT
;
1669 rpci
->session
= session
;
1671 if (bcm_rpc_connect_resp(rpci
, RPC_CONNECT_ACK
, reason
)) {
1672 /* call the resync callback if already established */
1673 if ((acn
== RPC_CONNECT
) && (rpci
->state
== ESTABLISHED
) &&
1674 (rpci
->resync_cb
)) {
1675 (rpci
->resync_cb
)(rpci
->dnctx
);
1677 rpci
->state
= ESTABLISHED
;
1679 RPC_ERR(("%s: RPC Establish failed !!!\n", __FUNCTION__
));
1682 RPC_ERR(("Connected Session:%x!\n", rpci
->session
));
1685 rpci
->rtn_trans
= 0;
1686 } else if (acn
== RPC_DOWN
) {
1692 bcm_rpc_buf_recv_low(struct rpc_info
*rpci
, rpc_header_t header
,
1693 rpc_acn_t acn
, rpc_buf_t
*rpc_buf
)
1695 switch (RPC_HDR_TYPE(header
)) {
1697 bcm_rpc_buf_recv_mgn_low(rpci
, RPC_HDR_SESSION(header
), acn
, rpc_buf
);
1702 ASSERT(rpci
->state
== ESTABLISHED
);
1704 /* Prepare the current log entry but add only if the TX was successful */
1705 /* This is done here before DATA pointer gets modified */
1706 if (RPC_PKTLOG_ON()) {
1707 struct rpc_pktlog cur
;
1708 bcm_rpc_prep_entry(rpci
, rpc_buf
, &cur
, FALSE
);
1709 bcm_rpc_add_entry_rx(rpci
, &cur
);
1711 #endif /* BCMDBG_RPC */
1713 if (rpci
->dispatchcb
) {
1714 (rpci
->dispatchcb
)(rpci
->ctx
, rpc_buf
);
1717 RPC_ERR(("%s: no rpcq callback, drop the pkt\n", __FUNCTION__
));
1728 #endif /* WLC_HIGH */
1732 bcm_rpc_pktlog_init(rpc_info_t
*rpci
)
1734 rpc_msg_level
|= RPC_PKTLOG_VAL
;
1736 if (RPC_PKTLOG_ON()) {
1737 if ((rpci
->send_log
= MALLOC(rpci
->osh
,
1738 sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
)) == NULL
)
1740 bzero(rpci
->send_log
, sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
);
1741 if ((rpci
->recv_log
= MALLOC(rpci
->osh
,
1742 sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
)) == NULL
)
1744 bzero(rpci
->recv_log
, sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
);
1747 RPC_ERR(("pktlog is on\n"));
1749 bcm_rpc_pktlog_deinit(rpci
);
1753 bcm_rpc_pktlog_deinit(rpc_info_t
*rpci
)
1755 if (rpci
->send_log
) {
1756 MFREE(rpci
->osh
, rpci
->send_log
, sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
);
1757 rpci
->send_log
= NULL
;
1759 if (rpci
->recv_log
) {
1760 MFREE(rpci
->osh
, rpci
->recv_log
, sizeof(struct rpc_pktlog
) * RPC_PKTLOG_SIZE
);
1761 rpci
->recv_log
= NULL
;
1763 rpc_msg_level
&= ~RPC_PKTLOG_VAL
; /* Turn off logging on failure */
1766 static struct rpc_pktlog
*
1767 bcm_rpc_prep_entry(struct rpc_info
* rpci
, rpc_buf_t
*b
, struct rpc_pktlog
*cur
, bool tx
)
1769 bzero(cur
, sizeof(struct rpc_pktlog
));
1771 cur
->trans
= rpci
->trans
;
1773 /* this function is called after match, so the oe_trans is already advanced */
1774 cur
->trans
= rpci
->oe_trans
- 1;
1776 cur
->len
= bcm_rpc_buf_len_get(rpci
->rpc_th
, b
);
1777 bcopy(bcm_rpc_buf_data(rpci
->rpc_th
, b
), cur
->data
, RPC_PKTLOG_DATASIZE
);
1782 bcm_rpc_add_entry_tx(struct rpc_info
* rpci
, struct rpc_pktlog
*cur
)
1784 RPC_OSL_LOCK(rpci
->rpc_osh
);
1785 bcopy(cur
, &rpci
->send_log
[rpci
->send_log_idx
], sizeof(struct rpc_pktlog
));
1786 rpci
->send_log_idx
= (rpci
->send_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1788 if (rpci
->send_log_num
< RPC_PKTLOG_SIZE
)
1789 rpci
->send_log_num
++;
1791 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1795 bcm_rpc_add_entry_rx(struct rpc_info
* rpci
, struct rpc_pktlog
*cur
)
1797 bcopy(cur
, &rpci
->recv_log
[rpci
->recv_log_idx
], sizeof(struct rpc_pktlog
));
1798 rpci
->recv_log_idx
= (rpci
->recv_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1800 if (rpci
->recv_log_num
< RPC_PKTLOG_SIZE
)
1801 rpci
->recv_log_num
++;
1803 #endif /* BCMDBG_RPC */
1807 bcm_rpc_dump(rpc_info_t
*rpci
, struct bcmstrbuf
*b
)
1811 bcm_bprintf(b
, "\nHOST rpc dump:\n");
1812 RPC_OSL_LOCK(rpci
->rpc_osh
);
1813 bcm_bprintf(b
, "Version: 0x%x State: %x\n", rpci
->version
, rpci
->state
);
1814 bcm_bprintf(b
, "session %d trans 0x%x oe_trans 0x%x rtn_trans 0x%x oe_rtn_trans 0x%x\n",
1815 rpci
->session
, rpci
->trans
, rpci
->oe_trans
,
1816 rpci
->rtn_trans
, rpci
->oe_rtn_trans
);
1817 bcm_bprintf(b
, "xactionID out of order %d\n", rpci
->cnt_xidooo
);
1818 bcm_bprintf(b
, "reorder queue depth %u first ID 0x%x, max depth %u, tossthreshold %u\n",
1819 rpci
->reorder_depth
, bcm_rpc_reorder_next_xid(rpci
), rpci
->reorder_depth_max
,
1820 BCM_RPC_REORDER_LIMIT
);
1822 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1823 return bcm_rpc_tp_dump(rpci
->rpc_th
, b
);
1830 bcm_rpc_pktlog_get(struct rpc_info
*rpci
, uint32
*buf
, uint buf_size
, bool send
)
1837 /* Clear the whole buffer */
1838 bzero(buf
, buf_size
);
1839 RPC_OSL_LOCK(rpci
->rpc_osh
);
1841 ret
= rpci
->send_log_num
;
1842 if (ret
< RPC_PKTLOG_SIZE
)
1845 start
= (rpci
->send_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1847 ret
= rpci
->recv_log_num
;
1848 if (ret
< RPC_PKTLOG_SIZE
)
1851 start
= (rpci
->recv_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1854 /* Return only first byte */
1855 if (buf_size
< (uint
) (ret
* RPC_PKTLOG_RD_LEN
)) {
1856 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1857 RPC_ERR(("%s buf too short\n", __FUNCTION__
));
1858 return BCME_BUFTOOSHORT
;
1862 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1863 RPC_ERR(("%s no record\n", __FUNCTION__
));
1868 for (i
= 0; tot
> 0; tot
--, i
++) {
1870 buf
[i
*RPC_PKTLOG_RD_LEN
] = rpci
->send_log
[start
].data
[0];
1871 buf
[i
*RPC_PKTLOG_RD_LEN
+1] = rpci
->send_log
[start
].trans
;
1872 buf
[i
*RPC_PKTLOG_RD_LEN
+2] = rpci
->send_log
[start
].len
;
1875 buf
[i
*RPC_PKTLOG_RD_LEN
] = rpci
->recv_log
[start
].data
[0];
1876 buf
[i
*RPC_PKTLOG_RD_LEN
+1] = rpci
->recv_log
[start
].trans
;
1877 buf
[i
*RPC_PKTLOG_RD_LEN
+2] = rpci
->recv_log
[start
].len
;
1880 start
= (start
% RPC_PKTLOG_SIZE
);
1882 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1884 #endif /* BCMDBG_RPC */
1887 #endif /* WLC_HIGH */
1893 _bcm_rpc_dump_pktlog(rpc_info_t
*rpci
)
1898 RPC_OSL_LOCK(rpci
->rpc_osh
);
1899 ret
= rpci
->send_log_num
;
1903 if (ret
< RPC_PKTLOG_SIZE
)
1906 start
= (rpci
->send_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1908 printf("send %d\n", ret
);
1909 for (i
= 0; ret
> 0; ret
--, i
++) {
1910 printf("[%d] trans 0x%x len %d data 0x%x\n", i
,
1911 rpci
->send_log
[start
].trans
,
1912 rpci
->send_log
[start
].len
,
1913 rpci
->send_log
[start
].data
[0]);
1915 start
= (start
% RPC_PKTLOG_SIZE
);
1918 ret
= rpci
->recv_log_num
;
1922 if (ret
< RPC_PKTLOG_SIZE
)
1925 start
= (rpci
->recv_log_idx
+ 1) % RPC_PKTLOG_SIZE
;
1927 printf("recv %d\n", ret
);
1928 for (i
= 0; ret
> 0; ret
--, i
++) {
1929 printf("[%d] trans 0x%x len %d data 0x%x\n", i
,
1930 rpci
->recv_log
[start
].trans
,
1931 rpci
->recv_log
[start
].len
,
1932 rpci
->recv_log
[start
].data
[0]);
1934 start
= (start
% RPC_PKTLOG_SIZE
);
1938 RPC_OSL_UNLOCK(rpci
->rpc_osh
);
1943 bcm_rpc_dump_pktlog_high(rpc_info_t
*rpci
)
1945 printf("HOST rpc pktlog dump:\n");
1946 _bcm_rpc_dump_pktlog(rpci
);
1952 bcm_rpc_dump_pktlog_low(uint32 arg
, uint argc
, char *argv
[])
1956 rpci
= (rpc_info_t
*)(uintptr
)arg
;
1958 printf("DONGLE rpc pktlog dump:\n");
1959 _bcm_rpc_dump_pktlog(rpci
);
1961 #endif /* WLC_HIGH */
1962 #endif /* BCMDBG_RPC */
1966 bcm_rpc_dump_state(uint32 arg
, uint argc
, char *argv
[])
1969 bcm_rpc_fatal_dump(void *arg
)
1976 uint size
= 1024*1024;
1977 #endif /* WLC_LOW */
1978 #endif /* BCMDBG_RPC */
1979 rpc_info_t
*rpci
= (rpc_info_t
*)(uintptr
)arg
;
1980 printf("DONGLE rpc dump:\n");
1981 printf("Version: 0x%x State: %x\n", rpci
->version
, rpci
->state
);
1982 printf("session %d trans 0x%x oe_trans 0x%x rtn_trans 0x%x\n",
1983 rpci
->session
, rpci
->trans
, rpci
->oe_trans
,
1985 printf("xactionID out of order %u reorder ovfl %u dropped hole %u\n",
1986 rpci
->cnt_xidooo
, rpci
->cnt_reorder_overflow
, rpci
->cnt_rx_drop_hole
);
1987 printf("reorder queue depth %u first ID 0x%x reorder_q_depth_max %d, tossthreshold %u\n",
1988 rpci
->reorder_depth
, bcm_rpc_reorder_next_xid(rpci
), rpci
->reorder_depth_max
,
1989 BCM_RPC_REORDER_LIMIT
);
1993 bcm_rpc_tp_dump(rpci
->rpc_th
);
1995 buf
= (char *)MALLOC(rpci
->osh
, size
);
1999 bcm_binit(&b
, buf
, size
);
2000 bcm_rpc_tp_dump(rpci
->rpc_th
, &b
);
2003 while ((((uintptr
)p
) < (((uintptr
)buf
) + size
)) && (*p
== '\0'))
2005 if (((uintptr
)p
) >= (((uintptr
)buf
) + size
))
2007 if ((t
= strchr(p
, '\n')) != NULL
) {
2014 MFREE(rpci
->osh
, buf
, size
);
2016 #endif /* WLC_LOW */
2017 #endif /* BCMDBG_RPC */
2021 bcm_rpc_msglevel_set(struct rpc_info
*rpci
, uint16 msglevel
, bool high
)
2024 ASSERT(high
== TRUE
);
2025 /* high 8 bits are for rpc, low 8 bits are for tp */
2026 rpc_msg_level
= msglevel
>> 8;
2027 bcm_rpc_tp_msglevel_set(rpci
->rpc_th
, (uint8
)(msglevel
& 0xff), TRUE
);
2030 ASSERT(high
== FALSE
);
2031 /* high 8 bits are for rpc, low 8 bits are for tp */
2032 rpc_msg_level
= msglevel
>> 8;
2033 bcm_rpc_tp_msglevel_set(rpci
->rpc_th
, (uint8
)(msglevel
& 0xff), FALSE
);
2039 bcm_rpc_dngl_suspend_enable_set(rpc_info_t
*rpc
, uint32 val
)
2041 rpc
->suspend_enable
= val
;
2045 bcm_rpc_dngl_suspend_enable_get(rpc_info_t
*rpc
, uint32
*pval
)
2047 *pval
= rpc
->suspend_enable
;