📄 pehci.c
字号:
u32 skipmap = 0;
u32 newschedule = 0;
u32 buffstatus = 0;
u32 schedulemap = 0;
#ifndef CONFIG_ISO_SUPPORT
u32 lasttd = 1;
#endif
u32 lastmap = 0;
struct urb *urb = 0;
urb_priv_t *urbpriv = 0;
int length = 0;
u32 ormask = 0,andmask = 0;
u32 intormask = 0;
td_ptd_map_t *td_ptd_map;
td_ptd_map_buff_t *ptd_map_buff;
struct isp1761_mem_addr *mem_addr = 0;
pehci_entry("++ %s: Entered\n",__FUNCTION__);
pehci_print("Buffer type %d\n", bufftype);
/*need to hold this lock if another interrupt is comming
for previously scheduled transfer, while scheduling new tds
*/
spin_lock(&hcd_data_lock);
ptd_map_buff = &td_ptd_map_buff[bufftype];
qha = &allqha;
switch(bufftype){
case TD_PTD_BUFF_TYPE_ATL:
skipmap = isp1761_reg_read32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
rmb();
ormask = isp1761_reg_read32(hcd->dev, hcd->regs.atl_irq_mask_or, ormask);
andmask = isp1761_reg_read32(hcd->dev, hcd->regs.atl_irq_mask_and, andmask);
break;
case TD_PTD_BUFF_TYPE_INTL:
skipmap = isp1761_reg_read32(hcd->dev, hcd->regs.inttdskipmap, skipmap);
/*read the interrupt mask registers*/
intormask = isp1761_reg_read32(hcd->dev, hcd->regs.int_irq_mask_or,intormask);
break;
default:
err("Never Error: Bogus type of bufer\n");
return;
}
buffstatus = isp1761_reg_read32(hcd->dev,hcd->regs.buffer_status,buffstatus);
/*td headers need attention*/
schedulemap = donemap;
while(schedulemap){
index = schedulemap & mask;
schedulemap &= ~mask;
mask <<= 1;
if(!index){
location++;
continue;
}
td_ptd_map = &ptd_map_buff->map_list[location];
/* can happen if donemap comes after
removal of the urb and associated tds
*/
if((td_ptd_map->state == TD_PTD_NEW) ||
(td_ptd_map->state == TD_PTD_REMOVE)){
qh = td_ptd_map->qh;
pehci_check("should not come here, map %x,pending map %x\n", td_ptd_map->ptd_bitmap,
ptd_map_buff->pending_ptd_bitmap);
pehci_check("buffer type %s\n", (bufftype == 0)?"ATL":"INTL");
donemap &= ~td_ptd_map->ptd_bitmap;
/*clear the pending map*/
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
/*no endpoint at this location*/
if(!(td_ptd_map->qh)){
err("queue head can not be null here\n");
/*move to the next location*/
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
/*current endpoint*/
qh = td_ptd_map->qh;
if(!(skipmap & td_ptd_map->ptd_bitmap)){
/*should not happen, if happening, then*/
pehci_check("buffertype %d,td_ptd_map %x,skipnap %x\n",
bufftype, td_ptd_map->ptd_bitmap,skipmap);
lastmap = td_ptd_map->ptd_bitmap;
donemap &= ~td_ptd_map->ptd_bitmap;
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
/*if we processed all the tds in ths transfer*/
if(td_ptd_map->lasttd){
err("should not show map %x,qtd %p\n", td_ptd_map->ptd_bitmap,td_ptd_map->qtd);
/*this can happen in case the transfer is not being
* procesed by the host , tho the transfer is there
* */
qh->hw_current = cpu_to_le32(td_ptd_map->qtd);
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
/*if we have ptd that is going for reload*/
if((td_ptd_map->qtd) && (td_ptd_map->state & TD_PTD_RELOAD)){
warn("%s: reload td\n",__FUNCTION__);
td_ptd_map->state &= ~TD_PTD_RELOAD;
qtd = td_ptd_map->qtd;
goto loadtd;
}
/* qh is there but no qtd so it means fresh transfer*/
if((td_ptd_map->qh) && !(td_ptd_map->qtd)){
if(list_empty(&qh->qtd_list)){
/*should not hapen again, as it comes here
when it has td in its map
*/
pehci_check("must not come here any more, td map %x\n",td_ptd_map->ptd_bitmap);
/*this location is idle and can be free next time if
no new transfers are comming for this*/
donemap &= ~td_ptd_map->ptd_bitmap;
td_ptd_map->state |= TD_PTD_IDLE;
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
qtd_list = &qh->qtd_list;
qtd = td_ptd_map->qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
/*got the td, now goto reload*/
goto loadtd;
}
/*if there is already one qtd there in the transfer*/
if(td_ptd_map->qtd){
/*new schedule*/
qtd = td_ptd_map->qtd;
}
loadtd:
/*should not happen*/
if(!qtd){
err("this piece of code should not be executed\n");
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
location++;
continue;
}
ptd_map_buff->active_ptds++;
/*clear the pending map here*/
ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
/*if this td is the last one*/
if(qtd->state & QTD_STATE_LAST){
/*no qtd anymore*/
qh->hw_current = cpu_to_le32(0);
/*else update the hw_next of qh to the next td*/
}else{
qh->hw_current = qtd->hw_next;
}
if(location != qh->qtd_ptd_index){
err("Never Error: Endpoint header location and scheduling information are not same\n");
}
/*next location*/
location++;
/*found new transfer*/
newschedule = 1;
/*take the urb*/
urb = qtd->urb;
/*sometimes we miss due to skipmap
so to make sure that we dont put again the
same stuff
*/
if(!(qtd->state & QTD_STATE_NEW))
{
err("Never Error: We should not put the same stuff\n");
continue;
}
urbpriv = (urb_priv_t*)urb->hcpriv;
urbpriv->timeout = 0;
/*no more new*/
qtd->state &= ~QTD_STATE_NEW;
qtd->state |= QTD_STATE_SCHEDULED;
/*NEW, now need to get the memory for this transfer*/
length = qtd->length;
mem_addr = &qtd->mem_addr;
phci_hcd_mem_alloc(length,mem_addr,0);
if(length && (
(mem_addr->phy_addr == 0 )
|| (mem_addr->virt_addr == 0))){
err("Never Error: Can not allocate memory for the current td,length %d\n",length);
location++;
continue;
}
pehci_check("qtd being scheduled %p, device %d,map %x\n", qtd,urb->dev->devnum,td_ptd_map->ptd_bitmap);
memset(qha, 0, sizeof(isp1761_qha));
/*convert qtd to qha*/
phci_hcd_qha_from_qtd(hcd,qtd,qtd->urb, (void *)qha,
td_ptd_map->ptd_ram_data_addr,
qh
/*td_ptd_map->datatoggle*/);
if(qh->type == TD_PTD_BUFF_TYPE_INTL){
phci_hcd_qhint_schedule(hcd, qh,qtd,(isp1761_qhint *)qha,qtd->urb);
}
length = PTD_XFERRED_LENGTH(qha->td_info1 >> 3);
if(length > HC_ATL_PL_SIZE){
err("Never Error: Bogus length,length %d(max %d)\n",(int)qtd->length, HC_ATL_PL_SIZE);
}
/*write qha into the header of the host controller*/
isp1761_mem_write(hcd->dev, td_ptd_map->ptd_header_addr,0,(u32 *)(qha),PHCI_QHA_LENGTH,0);
/*if this is SETUP/OUT token , then need to write into the buffer*/
/*length should be valid*/
if(qtd->length && ( length <= HC_ATL_PL_SIZE))
switch(PTD_PID(qha->td_info2)){
case OUT_PID:
case SETUP_PID:
isp1761_mem_write(hcd->dev,(u32)mem_addr->phy_addr,0,(void*)(le32_to_cpu(qtd->hw_buf[0])),length,0);
break;
}
/*unskip the tds at this location*/
switch(bufftype){
case TD_PTD_BUFF_TYPE_ATL:
skipmap &= ~td_ptd_map->ptd_bitmap;
lastmap = td_ptd_map->ptd_bitmap;
/*try to reduce the interrupts*/
ormask |= td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.atl_irq_mask_or, ormask);
break;
case TD_PTD_BUFF_TYPE_INTL:
skipmap &= ~td_ptd_map->ptd_bitmap;
lastmap = td_ptd_map->ptd_bitmap;
intormask |= td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.int_irq_mask_or,intormask);
break;
case TD_PTD_BUFF_TYPE_ISTL:
#ifdef CONFIG_ISO_SUPPORT
iso_dbg(ISO_DBG_INFO,"Never Error: Should not come here\n");
#else
skipmap &= ~td_ptd_map->ptd_bitmap;
isp1761_reg_write32(hcd->dev, hcd->regs.isotdskipmap, skipmap);
isp1761_reg_write32(hcd->dev, hcd->regs.isotdlastmap,lasttd/*td_ptd_map->ptd_bitmap*/);
#endif /* CONFIG_ISO_SUPPORT */
break;
}
}
/*if any new schedule, enable the atl buffer*/
if(newschedule){
switch(bufftype){
case TD_PTD_BUFF_TYPE_ATL:
isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, buffstatus | ATL_BUFFER);
/*i am comming here to only those tds that has to be scheduled*/
/*so skip map must be in place*/
if(skipmap & donemap){
pehci_check("must be both ones compliment of each other\n");
pehci_check("problem, skipmap %x, donemap %x,\n",skipmap,donemap);
}
skipmap &= ~donemap;
isp1761_reg_write32(hcd->dev, hcd->regs.atltdskipmap, skipmap);
break;
case TD_PTD_BUFF_TYPE_INTL:
isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, buffstatus | INT_BUFFER);
skipmap &= ~donemap;
isp1761_reg_write32(hcd->dev, hcd->regs.inttdskipmap, skipmap);
break;
case TD_PTD_BUFF_TYPE_ISTL:
#ifndef CONFIG_ISO_SUPPORT
isp1761_reg_write32(hcd->dev, hcd->regs.buffer_status, buffstatus | ISO_BUFFER);
#endif
break;
}
}
spin_unlock(&hcd_data_lock);
pehci_entry("-- %s: Exit\n",__FUNCTION__);
}
static void
pehci_hcd_qtd_schedule(phci_hcd *hcd,struct ehci_qtd *qtd,
struct ehci_qh *qh,td_ptd_map_t *td_ptd_map)
{
struct urb *urb;
urb_priv_t *urbpriv = 0;
u32 length;
struct isp1761_mem_addr *mem_addr = 0;
struct _isp1761_qha *qha, qhtemp;
pehci_entry("++ %s: Entered\n",__FUNCTION__);
/*redundant*/
qha = &qhtemp;
/*if this td is the last one*/
if(qtd->state & QTD_STATE_LAST){
/*no qtd anymore*/
qh->hw_current = cpu_to_le32(0);
/*else update the hw_next of qh to the next td*/
}else{
qh->hw_current = qtd->hw_next;
}
urb = qtd->urb;
urbpriv = (urb_priv_t*)urb->hcpriv;
urbpriv->timeout = 0;
/*NEW, now need to get the memory for this transfer*/
length = qtd->length;
mem_addr = &qtd->mem_addr;
phci_hcd_mem_alloc(length,mem_addr,0);
if(length && (
(mem_addr->phy_addr == 0 )
|| (mem_addr->virt_addr == 0))){
err("Never Error: Cannot allocate memory for the current td,length %d\n",length);
return;
}
pehci_check("newqtd being scheduled, device: %d,map: %x\n", urb->dev->devnum,td_ptd_map->ptd_bitmap);
memset(qha, 0, sizeof(isp1761_qha));
/*convert qtd to qha*/
phci_hcd_qha_from_qtd(hcd,qtd,qtd->urb, (void *)qha,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -