📄 fmc.c
字号:
// g_n_lb_this_xfer - specifies the total number of logical blocks to move
// for this transfer per the protocol
// _lun_data(lun, max_lb_per_split) - specifies the maximum number of logical blocks that the
// drive can handle in a single command
// _lun_data(lun, max_lb_per_burst) - specifies the maximum number of logical blocks that the
// drive can deliver before generating an interrupt
// g_fmc_begin_xfer_callback - specifies the callback function to begin a xfer
// g_fmc_end_xfer_callback - specifies the callback function to end a xfer
// g_fmc_begin_split_callback - specifies the callback function to begin a split;
// i.e., issue the command
// g_fmc_end_split_callback - specifies the callback function to end a split;
// i.e., check for error
// g_fmc_begin_burst_callback - specifies the callback function to begin a burst;
// i.e., check drive ready
// g_fmc_end_burst_callback - specifies the callback function to end a burst;
// i.e., check for error
//
// This is a FUNCTION, not a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
// oddly enough, moving these to xdata a tiny smidge is faster
// than manipulating them on the stack...
xdata t_udw32 n_lb_this_burst;
xdata t_udw32 n_bytes_this_burst;
xdata uint32 tmp;
t_result fmc_transfer() reentrant
{
// profile:
// ms reads: 76msec avg to 230msec max per 64Kbytes
// ms writes: 145msec to 150msec per 64Kbytes
//if ((g_bot_xfer_dir == k_dir_read)&&
// (g_bot_data_len.u32 > 0xE000)){_profile_on(7);}
TRACE0(29, fmc, 1, "fmc_transfer()");
// do this to get kbm_sync_abort delivered if there is traffic on the control pipe
_isr_bind_dma_owner(g_tid, kbm_sync_none);
// begin the xfer
//_profile_on(4);
g_fmc_rslt = (*g_fmc_begin_xfer_callback)();
//_profile_off(4);
if (k_success != g_fmc_rslt)
goto EXIT;
// need to disable auto transfer?
if (!(g_fmc_options & kbm_fmc_disable_auto_xfer))
{
// enable auto transfer - start receiving data packets
_mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_auto_trans);
TRACE0(30, fmc, 0, "auto-transfer bit on");
}
//------------------------------------------------------------------------------
// moved from inside the burst loop to improve speed of MS transfers
//------------------------------------------------------------------------------
// enable the block transfer hardware
if (sie_is_high_speed())
{
TRACE0(31, fmc, 0, "HS mode set-->kbm_fmc_ctl_512_byte_pkt");
_mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
}
else
{
TRACE0(32, fmc, 0, "FS mode clr-->kbm_fmc_ctl_512_byte_pkt");
_mcu_register_clr_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
}
// check to see if we need to force the 512 byte xfer irrespective of the speed
if ((g_fmc_options & kbm_fmc_xfer_512_byte_pkt))
{
TRACE0(33, fmc, 0, "option forced set-->kbm_fmc_ctl_512_byte_pkt");
_mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_512_byte_pkt);
}
//------------------------------------------------------------------------------
// process each split in the transaction
//while (g_n_lb_this_xfer.u32)
while (!_u32_equ_0(g_n_lb_this_xfer))
{
_thread_clr_sync(kbm_sync_fmc_irq);
// determine the number of logical blocks for this split
tmp = _lun_data(max_lb_per_split);
if (g_n_lb_this_xfer.u32 > tmp)
{
// split
TRACE0(34, fmc, 0, "fmc_transfer() - multiple splits");
g_n_lb_this_split.u32 = tmp;
}
else
{
// not split, or final split
TRACE0(35, fmc, 0, "fmc_transfer() - single split");
g_n_lb_this_split.u32 = g_n_lb_this_xfer.u32;
}
// begin the split
TRACE2(36, fmc, 0, "n_lb_this_split: %04x%04x" , _hw(g_n_lb_this_split.u32), _lw(g_n_lb_this_split.u32));
//_profile_on(5);
g_fmc_rslt = (*g_fmc_begin_split_callback)();
//_profile_off(5);
if (k_success != g_fmc_rslt)
goto EXIT;
// process each burst in the split
//while (g_n_lb_this_split.u32)
while (!_u32_equ_0(g_n_lb_this_split))
{
// determine the number of logical blocks in this burst
tmp = _lun_data(max_lb_per_burst);
if (g_n_lb_this_split.u32 > tmp)
{
// multi-burst
TRACE0(37, fmc, 0, "fmc_transfer() - multiple bursts");
n_lb_this_burst.u32 = tmp;
}
else
{
// single burst, or final burst
TRACE0(38, fmc, 0, "fmc_transfer() - single burst");
n_lb_this_burst.u32 = g_n_lb_this_split.u32;
}
// determine the number of bytes in this burst
TRACE2(39, fmc, 0, "n_lb_this_burst: %04x%04x", _hw(n_lb_this_burst.u32), _lw(n_lb_this_burst.u32));
#if 1
n_bytes_this_burst.u32 = n_lb_this_burst.u32 * 512L;
#else
// tried to hand multiply by a constant - didnt work right - needs work
n_bytes_this_burst.u8.hi = n_lb_this_burst.u8.lh << 1;
n_bytes_this_burst.u8.lh = n_lb_this_burst.u8.hl << 1;
n_bytes_this_burst.u8.hl = n_lb_this_burst.u8.lo << 1;
n_bytes_this_burst.u8.lo = 0;
#endif
// begin the burst
//_profile_on(6);
g_fmc_rslt = (*g_fmc_begin_burst_callback)();
//_profile_off(6);
if (k_success != g_fmc_rslt)
goto EXIT;
// clear, and unmask, the block xfer interrupt
//irq_control(k_irq_blk_xfer_complete, kbm_irqctl_clear |kbm_irqctl_unmask);
_mcu_register_wr(x_isr0, kbm_isr0_blk_xfer_complete);
// AAA: do not take the interrupt at end of transfer and watch for a synchronizer.
// instead poll for the bit and eliminate the isr entry/exit overhead.
//_mcu_register_clr_bits(x_imr0, kbm_isr0_blk_xfer_complete);
// write the count registers
_mcu_register_wr(x_fmc_cnt3, n_bytes_this_burst.u8.hi);
_mcu_register_wr(x_fmc_cnt2, n_bytes_this_burst.u8.lh);
_mcu_register_wr(x_fmc_cnt1, n_bytes_this_burst.u8.hl);
_mcu_register_wr(x_fmc_cnt0, n_bytes_this_burst.u8.lo);
TRACE4(40, fmc, 0, "fmc_cnt#: %02x%02x%02x%02x", x_fmc_cnt3, x_fmc_cnt2, x_fmc_cnt1, x_fmc_cnt0);
// prime the loop to "resume" transfer, w/o calling split/burst/xfer mechanisms
// to allow luns to fix and/or correct errors in mid transfer, then to continue
// data xfer.
g_fmc_rslt = k_resume;
while (g_fmc_rslt == k_resume)
{
_mcu_register_set_bits(x_fmc_ctl, kbm_fmc_ctl_blk_xfer_en);
TRACE0(41, fmc, 0, "fmdu activated");
// call a xfer-in-progress callback?
//_profile_on(5);
g_fmc_rslt = (*g_fmc_intra_burst_callback)();
//_profile_off(5);
if (k_success != g_fmc_rslt)
goto EXIT;
// !!! possible performance optimization is to make these fctns inline...
// wait for the end of the burst
if (g_fmc_options & kbm_fmc_end_burst_on_count_down)
{
// wait for the count to decrement to zero
g_fmc_rslt = fmc_wait_count_down_with_timeout(g_fmc_timeout);
}
else
{
t_sync sync;
// wait for the block transfer irq
// unrolled: g_fmc_rslt = fmc_wait_blk_irq_with_timeout(g_fmc_timeout);
// poll for bit instead of taking irq and waiting synch.
//_profile_on(7);
//trace0(0, fmc, 1, "fmc_wait_blk_irq_with_timeout()");
thread_set_timer(g_fmc_timeout);
do
{
sync = thread_got_sync(kbm_sync_abort |kbm_sync_usbrst |kbm_sync_timer|kbm_sync_fmc_irq);
_thread_clr_sync(sync);
if (sync & kbm_sync_usbrst)
{
TRACE0(42, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_usbrst");
g_fmc_rslt = k_usbreset;
break;
}
if (sync & kbm_sync_abort)
{
TRACE0(43, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_abort");
g_fmc_rslt = k_aborted;
break;
}
if (sync & kbm_sync_timer)
{
TRACE0(44, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: timeout awaiting irq");
g_fmc_rslt = k_timeout;
break;
}
if (sync & kbm_sync_fmc_irq)
{
TRACE0(45, fmc, 1, "optimized fmc_wait_blk_irq_with_timeout() - error: kbm_sync_fmc_irq") ;
// set to success, since we don't know the cause of the error yet... the specific end-burst
// function should determine the actual status fot eh fmc xfer
g_fmc_rslt = k_success;
break;
}
// AAA: added this to poll instead of taking the interrupt
// cds: added isr bit fmc_irq to break out of loop for fmc error (ecc or otherwise) detection
} while (!(_mcu_register_rd(x_isr0) & (kbm_isr0_blk_xfer_complete|kbm_isr0_fmc_irq) ));
//_profile_off(7);
}
if (k_success != g_fmc_rslt)
{
goto EXIT;
}
// end the burst
//_profile_on(6);
g_fmc_rslt = (*g_fmc_end_burst_callback)();
//_profile_off(6);
if (k_resume == g_fmc_rslt)
{
TRACE0(46, fmc, 0, "resuming fmc transfer");
continue;
}
else
if (k_success != g_fmc_rslt)
goto EXIT;
}
// update start block for next split
g_start_lb_this_xfer.u32 += n_lb_this_burst.u32;
// decrement the number of logical blocks remaining in the split
g_n_lb_this_split.u32 -= n_lb_this_burst.u32;
// decrement the number of logical blocks remaining in the transfer
g_n_lb_this_xfer.u32 -= n_lb_this_burst.u32;
// track the mscbot byte residue
_mscbot_decr_residue(n_bytes_this_burst.u32);
}
// end the split
//_profile_on(5);
g_fmc_rslt = (*g_fmc_end_split_callback)();
//_profile_off(5);
if (k_success != g_fmc_rslt)
goto EXIT;
}
EXIT:
// check for an error
if (k_success != g_fmc_rslt)
fmc_abort_transfer();
else
_lun_data(sensep) = &sense_none;
// end the xfer
// ??? need to get the returned result? can end_xfer fail the xfer?
//_profile_on(4);
(*g_fmc_end_xfer_callback)();
//_profile_off(4);
//_profile_off(7);
// exit, stage left
return g_fmc_rslt;
}
//---eof------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -