From cbd4880e3ce3dc60748e9a57b01c51f1d1221a21 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 19 Jan 2014 17:27:13 +0000 Subject: ralink: add xhci driver Signed-off-by: John Crispin git-svn-id: svn://svn.openwrt.org/openwrt/trunk@39328 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../files/drivers/usb/host/xhci-mtk-scheduler.c | 608 +++++++++++++++++++++ 1 file changed, 608 insertions(+) create mode 100644 target/linux/ramips/files/drivers/usb/host/xhci-mtk-scheduler.c (limited to 'target/linux/ramips/files/drivers/usb/host/xhci-mtk-scheduler.c') diff --git a/target/linux/ramips/files/drivers/usb/host/xhci-mtk-scheduler.c b/target/linux/ramips/files/drivers/usb/host/xhci-mtk-scheduler.c new file mode 100644 index 0000000000..bf6a8bdc19 --- /dev/null +++ b/target/linux/ramips/files/drivers/usb/host/xhci-mtk-scheduler.c @@ -0,0 +1,608 @@ +#include "xhci-mtk-scheduler.h" +#include /* printk() */ + +static struct sch_ep **ss_out_eps[MAX_EP_NUM]; +static struct sch_ep **ss_in_eps[MAX_EP_NUM]; +static struct sch_ep **hs_eps[MAX_EP_NUM]; //including tt isoc +static struct sch_ep **tt_intr_eps[MAX_EP_NUM]; + + +int mtk_xhci_scheduler_init(void){ + int i; + + for(i=0; idev_speed = dev_speed; + tmp_ep->isTT = isTT; + tmp_ep->is_in = is_in; + tmp_ep->ep_type = ep_type; + tmp_ep->maxp = maxp; + tmp_ep->interval = interval; + tmp_ep->burst = burst; + tmp_ep->mult = mult; + tmp_ep->offset = offset; + tmp_ep->repeat = repeat; + tmp_ep->pkts = pkts; + tmp_ep->cs_count = cs_count; + tmp_ep->burst_mode = burst_mode; + tmp_ep->bw_cost = bw_cost; + tmp_ep->ep = ep; + ep_array[i] = tmp_ep; + return SCH_SUCCESS; + } + } + return SCH_FAIL; +} + +int count_ss_bw(int is_in, int ep_type, int maxp, int interval, int burst, int mult, int offset, int repeat + , int td_size){ + int i, j, k; + int bw_required[3]; + int final_bw_required; + int bw_required_per_repeat; + int tmp_bw_required; + struct sch_ep *cur_sch_ep; + struct sch_ep **ep_array; + int cur_offset; + int cur_ep_offset; + int tmp_offset; + int tmp_interval; + int ep_offset; + int ep_interval; + int ep_repeat; + int ep_mult; + + if(is_in){ + ep_array = (struct sch_ep **)ss_in_eps; + } + else{ + ep_array = (struct sch_ep **)ss_out_eps; + } + + bw_required[0] = 0; + bw_required[1] = 0; + bw_required[2] = 0; + + if(repeat == 0){ + final_bw_required = 0; + for(i=0; iinterval; + ep_offset = cur_sch_ep->offset; + if(cur_sch_ep->repeat == 0){ + if(ep_interval >= interval){ + tmp_offset = ep_offset + ep_interval - offset; + tmp_interval = interval; + } + else{ + tmp_offset = offset + interval - ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset % tmp_interval == 0){ + final_bw_required += cur_sch_ep->bw_cost; + } + } + else{ + ep_repeat = cur_sch_ep->repeat; + ep_mult = cur_sch_ep->mult; + for(k=0; k<=ep_mult; k++){ + cur_ep_offset = ep_offset+(k*ep_mult); + if(ep_interval >= interval){ + tmp_offset = cur_ep_offset + ep_interval - offset; + tmp_interval = interval; + } + else{ + tmp_offset = offset + interval - cur_ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset % tmp_interval == 0){ + final_bw_required += cur_sch_ep->bw_cost; + break; + } + } + } + } + final_bw_required += td_size; + } + else{ + bw_required_per_repeat = maxp * (burst+1); + for(j=0; j<=mult; j++){ + tmp_bw_required = 0; + cur_offset = offset+(j*repeat); + for(i=0; iinterval; + ep_offset = cur_sch_ep->offset; + if(cur_sch_ep->repeat == 0){ + if(ep_interval >= interval){ + tmp_offset = ep_offset + ep_interval - cur_offset; + tmp_interval = interval; + } + else{ + tmp_offset = cur_offset + interval - ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset % tmp_interval == 0){ + tmp_bw_required += cur_sch_ep->bw_cost; + } + } + else{ + ep_repeat = cur_sch_ep->repeat; + ep_mult = cur_sch_ep->mult; + for(k=0; k<=ep_mult; k++){ + cur_ep_offset = ep_offset+(k*ep_repeat); + if(ep_interval >= interval){ + tmp_offset = cur_ep_offset + ep_interval - cur_offset; + tmp_interval = interval; + } + else{ + tmp_offset = cur_offset + interval - cur_ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset % tmp_interval == 0){ + tmp_bw_required += cur_sch_ep->bw_cost; + break; + } + } + } + } + bw_required[j] = tmp_bw_required; + } + final_bw_required = SS_BW_BOUND; + for(j=0; j<=mult; j++){ + if(bw_required[j] < final_bw_required){ + final_bw_required = bw_required[j]; + } + } + final_bw_required += bw_required_per_repeat; + } + return final_bw_required; +} + +int count_hs_bw(int ep_type, int maxp, int interval, int offset, int td_size){ + int i; + int bw_required; + struct sch_ep *cur_sch_ep; + int tmp_offset; + int tmp_interval; + int ep_offset; + int ep_interval; + int cur_tt_isoc_interval; //for isoc tt check + + bw_required = 0; + for(i=0; ioffset; + ep_interval = cur_sch_ep->interval; + + if(cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC){ + cur_tt_isoc_interval = ep_interval<<3; + if(ep_interval >= interval){ + tmp_offset = ep_offset + cur_tt_isoc_interval - offset; + tmp_interval = interval; + } + else{ + tmp_offset = offset + interval - ep_offset; + tmp_interval = cur_tt_isoc_interval; + } + if(cur_sch_ep->is_in){ + if((tmp_offset%tmp_interval >=2) && (tmp_offset%tmp_interval <= cur_sch_ep->cs_count)){ + bw_required += 188; + } + } + else{ + if(tmp_offset%tmp_interval <= cur_sch_ep->cs_count){ + bw_required += 188; + } + } + } + else{ + if(ep_interval >= interval){ + tmp_offset = ep_offset + ep_interval - offset; + tmp_interval = interval; + } + else{ + tmp_offset = offset + interval - ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset%tmp_interval == 0){ + bw_required += cur_sch_ep->bw_cost; + } + } + } + bw_required += td_size; + return bw_required; +} + +int count_tt_isoc_bw(int is_in, int maxp, int interval, int offset, int td_size){ + char is_cs; + int mframe_idx, frame_idx, s_frame, s_mframe, cur_mframe; + int bw_required, max_bw; + int ss_cs_count; + int cs_mframe; + int max_frame; + int i,j; + struct sch_ep *cur_sch_ep; + int ep_offset; + int ep_interval; + int ep_cs_count; + int tt_isoc_interval; //for isoc tt check + int cur_tt_isoc_interval; //for isoc tt check + int tmp_offset; + int tmp_interval; + + is_cs = 0; + + tt_isoc_interval = interval<<3; //frame to mframe + if(is_in){ + is_cs = 1; + } + s_frame = offset/8; + s_mframe = offset%8; + ss_cs_count = (maxp + (188 - 1))/188; + if(is_cs){ + cs_mframe = offset%8 + 2 + ss_cs_count; + if (cs_mframe <= 6) + ss_cs_count += 2; + else if (cs_mframe == 7) + ss_cs_count++; + else if (cs_mframe > 8) + return -1; + } + max_bw = 0; + if(is_in){ + i=2; + } + for(cur_mframe = offset+i; ioffset; + ep_interval = cur_sch_ep->interval; + if(cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC){ + //isoc tt + //check if mframe offset overlap + //if overlap, add 188 to the bw + cur_tt_isoc_interval = ep_interval<<3; + if(cur_tt_isoc_interval >= tt_isoc_interval){ + tmp_offset = (ep_offset+cur_tt_isoc_interval) - cur_mframe; + tmp_interval = tt_isoc_interval; + } + else{ + tmp_offset = (cur_mframe+tt_isoc_interval) - ep_offset; + tmp_interval = cur_tt_isoc_interval; + } + if(cur_sch_ep->is_in){ + if((tmp_offset%tmp_interval >=2) && (tmp_offset%tmp_interval <= cur_sch_ep->cs_count)){ + bw_required += 188; + } + } + else{ + if(tmp_offset%tmp_interval <= cur_sch_ep->cs_count){ + bw_required += 188; + } + } + + } + else if(cur_sch_ep->ep_type == USB_EP_INT || cur_sch_ep->ep_type == USB_EP_ISOC){ + //check if mframe + if(ep_interval >= tt_isoc_interval){ + tmp_offset = (ep_offset+ep_interval) - cur_mframe; + tmp_interval = tt_isoc_interval; + } + else{ + tmp_offset = (cur_mframe+tt_isoc_interval) - ep_offset; + tmp_interval = ep_interval; + } + if(tmp_offset%tmp_interval == 0){ + bw_required += cur_sch_ep->bw_cost; + } + } + } + bw_required += 188; + if(bw_required > max_bw){ + max_bw = bw_required; + } + } + return max_bw; +} + +int count_tt_intr_bw(int interval, int frame_offset){ + //check all eps in tt_intr_eps + int ret; + int i,j; + int ep_offset; + int ep_interval; + int tmp_offset; + int tmp_interval; + ret = SCH_SUCCESS; + struct sch_ep *cur_sch_ep; + + for(i=0; ioffset; + ep_interval = cur_sch_ep->interval; + if(ep_interval >= interval){ + tmp_offset = ep_offset + ep_interval - frame_offset; + tmp_interval = interval; + } + else{ + tmp_offset = frame_offset + interval - ep_offset; + tmp_interval = ep_interval; + } + + if(tmp_offset%tmp_interval==0){ + return SCH_FAIL; + } + } + return SCH_SUCCESS; +} + +struct sch_ep * mtk_xhci_scheduler_remove_ep(int dev_speed, int is_in, int isTT, int ep_type, mtk_u32 *ep){ + int i; + struct sch_ep **ep_array; + struct sch_ep *cur_ep; + + if (is_in && dev_speed == USB_SPEED_SUPER) { + ep_array = (struct sch_ep **)ss_in_eps; + } + else if (dev_speed == USB_SPEED_SUPER) { + ep_array = (struct sch_ep **)ss_out_eps; + } + else if (dev_speed == USB_SPEED_HIGH || (isTT && ep_type == USB_EP_ISOC)) { + ep_array = (struct sch_ep **)hs_eps; + } + else { + ep_array = (struct sch_ep **)tt_intr_eps; + } + for (i = 0; i < MAX_EP_NUM; i++) { + cur_ep = (struct sch_ep *)ep_array[i]; + if(cur_ep != NULL && cur_ep->ep == ep){ + ep_array[i] = NULL; + return cur_ep; + } + } + return NULL; +} + +int mtk_xhci_scheduler_add_ep(int dev_speed, int is_in, int isTT, int ep_type, int maxp, int interval, int burst + , int mult, mtk_u32 *ep, mtk_u32 *ep_ctx, struct sch_ep *sch_ep){ + mtk_u32 bPkts = 0; + mtk_u32 bCsCount = 0; + mtk_u32 bBm = 1; + mtk_u32 bOffset = 0; + mtk_u32 bRepeat = 0; + int ret; + struct mtk_xhci_ep_ctx *temp_ep_ctx; + int td_size; + int mframe_idx, frame_idx; + int bw_cost; + int cur_bw, best_bw, best_bw_idx,repeat, max_repeat, best_bw_repeat; + int cur_offset, cs_mframe; + int break_out; + int frame_interval; + + printk(KERN_ERR "add_ep parameters, dev_speed %d, is_in %d, isTT %d, ep_type %d, maxp %d, interval %d, burst %d, mult %d, ep 0x%x, ep_ctx 0x%x, sch_ep 0x%x\n", dev_speed, is_in, isTT, ep_type, maxp + , interval, burst, mult, ep, ep_ctx, sch_ep); + if(isTT && ep_type == USB_EP_INT && ((dev_speed == USB_SPEED_LOW) || (dev_speed == USB_SPEED_FULL))){ + frame_interval = interval >> 3; + for(frame_idx=0; frame_idx>3; + for(frame_idx=0; frame_idx 0 && cur_bw < best_bw){ + best_bw_idx = cur_offset; + best_bw = cur_bw; + if(cur_bw == td_size || cur_bw < (HS_BW_BOUND>>1)){ + break_out = 1; + break; + } + } + } + } + if(best_bw_idx == -1){ + return SCH_FAIL; + } + else{ + bOffset = best_bw_idx; + bPkts = 1; + bCsCount = (maxp + (188 - 1)) / 188; + if(is_in){ + cs_mframe = bOffset%8 + 2 + bCsCount; + if (cs_mframe <= 6) + bCsCount += 2; + else if (cs_mframe == 7) + bCsCount++; + } + bw_cost = 188; + bRepeat = 0; + if(add_sch_ep( dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult + , bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ + return SCH_FAIL; + } + ret = SCH_SUCCESS; + } + } + else if((dev_speed == USB_SPEED_FULL || dev_speed == USB_SPEED_LOW) && ep_type == USB_EP_INT){ + bPkts = 1; + ret = SCH_SUCCESS; + } + else if(dev_speed == USB_SPEED_FULL && ep_type == USB_EP_ISOC){ + bPkts = 1; + ret = SCH_SUCCESS; + } + else if(dev_speed == USB_SPEED_HIGH && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)){ + best_bw = HS_BW_BOUND; + best_bw_idx = -1; + cur_bw = 0; + td_size = maxp*(burst+1); + for(cur_offset = 0; cur_offset 0 && cur_bw < best_bw){ + best_bw_idx = cur_offset; + best_bw = cur_bw; + if(cur_bw == td_size || cur_bw < (HS_BW_BOUND>>1)){ + break; + } + } + } + if(best_bw_idx == -1){ + return SCH_FAIL; + } + else{ + bOffset = best_bw_idx; + bPkts = burst + 1; + bCsCount = 0; + bw_cost = td_size; + bRepeat = 0; + if(add_sch_ep(dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult + , bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ + return SCH_FAIL; + } + ret = SCH_SUCCESS; + } + } + else if(dev_speed == USB_SPEED_SUPER && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)){ + best_bw = SS_BW_BOUND; + best_bw_idx = -1; + cur_bw = 0; + td_size = maxp * (mult+1) * (burst+1); + if(mult == 0){ + max_repeat = 0; + } + else{ + max_repeat = (interval-1)/(mult+1); + } + break_out = 0; + for(frame_idx = 0; (frame_idx < interval) && !break_out; frame_idx++){ + for(repeat = max_repeat; repeat >= 0; repeat--){ + cur_bw = count_ss_bw(is_in, ep_type, maxp, interval, burst, mult, frame_idx + , repeat, td_size); + printk(KERN_ERR "count_ss_bw, frame_idx %d, repeat %d, td_size %d, result bw %d\n" + , frame_idx, repeat, td_size, cur_bw); + if(cur_bw > 0 && cur_bw < best_bw){ + best_bw_idx = frame_idx; + best_bw_repeat = repeat; + best_bw = cur_bw; + if(cur_bw <= td_size || cur_bw < (HS_BW_BOUND>>1)){ + break_out = 1; + break; + } + } + } + } + printk(KERN_ERR "final best idx %d, best repeat %d\n", best_bw_idx, best_bw_repeat); + if(best_bw_idx == -1){ + return SCH_FAIL; + } + else{ + bOffset = best_bw_idx; + bCsCount = 0; + bRepeat = best_bw_repeat; + if(bRepeat == 0){ + bw_cost = (burst+1)*(mult+1)*maxp; + bPkts = (burst+1)*(mult+1); + } + else{ + bw_cost = (burst+1)*maxp; + bPkts = (burst+1); + } + if(add_sch_ep(dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult + , bOffset, bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL){ + return SCH_FAIL; + } + ret = SCH_SUCCESS; + } + } + else{ + bPkts = 1; + ret = SCH_SUCCESS; + } + if(ret == SCH_SUCCESS){ + temp_ep_ctx = (struct mtk_xhci_ep_ctx *)ep_ctx; + temp_ep_ctx->reserved[0] |= (BPKTS(bPkts) | BCSCOUNT(bCsCount) | BBM(bBm)); + temp_ep_ctx->reserved[1] |= (BOFFSET(bOffset) | BREPEAT(bRepeat)); + + printk(KERN_DEBUG "[DBG] BPKTS: %x, BCSCOUNT: %x, BBM: %x\n", bPkts, bCsCount, bBm); + printk(KERN_DEBUG "[DBG] BOFFSET: %x, BREPEAT: %x\n", bOffset, bRepeat); + return SCH_SUCCESS; + } + else{ + return SCH_FAIL; + } +} -- cgit v1.2.3