📄 patch_doc.txt
字号:
Date: Thu, 09 Jun 2005 10:52:08 +0300
From: Jukka Santala <donwulff_at_nic.fi>
To: kernel-discuss_at_handhelds.org
Subject: [Kernel-discuss] mmc_samsung.c fixes to MMC hangs/performance
I have written a couple of fixes for the s3c2410 MMC drivers. I only
have access to iPAQ h5550 and Transcend 45x 256MB SD card, however, so I
cannot test whether the fixes work with all combinations. If people with
different configurations could give it a spin hopefully we can get this
into the Handhelds kernel soon. It's written against
handhelds-pxa-2.4.19-rmk6-pxa1-hh37.6-r0 (Familiar 8.2) but should apply
against any reasonably recent Handhelds kernel.
There are three fixes in the patch:
1) On ARM architechture, pending IRQ flags must always be reset, or they
will keep being sent back for processing. The current driver doesn't
reset the pending IRQ when getting "ignoring mmc irq with null request"
error. This causes the device to frequently go into near endless loop
processing the same empty IRQ. Since interrupts are disabled during the
interrupt service routine, we can reset the interrupt flags at the
beginning.
2) Transcend 45x 256MB SD card specifies TAAC 0x8f, that translates to
80ms. The Samsung datasheets state "SDI data/busy timer register has
16-bit counter. In caise of 25MHz operation, the countable maximum is
2.6ms (40ns * 0x10000). But, some cards have very long access time
(TAAC), their TAAC are up to 100ms. In this case the SDI generates data
timeout error state." The timeout error is not currently handled,
causing the IO operation to hang. Unfortunately the chart provided in
the datasheet doesn't make much sense, but the concept is simple: If the
read access times out, temporarily reduce clock to 600kHz and try again.
This patch does just that, no matter how ugly it is.
3) Since the two fixes remove the two hangs I've had with the driver,
I've changed it to use the clock-speed specified by the card directly.
This works fine for me, but is the main thing that needs testing. If you
have problems with the patch, check out what /proc/bus/mmc/device says.
If it works, it should lead to small performance improvements even for
people who haven't experienced hangs before. Bit suspicious about why
the clock-speed is hardcoded, currently in two places, though.
There's still plenty of errors and warnings coming out of the MMC
driver, but at least with the above changes it works (for me) with good
performance and stability.
Patch attached, unless attachments are disabled.
-Donwulff
diff -r -u kernel.org/drivers/mmc/mmc_protocol.c kernel/drivers/mmc/mmc_protocol.c
--- kernel.org/drivers/mmc/mmc_protocol.c 2004-08-21 21:14:24.000000000 +0300
+++ kernel/drivers/mmc/mmc_protocol.c 2005-06-09 09:51:01.000000000 +0300
@@ -65,10 +65,12 @@
/* Fix the clock rate */
rate = mmc_tran_speed(dev->slot[slot].csd.tran_speed);
MMC_DEBUG(2,"==> mmc_configure_card (rate= %d) ",rate);
+ /* Trust the value reported by card
if ( rate < MMC_CLOCK_SLOW )
rate = MMC_CLOCK_SLOW;
if ( rate > MMC_CLOCK_FAST )
rate = MMC_CLOCK_FAST;
+ */
dev->sdrive->set_clock(rate);
diff -r -u kernel.org/drivers/mmc/mmc_samsung.c kernel/drivers/mmc/mmc_samsung.c
--- kernel.org/drivers/mmc/mmc_samsung.c 2004-06-23 02:12:06.000000000 +0300
+++ kernel/drivers/mmc/mmc_samsung.c 2005-06-09 10:26:11.000000000 +0300
@@ -317,10 +317,12 @@
int prescaler = 0;
/* Does not seem to work consistently if clock rate is above 10000000 */
+ /* Experimental - trust the value reported by card itself
if ( 10000000 < rate )
{
rate = 10000000;
}
+ */
prescaler = (2*PCLK)/(rate) - 1;
retval = mmc_s3c_stop_clock();
if ( retval ) return retval;
@@ -689,6 +691,7 @@
static void mmc_s3c_send_command (struct mmc_request * request)
{
int retval;
+ int clock;
/*
MMC_DEBUG(2," rINTMSK 0x%08X
rINTMOD 0x%08X
@@ -718,7 +721,16 @@
else {
retval = mmc_s3c_exec_command(request);
MMC_DEBUG(2," retval 0x%08X ",retval);
-
+ if(retval == MMC_ERROR_TIMEOUT) {
+ MMC_DEBUG(2," timed out, trying again at 600kHz");
+ request->result = MMC_NO_RESPONSE;
+ clock = g_s3c_mmc_data.clock; /* Save value */
+ mmc_s3c_adjust_clock(600000);
+ retval = mmc_s3c_exec_command(request);
+ MMC_DEBUG(2," retval 0x%08X ",retval);
+ mmc_s3c_adjust_clock(clock);
+ }
+
#if 0
if ( retval) {
// g_s3c_statistics.mmc_error++;
@@ -1165,7 +1177,9 @@
}
/* It is impossible to get both response and data */
if ( sd->request->nob ) {
- msk_reg = S3C_RX_FIFO_LAST_DATA_INT_ON | S3C_RX_FIFO_FULL_INT_ON;
+ msk_reg = S3C_RX_FIFO_LAST_DATA_INT_ON | S3C_RX_FIFO_FULL_INT_ON
+ |S3C_DATA_TIMEOUT_INT_ON;
+
MMC_DEBUG(2,": read SDIIMSK mask=0x%08x",rSDIIMSK);
// mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT);
// mmc_s3c_start_clock(); /* redundancy ? */
@@ -1253,6 +1267,11 @@
MMC_DEBUG(2, " rSDIIMSK 0x%08X cmd 0x%08X data 0x%08X fifo 0x%08X",rSDIIMSK,status[0],status[1],status[2]);
MMC_DEBUG(2, " rSDICON 0x%08X CCON 0x%08X DCONdata 0x%08X ",rSDICON,rSDICCON,rSDIDCON);
+ /* Clear the interrupt. Must write a one to the src pending register
+ then the interrupt pending register. */
+ h5400_asic_write_register (H5400_ASIC_IC_SRCPND, _H5400_ASIC_IC_INT_SD);
+ h5400_asic_write_register (H5400_ASIC_IC_INTPND, _H5400_ASIC_IC_INT_SD);
+
/* this can happen if there is an old interrupt hanging around when the irq is registered */
if (sd->request == NULL) {
printk ("ignoring mmc irq with null request\n");
@@ -1272,11 +1291,6 @@
mmc_s3c_split_status( sd, status, 0 );
- /* Clear the interrupt. Must write a one to the src pending register
- then the interrupt pending register. */
- h5400_asic_write_register (H5400_ASIC_IC_SRCPND, _H5400_ASIC_IC_INT_SD);
- h5400_asic_write_register (H5400_ASIC_IC_INTPND, _H5400_ASIC_IC_INT_SD);
-
/* Enable the irq */
enable_irq( irq );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -