Skip to content

Commit c55dc6b

Browse files
Adrian ChaddAdrian Chadd
authored andcommitted
[mtwn] wip (crashes) cmd rework
Will complete the commit message,e tc when I'm done
1 parent a71a379 commit c55dc6b

File tree

4 files changed

+190
-39
lines changed

4 files changed

+190
-39
lines changed

otus/freebsd/src/sys/dev/mtwn/usb/if_mtwn_usb_cmd.c

Lines changed: 182 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ mtwn_usb_alloc_cmd_list(struct mtwn_usb_softc *uc)
122122
TAILQ_INIT(&uc->uc_cmd_pending);
123123
TAILQ_INIT(&uc->uc_cmd_waiting);
124124
TAILQ_INIT(&uc->uc_cmd_inactive);
125+
TAILQ_INIT(&uc->uc_cmd_completed);
125126

126127
ret = mtwn_usb_cmd_alloc_list_array(uc, uc->uc_cmd,
127128
MTWN_USB_CMD_LIST_COUNT, MTWN_USB_CMDBUFSZ);
@@ -145,6 +146,7 @@ mtwn_usb_free_cmd_list(struct mtwn_usb_softc *uc)
145146
TAILQ_INIT(&uc->uc_cmd_pending);
146147
TAILQ_INIT(&uc->uc_cmd_waiting);
147148
TAILQ_INIT(&uc->uc_cmd_inactive);
149+
TAILQ_INIT(&uc->uc_cmd_completed);
148150
}
149151

150152
/**
@@ -156,6 +158,9 @@ mtwn_usb_free_cmd_list(struct mtwn_usb_softc *uc)
156158
* but that way we don't need to worry about the sending thread timing
157159
* out - the mtwn_cmd response buffer will always be available.
158160
*
161+
* This must only be called on buffers that are in the ALLOCED state;
162+
* ie they're not on any lists.
163+
*
159164
* @param uc usb_softc
160165
* @param cmd command to set completion info for
161166
* @param buf payload buffer to copy from
@@ -166,6 +171,12 @@ void
166171
mtwn_usb_cmd_copyin_response(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd,
167172
const char *buf, int len)
168173
{
174+
struct mtwn_softc *sc = &uc->uc_sc;
175+
176+
if (cmd->state != MTWN_CMD_STATE_ALLOCED)
177+
MTWN_WARN_PRINTF(sc, "%s: cmd %p has the wrong state! (%d)\n",
178+
__func__, cmd, cmd->state);
179+
169180
/*
170181
* If we get an error or zero-size response then don't copy, but do set
171182
* completion.
@@ -190,17 +201,24 @@ mtwn_usb_cmd_copyin_response(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd,
190201
}
191202

192203
/**
193-
* @brief Complete the given command, re-insert it on the inactive list.
204+
* @brief Return the given buffer to the inactive list.
205+
*
206+
* This must only be called on a cmd buffer that isn't on any list,
207+
* and is in the ALLOCED state.
194208
*/
195-
void
196-
mtwn_usb_cmd_complete(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
209+
static void
210+
mtwn_usb_cmd_return_inactive(struct mtwn_usb_softc *uc,
211+
struct mtwn_cmd *cmd)
197212
{
198213
struct mtwn_softc *sc = &uc->uc_sc;
199214
MTWN_LOCK_ASSERT(sc, MA_OWNED);
200215

201-
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: cmd=%p; completing\n",
216+
if (cmd->state != MTWN_CMD_STATE_ALLOCED)
217+
MTWN_WARN_PRINTF(sc, "%s: cmd %p has the wrong state! (%d)\n",
218+
__func__, cmd, cmd->state);
219+
220+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: cmd=%p; returning to inactive\n",
202221
__func__, cmd);
203-
wakeup(cmd);
204222

205223
/* Free response buffer contents */
206224
if (cmd->resp.buf != NULL)
@@ -211,10 +229,53 @@ mtwn_usb_cmd_complete(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
211229
cmd->state = MTWN_CMD_STATE_INACTIVE;
212230
}
213231

232+
/**
233+
* @brief Complete the given command, re-insert it on the inactive list.
234+
*
235+
* The command must be in the ALLOCED state and not on any list.
236+
*
237+
* If the buffer is 'wait', then move it to the completed list before
238+
* waking up. If not, just free it.
239+
*/
240+
void
241+
mtwn_usb_cmd_complete(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
242+
{
243+
struct mtwn_softc *sc = &uc->uc_sc;
244+
MTWN_LOCK_ASSERT(sc, MA_OWNED);
245+
246+
if (cmd->state != MTWN_CMD_STATE_ALLOCED)
247+
MTWN_WARN_PRINTF(sc, "%s: cmd %p has the wrong state! (%d)\n",
248+
__func__, cmd, cmd->state);
249+
250+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: cmd=%p; completing\n",
251+
__func__, cmd);
252+
253+
if (cmd->flags.do_wait == true) {
254+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD,
255+
"%s: cmd=%p; moving to COMPLETED queue\n", __func__, cmd);
256+
/* Move the buffer to the completed state */
257+
TAILQ_INSERT_TAIL(&uc->uc_cmd_completed, cmd, next);
258+
cmd->state = MTWN_CMD_STATE_COMPLETED;
259+
260+
/* Signal any waiter that the command has completed */
261+
wakeup(cmd);
262+
} else {
263+
/* Signal any waiter that the command has completed */
264+
wakeup(cmd);
265+
266+
/* Return the buffer to the inactive list */
267+
mtwn_usb_cmd_return_inactive(uc, cmd);
268+
}
269+
}
270+
214271
/*
215-
* Handle completion of the given command buffer.
272+
* @brief Handle completion of the given command buffer.
273+
*
274+
* The command buffer must not be on any active lists, and must be
275+
* in the ALLOCED state.
216276
*
217-
* Note the caller still needs to shuffle it to the inactive list.
277+
* If we're required to wait for a follow-up RX notification (do_wait=true)
278+
* then move it to WAITING, else immediately complete it.
218279
*/
219280
static void
220281
mtwn_usb_cmd_eof(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
@@ -223,20 +284,24 @@ mtwn_usb_cmd_eof(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
223284

224285
MTWN_LOCK_ASSERT(sc, MA_OWNED);
225286

226-
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: completed, cmd=%p, do_wait=%d\n",
227-
__func__, cmd, cmd->flags.do_wait);
287+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: completed, cmd=%p, do_wait=%d, state=%d\n",
288+
__func__, cmd, cmd->flags.do_wait, cmd->state);
289+
290+
if (cmd->state != MTWN_CMD_STATE_ALLOCED)
291+
MTWN_WARN_PRINTF(sc, "%s: cmd %p has the wrong state! (%d)\n",
292+
__func__, cmd, cmd->state);
228293

229294
if (cmd->flags.do_wait == true) {
230-
cmd->state = MTWN_CMD_STATE_WAITING;
231295
TAILQ_INSERT_HEAD(&uc->uc_cmd_waiting, cmd, next);
296+
cmd->state = MTWN_CMD_STATE_WAITING;
232297
} else
233298
mtwn_usb_cmd_complete(uc, cmd);
234299
}
235300

236301
/**
237302
* @brief wait for the command buffer in question to complete.
238303
*/
239-
int
304+
static int
240305
mtwn_usb_cmd_wait(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd, int timeout)
241306
{
242307
struct mtwn_softc *sc = &uc->uc_sc;
@@ -305,6 +370,8 @@ mtwn_usb_cmd_get(struct mtwn_usb_softc *uc, int size, int rx_size)
305370
TAILQ_REMOVE_HEAD(&uc->uc_cmd_inactive, next);
306371
cmd->state = MTWN_CMD_STATE_ALLOCED;
307372

373+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: cmd=%p\n", __func__, cmd);
374+
308375
return (cmd);
309376
}
310377

@@ -319,14 +386,9 @@ mtwn_usb_cmd_return(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
319386
struct mtwn_softc *sc = &uc->uc_sc;
320387

321388
MTWN_LOCK_ASSERT(sc, MA_OWNED);
322-
323-
/* Free response buffer contents */
324-
if (cmd->resp.buf != NULL)
325-
free(cmd->resp.buf, M_USBDEV);
326-
bzero(&cmd->resp, sizeof(cmd->resp));
327-
328-
TAILQ_INSERT_TAIL(&uc->uc_cmd_inactive, cmd, next);
329-
cmd->state = MTWN_CMD_STATE_INACTIVE;
389+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: cmd=%p, state=%d\n", __func__, cmd, state);
390+
/* Return the buffer to the inactive list */
391+
mtwn_usb_cmd_return_inactive(uc, cmd);
330392
}
331393

332394
/**
@@ -340,6 +402,9 @@ mtwn_usb_cmd_queue(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
340402
struct mtwn_softc *sc = &uc->uc_sc;
341403
MTWN_LOCK_ASSERT(sc, MA_OWNED);
342404

405+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD,
406+
"%s: cmd=%p\n", __func__, cmd);
407+
343408
TAILQ_INSERT_TAIL(&uc->uc_cmd_pending, cmd, next);
344409
cmd->state = MTWN_CMD_STATE_PENDING;
345410
usbd_transfer_start(uc->uc_xfer[MTWN_BULK_TX_INBAND_CMD]);
@@ -352,8 +417,8 @@ mtwn_usb_cmd_queue(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd)
352417
* Note to the caller that once this is called, the buffer is no
353418
* longer owned by the caller.
354419
*
355-
* Also note this isn't going to wait for the RESPONSE, only the
356-
* transfer completed.
420+
* This will either wait for the TX completion (do_wait == false);
421+
* or TX + RX completion (do_wait == true).
357422
*/
358423
int
359424
mtwn_usb_cmd_queue_wait(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd,
@@ -364,15 +429,100 @@ mtwn_usb_cmd_queue_wait(struct mtwn_usb_softc *uc, struct mtwn_cmd *cmd,
364429

365430
MTWN_LOCK_ASSERT(sc, MA_OWNED);
366431

432+
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD,
433+
"%s: cmd=%p; timeout=%d, wait_resp=%d\n", __func__, cmd,
434+
timeout, wait_resp);
435+
367436
/* Wait for completion, not just transmit */
368437
cmd->flags.do_wait = wait_resp;
369438

439+
/* Enqueue */
370440
TAILQ_INSERT_TAIL(&uc->uc_cmd_pending, cmd, next);
371441
cmd->state = MTWN_CMD_STATE_PENDING;
372442
usbd_transfer_start(uc->uc_xfer[MTWN_BULK_TX_INBAND_CMD]);
373443

444+
/* Wait for TX completion, optional RX completion */
374445
ret = mtwn_usb_cmd_wait(uc, cmd, timeout);
375-
return (ret);
446+
447+
/*
448+
* If it's a timeout, then mark it as no longer waiting so it'll
449+
* be immediately freed, or free it here if we have to.
450+
*/
451+
if (ret != 0) {
452+
/* error path */
453+
MTWN_WARN_PRINTF(sc, "%s: cmd %p (state %d) timeout\n", __func__, cmd, cmd->state);
454+
cmd->flags.do_wait = false;
455+
456+
/* TODO: refactor this out */
457+
switch (cmd->state) {
458+
case MTWN_CMD_STATE_ACTIVE:
459+
case MTWN_CMD_STATE_PENDING:
460+
/* These two will complete w/ do_wait and go straight to inactive */
461+
break;
462+
case MTWN_CMD_STATE_WAITING:
463+
/*
464+
* Don't wait until the next firmware RX notification
465+
* to run through the waiting list and free this; just
466+
* free it now.
467+
*/
468+
TAILQ_REMOVE(&uc->uc_cmd_waiting, cmd, next);
469+
cmd->state = MTWN_CMD_STATE_ALLOCED;
470+
mtwn_usb_cmd_return_inactive(uc, cmd);
471+
break;
472+
case MTWN_CMD_STATE_COMPLETED:
473+
MTWN_WARN_PRINTF(sc,
474+
"%s: cmd %p timeout but state=COMPLETED?\n",
475+
__func__, cmd);
476+
/*
477+
* This is a weird situation to be in, but at least
478+
* handle it.
479+
*
480+
* This may actually be OK and we may want to just
481+
* jump to the normal completion path / response
482+
* path below somehow.
483+
*/
484+
TAILQ_REMOVE(&uc->uc_cmd_completed, cmd, next);
485+
cmd->state = MTWN_CMD_STATE_ALLOCED;
486+
mtwn_usb_cmd_return_inactive(uc, cmd);
487+
break;
488+
default:
489+
/* TODO: actually figure out what list to remove it from, do so, etc */
490+
MTWN_WARN_PRINTF(sc, "%s: cmd %p (state %d) invalid/unhandled state!\n", __func__, cmd, cmd->state);
491+
break;
492+
}
493+
494+
return (ret);
495+
}
496+
MTWN_DEBUG_PRINTF(sc, "%s: completion, cmd=%p, state=%d, resp=%d, wait=%d\n", __func__, cmd, state, cmd->flags.resp_set, cmd->flags.do_wait);
497+
/* Completion path */
498+
499+
/* handle response */
500+
if (cmd->flags.resp_set == true) {
501+
MTWN_TODO_PRINTF(sc,
502+
"%s: TODO: **** COMPLETION COPYOUT TIME (%p) ****\n",
503+
__func__, cmd);
504+
/* XXX TODO: copy the RX specific payload out */
505+
}
506+
507+
/*
508+
* if we're waiting for the response on this command buffer then
509+
* we need to also clean it up.
510+
*/
511+
if (cmd->flags.do_wait == true) {
512+
/* XXX refactor this out */
513+
if (cmd->state != MTWN_CMD_STATE_COMPLETED)
514+
MTWN_WARN_PRINTF(sc, "%s: cmd %p in wrong state (%d)\n",
515+
__func__, cmd, cmd->state);
516+
517+
/* Remove from the completed list */
518+
TAILQ_REMOVE(&uc->uc_cmd_completed, cmd, next);
519+
cmd->state = MTWN_CMD_STATE_ALLOCED;
520+
521+
/* Return the buffer to the inactive list */
522+
mtwn_usb_cmd_return_inactive(uc, cmd);
523+
}
524+
525+
return (0);
376526
}
377527

378528
/*
@@ -383,7 +533,7 @@ mtwn_bulk_tx_inband_cmd_callback(struct usb_xfer *xfer, usb_error_t error)
383533
{
384534
struct mtwn_usb_softc *uc = usbd_xfer_softc(xfer);
385535
struct mtwn_softc *sc = &uc->uc_sc;
386-
struct mtwn_cmd *cmd;
536+
struct mtwn_cmd *cmd, *c;
387537

388538
MTWN_DPRINTF(sc, MTWN_DEBUG_CMD, "%s: called\n", __func__);
389539

@@ -397,6 +547,14 @@ mtwn_bulk_tx_inband_cmd_callback(struct usb_xfer *xfer, usb_error_t error)
397547
TAILQ_REMOVE_HEAD(&uc->uc_cmd_active, next);
398548
cmd->state = MTWN_CMD_STATE_ALLOCED;
399549

550+
/*
551+
* TODO: usbd_xfer_get_priv() to fetch cmd, verify against
552+
* uc_cmd_active head!
553+
*/
554+
c = usbd_xfer_get_priv(xfer);
555+
if (c != cmd)
556+
MTWN_WARN_PRINTF(sc,
557+
"%s: mismatch between xfer and cmd\n", __func__);
400558
/* TX completed */
401559
mtwn_usb_cmd_eof(uc, cmd);
402560
/* FALLTHROUGH */
@@ -412,6 +570,7 @@ mtwn_bulk_tx_inband_cmd_callback(struct usb_xfer *xfer, usb_error_t error)
412570
cmd->state = MTWN_CMD_STATE_ACTIVE;
413571

414572
usbd_xfer_set_frame_data(xfer, 0, cmd->buf, cmd->buflen);
573+
usbd_xfer_set_priv(xfer, cmd);
415574
usbd_transfer_submit(xfer);
416575
break;
417576
default:

otus/freebsd/src/sys/dev/mtwn/usb/if_mtwn_usb_cmd.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ extern struct mtwn_cmd * mtwn_usb_cmd_get_waiting(struct mtwn_usb_softc *);
2323
extern void mtwn_usb_cmd_copyin_response(struct mtwn_usb_softc *,
2424
struct mtwn_cmd *, const char *, int);
2525
extern void mtwn_usb_cmd_complete(struct mtwn_usb_softc *, struct mtwn_cmd *);
26-
extern int mtwn_usb_cmd_wait(struct mtwn_usb_softc *, struct mtwn_cmd *,
27-
int);
2826

2927
extern struct mtwn_cmd * mtwn_usb_cmd_get(struct mtwn_usb_softc *, int, int);
3028
extern void mtwn_usb_cmd_return(struct mtwn_usb_softc *, struct mtwn_cmd *);

otus/freebsd/src/sys/dev/mtwn/usb/if_mtwn_usb_var.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ enum {
6161
* + It's the USB transfer buffer, for both transmit/receive endpoints
6262
* + It holds a node reference during 802.11 TX
6363
* + It holds an mbuf reference during 802.11 TX
64-
* + For the command endpoint, it holds state and can be slept on
65-
* for the transfer completion notification
6664
*/
6765
struct mtwn_data {
6866
uint8_t *buf;
@@ -127,6 +125,7 @@ struct mtwn_usb_softc {
127125
mtwn_cmd_head uc_cmd_inactive;
128126
mtwn_cmd_head uc_cmd_pending;
129127
mtwn_cmd_head uc_cmd_waiting;
128+
mtwn_cmd_head uc_cmd_completed;
130129
};
131130

132131
#endif /* __IF_MTWN_USB_VAR_H__ */

0 commit comments

Comments
 (0)