Skip to content

Commit

Permalink
Merged in microframe scheduler, currently disabled. Enable with dwc_o…
Browse files Browse the repository at this point in the history
…tg.microframe_schedule=1
  • Loading branch information
popcornmix committed Aug 19, 2012
1 parent f599001 commit 5cc98c1
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 41 deletions.
4 changes: 4 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
#define DWC_DRIVER_VERSION "2.94b 27-OCT-2011 (rev 01-DEC-2011)"
#define DWC_DRIVER_DESC "HS OTG USB Controller driver"

bool microframe_schedule;

static const char dwc_driver_name[] = "dwc_otg";

extern int pcd_init(
Expand Down Expand Up @@ -1337,6 +1339,8 @@ module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
module_param(microframe_schedule, bool, 0444);
MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");

/** @page "Module Parameters"
*
Expand Down
69 changes: 65 additions & 4 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@
#include "dwc_otg_hcd.h"
#include "dwc_otg_regs.h"

extern bool microframe_schedule;

//#define DEBUG_HOST_CHANNELS
#ifdef DEBUG_HOST_CHANNELS
static int last_sel_trans_num_per_scheduled = 0;
static int last_sel_trans_num_nonper_scheduled = 0;
static int last_sel_trans_num_avail_hc_at_start = 0;
static int last_sel_trans_num_avail_hc_at_end = 0;
#endif /* DEBUG_HOST_CHANNELS */

dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
{
return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
Expand Down Expand Up @@ -825,6 +835,8 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
DWC_FREE(dwc_otg_hcd);
}

int init_hcd_usecs(dwc_otg_hcd_t *_hcd);

int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
{
int retval = 0;
Expand Down Expand Up @@ -888,6 +900,10 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
dwc_otg_hcd_connect_timeout, 0);

printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled");
if (microframe_schedule)
init_hcd_usecs(hcd);

/* Initialize reset tasklet. */
hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
#ifdef DWC_DEV_SRPCAP
Expand Down Expand Up @@ -947,9 +963,12 @@ static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
hcd->flags.d32 = 0;

hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
hcd->non_periodic_channels = 0;
hcd->periodic_channels = 0;

if (!microframe_schedule) {
hcd->non_periodic_channels = 0;
hcd->periodic_channels = 0;
} else {
hcd->available_host_channels = hcd->core_if->core_params->host_channels;
}
/*
* Put all channels in the free channel list and clean up channel
* states.
Expand Down Expand Up @@ -1225,17 +1244,38 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
dwc_list_link_t *qh_ptr;
dwc_otg_qh_t *qh;
int num_channels;
dwc_irqflags_t flags;
dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;

#ifdef DEBUG_SOF
DWC_DEBUGPL(DBG_HCD, " Select Transactions\n");
#endif

#ifdef DEBUG_HOST_CHANNELS
last_sel_trans_num_per_scheduled = 0;
last_sel_trans_num_nonper_scheduled = 0;
last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels;
#endif /* DEBUG_HOST_CHANNELS */

/* Process entries in the periodic ready list. */
qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);

while (qh_ptr != &hcd->periodic_sched_ready &&
!DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
if (microframe_schedule) {
// Make sure we leave one channel for non periodic transactions.
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
if (hcd->available_host_channels <= 1) {
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
break;
}
hcd->available_host_channels--;
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
#ifdef DEBUG_HOST_CHANNELS
last_sel_trans_num_per_scheduled++;
#endif /* DEBUG_HOST_CHANNELS */
}
qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
assign_and_init_hc(hcd, qh);

Expand All @@ -1244,8 +1284,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
* periodic assigned schedule.
*/
qh_ptr = DWC_LIST_NEXT(qh_ptr);
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
&qh->qh_list_entry);
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);

ret_val = DWC_OTG_TRANSACTION_PERIODIC;
}
Expand All @@ -1258,10 +1300,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
qh_ptr = hcd->non_periodic_sched_inactive.next;
num_channels = hcd->core_if->core_params->host_channels;
while (qh_ptr != &hcd->non_periodic_sched_inactive &&
(hcd->non_periodic_channels <
(microframe_schedule || hcd->non_periodic_channels <
num_channels - hcd->periodic_channels) &&
!DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {

if (microframe_schedule) {
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
if (hcd->available_host_channels < 1) {
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
break;
}
hcd->available_host_channels--;
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
#ifdef DEBUG_HOST_CHANNELS
last_sel_trans_num_nonper_scheduled++;
#endif /* DEBUG_HOST_CHANNELS */
}
qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);

assign_and_init_hc(hcd, qh);
Expand All @@ -1271,8 +1325,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
* non-periodic active schedule.
*/
qh_ptr = DWC_LIST_NEXT(qh_ptr);
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
&qh->qh_list_entry);
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);

if (ret_val == DWC_OTG_TRANSACTION_NONE) {
ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
Expand All @@ -1283,6 +1339,11 @@ dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
hcd->non_periodic_channels++;
}

#ifdef DEBUG_HOST_CHANNELS
last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
#endif /* DEBUG_HOST_CHANNELS */

DWC_SPINLOCK_FREE(channel_lock);
return ret_val;
}

Expand Down
25 changes: 23 additions & 2 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ typedef struct dwc_otg_qh {

/** @} */


uint16_t speed;
uint16_t frame_usecs[8];
} dwc_otg_qh_t;

DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
Expand Down Expand Up @@ -476,6 +479,19 @@ struct dwc_otg_hcd {
*/
uint16_t periodic_usecs;

/**
* Total bandwidth claimed so far for all periodic transfers
* in a frame.
* This will include a mixture of HS and FS transfers.
* Units are microseconds per (micro)frame.
* We have a budget per frame and have to schedule
* transactions accordingly.
* Watch out for the fact that things are actually scheduled for the
* "next frame".
*/
uint16_t frame_usecs[8];


/**
* Frame number read from the core at SOF. The value ranges from 0 to
* DWC_HFNUM_MAX_FRNUM.
Expand All @@ -498,12 +514,17 @@ struct dwc_otg_hcd {
* transaction and at least one host channel available for
* non-periodic transactions.
*/
int periodic_channels;
int periodic_channels; /* microframe_schedule==0 */

/**
* Number of host channels assigned to non-periodic transfers.
*/
int non_periodic_channels; /* microframe_schedule==0 */

/**
* Number of host channels assigned to non-periodic transfers.
*/
int non_periodic_channels;
int available_host_channels;

/**
* Array of pointers to the host channel descriptors. Allows accessing
Expand Down
21 changes: 16 additions & 5 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#include "dwc_otg_hcd.h"
#include "dwc_otg_regs.h"

extern bool microframe_schedule;

static inline uint8_t frame_list_idx(uint16_t frame)
{
return (frame & (MAX_FRLIST_EN_NUM - 1));
Expand Down Expand Up @@ -273,10 +275,18 @@ void dump_frame_list(dwc_otg_hcd_t * hcd)

static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
{
dwc_irqflags_t flags;
dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();

dwc_hc_t *hc = qh->channel;
if (dwc_qh_is_non_per(qh))
hcd->non_periodic_channels--;
else
if (dwc_qh_is_non_per(qh)) {
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
if (!microframe_schedule)
hcd->non_periodic_channels--;
else
hcd->available_host_channels++;
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
} else
update_frame_list(hcd, qh, 0);

/*
Expand All @@ -296,6 +306,7 @@ static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
dwc_memset(qh->desc_list, 0x00,
sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
}
DWC_SPINLOCK_FREE(channel_lock);
}

/**
Expand Down Expand Up @@ -358,7 +369,7 @@ void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
release_channel_ddma(hcd, qh);

if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
&& !hcd->periodic_channels && hcd->frame_list) {
&& (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {

per_sched_disable(hcd);
frame_list_free(hcd);
Expand Down Expand Up @@ -665,7 +676,7 @@ static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)

qtd->in_process = 1;

if (qh->ep_type == UE_CONTROL)
if (qh->ep_type == UE_CONTROL)
break;

if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
Expand Down
36 changes: 24 additions & 12 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "dwc_otg_hcd.h"
#include "dwc_otg_regs.h"

extern bool microframe_schedule;

/** @file
* This file contains the implementation of the HCD Interrupt handlers.
*/
Expand Down Expand Up @@ -794,6 +796,8 @@ static void release_channel(dwc_otg_hcd_t * hcd,
{
dwc_otg_transaction_type_e tr_type;
int free_qtd;
dwc_irqflags_t flags;
dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();

DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
__func__, hc->hc_num, halt_status, hc->xfer_len);
Expand Down Expand Up @@ -853,26 +857,34 @@ static void release_channel(dwc_otg_hcd_t * hcd,
dwc_otg_hc_cleanup(hcd->core_if, hc);
DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);

switch (hc->ep_type) {
case DWC_OTG_EP_TYPE_CONTROL:
case DWC_OTG_EP_TYPE_BULK:
hcd->non_periodic_channels--;
break;
if (!microframe_schedule) {
switch (hc->ep_type) {
case DWC_OTG_EP_TYPE_CONTROL:
case DWC_OTG_EP_TYPE_BULK:
hcd->non_periodic_channels--;
break;

default:
/*
* Don't release reservations for periodic channels here.
* That's done when a periodic transfer is descheduled (i.e.
* when the QH is removed from the periodic schedule).
*/
break;
default:
/*
* Don't release reservations for periodic channels here.
* That's done when a periodic transfer is descheduled (i.e.
* when the QH is removed from the periodic schedule).
*/
break;
}
} else {

DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
hcd->available_host_channels++;
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
}

/* Try to queue more transfers now that there's a free channel. */
tr_type = dwc_otg_hcd_select_transactions(hcd);
if (tr_type != DWC_OTG_TRANSACTION_NONE) {
dwc_otg_hcd_queue_transactions(hcd, tr_type);
}
DWC_SPINLOCK_FREE(channel_lock);
}

/**
Expand Down
Loading

0 comments on commit 5cc98c1

Please sign in to comment.