Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
019c21a8
Commit
019c21a8
authored
Sep 29, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk/linux-2.6-mmc
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
87bd1b54
e2885a51
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
158 additions
and
130 deletions
+158
-130
drivers/mmc/mmc.c
drivers/mmc/mmc.c
+29
-9
drivers/mmc/mmc_block.c
drivers/mmc/mmc_block.c
+10
-7
drivers/mmc/mmci.c
drivers/mmc/mmci.c
+78
-113
drivers/mmc/mmci.h
drivers/mmc/mmci.h
+41
-1
No files found.
drivers/mmc/mmc.c
View file @
019c21a8
...
...
@@ -270,8 +270,7 @@ static inline void mmc_delay(unsigned int ms)
yield
();
mdelay
(
ms
);
}
else
{
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
ms
*
HZ
/
1000
);
msleep_interruptible
(
ms
);
}
}
...
...
@@ -450,12 +449,27 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
return
card
;
}
/*
* Tell attached cards to go to IDLE state
*/
static
void
mmc_idle_cards
(
struct
mmc_host
*
host
)
{
struct
mmc_command
cmd
;
cmd
.
opcode
=
MMC_GO_IDLE_STATE
;
cmd
.
arg
=
0
;
cmd
.
flags
=
MMC_RSP_NONE
;
mmc_wait_for_cmd
(
host
,
&
cmd
,
0
);
mmc_delay
(
1
);
}
/*
* Apply power to the MMC stack.
*/
static
void
mmc_power_up
(
struct
mmc_host
*
host
)
{
struct
mmc_command
cmd
;
int
bit
=
fls
(
host
->
ocr_avail
)
-
1
;
host
->
ios
.
vdd
=
bit
;
...
...
@@ -470,12 +484,6 @@ static void mmc_power_up(struct mmc_host *host)
host
->
ops
->
set_ios
(
host
,
&
host
->
ios
);
mmc_delay
(
2
);
cmd
.
opcode
=
MMC_GO_IDLE_STATE
;
cmd
.
arg
=
0
;
cmd
.
flags
=
MMC_RSP_NONE
;
mmc_wait_for_cmd
(
host
,
&
cmd
,
0
);
}
static
void
mmc_power_off
(
struct
mmc_host
*
host
)
...
...
@@ -505,6 +513,8 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
break
;
err
=
MMC_ERR_TIMEOUT
;
mmc_delay
(
10
);
}
if
(
rocr
)
...
...
@@ -647,12 +657,22 @@ static void mmc_setup(struct mmc_host *host)
u32
ocr
;
mmc_power_up
(
host
);
mmc_idle_cards
(
host
);
err
=
mmc_send_op_cond
(
host
,
0
,
&
ocr
);
if
(
err
!=
MMC_ERR_NONE
)
return
;
host
->
ocr
=
mmc_select_voltage
(
host
,
ocr
);
/*
* Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle
* state. We wait 1ms to give cards time to
* respond.
*/
if
(
host
->
ocr
)
mmc_idle_cards
(
host
);
}
else
{
host
->
ios
.
bus_mode
=
MMC_BUSMODE_OPENDRAIN
;
host
->
ios
.
clock
=
host
->
f_min
;
...
...
drivers/mmc/mmc_block.c
View file @
019c21a8
...
...
@@ -42,7 +42,7 @@
*/
#define MMC_SHIFT 3
static
int
m
mc_m
ajor
;
static
int
major
;
/*
* There is one mmc_blk_data per slot.
...
...
@@ -323,7 +323,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md
->
queue
.
issue_fn
=
mmc_blk_issue_rq
;
md
->
queue
.
data
=
md
;
md
->
disk
->
major
=
m
mc_m
ajor
;
md
->
disk
->
major
=
major
;
md
->
disk
->
first_minor
=
devidx
<<
MMC_SHIFT
;
md
->
disk
->
fops
=
&
mmc_bdops
;
md
->
disk
->
private_data
=
md
;
...
...
@@ -462,14 +462,14 @@ static int __init mmc_blk_init(void)
{
int
res
=
-
ENOMEM
;
res
=
register_blkdev
(
m
mc_m
ajor
,
"mmc"
);
res
=
register_blkdev
(
major
,
"mmc"
);
if
(
res
<
0
)
{
printk
(
KERN_WARNING
"Unable to get major %d for MMC media: %d
\n
"
,
m
mc_m
ajor
,
res
);
major
,
res
);
goto
out
;
}
if
(
m
mc_m
ajor
==
0
)
m
mc_m
ajor
=
res
;
if
(
major
==
0
)
major
=
res
;
devfs_mk_dir
(
"mmc"
);
return
mmc_register_driver
(
&
mmc_driver
);
...
...
@@ -482,7 +482,7 @@ static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver
(
&
mmc_driver
);
devfs_remove
(
"mmc"
);
unregister_blkdev
(
m
mc_m
ajor
,
"mmc"
);
unregister_blkdev
(
major
,
"mmc"
);
}
module_init
(
mmc_blk_init
);
...
...
@@ -490,3 +490,6 @@ module_exit(mmc_blk_exit);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Multimedia Card (MMC) block device driver"
);
module_param
(
major
,
int
,
0444
);
MODULE_PARM_DESC
(
major
,
"specify the major device number for MMC block driver"
);
drivers/mmc/mmci.c
View file @
019c21a8
...
...
@@ -75,10 +75,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
1
<<
data
->
blksz_bits
,
data
->
blocks
,
data
->
flags
);
host
->
data
=
data
;
host
->
offset
=
0
;
host
->
size
=
data
->
blocks
<<
data
->
blksz_bits
;
host
->
data_xfered
=
0
;
mmci_init_sg
(
host
,
data
);
timeout
=
data
->
timeout_clks
+
((
unsigned
long
long
)
data
->
timeout_ns
*
host
->
cclk
)
/
1000000000ULL
;
...
...
@@ -190,160 +191,124 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
}
}
static
int
mmci_pio_read
(
struct
mmci_host
*
host
,
struct
request
*
req
,
u32
status
)
static
int
mmci_pio_read
(
struct
mmci_host
*
host
,
char
*
buffer
,
unsigned
int
remain
)
{
void
*
base
=
host
->
base
;
int
ret
=
0
;
char
*
ptr
=
buffer
;
u32
status
;
do
{
unsigned
long
flags
;
unsigned
int
bio_remain
;
char
*
buffer
;
int
count
=
host
->
size
-
(
readl
(
base
+
MMCIFIFOCNT
)
<<
2
);
/*
* Check for data available.
*/
if
(
!
(
status
&
MCI_RXDATAAVLBL
)
)
if
(
count
>
remain
)
count
=
remain
;
if
(
count
<=
0
)
break
;
/*
* Map the BIO buffer.
*/
buffer
=
bio_kmap_irq
(
req
->
cbio
,
&
flags
);
bio_remain
=
(
req
->
current_nr_sectors
<<
9
)
-
host
->
offset
;
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
do
{
int
count
=
host
->
size
-
(
readl
(
base
+
MMCIFIFOCNT
)
<<
2
)
;
ptr
+=
count
;
remain
-=
count
;
if
(
count
>
bio_remain
)
count
=
bio_remain
;
if
(
remain
==
0
)
break
;
if
(
count
>
0
)
{
ret
=
1
;
readsl
(
base
+
MMCIFIFO
,
buffer
+
host
->
offset
,
count
>>
2
);
host
->
offset
+=
count
;
host
->
size
-=
count
;
bio_remain
-=
count
;
if
(
bio_remain
==
0
)
goto
next_bio
;
}
status
=
readl
(
base
+
MMCISTATUS
);
}
while
(
status
&
MCI_RXDATAAVLBL
);
status
=
readl
(
base
+
MMCISTATUS
)
;
}
while
(
status
&
MCI_RXDATAAVLBL
);
return
ptr
-
buffer
;
}
bio_kunmap_irq
(
buffer
,
&
flags
);
break
;
static
int
mmci_pio_write
(
struct
mmci_host
*
host
,
char
*
buffer
,
unsigned
int
remain
,
u32
status
)
{
void
*
base
=
host
->
base
;
char
*
ptr
=
buffer
;
next_bio:
bio_kunmap_irq
(
buffer
,
&
flags
)
;
do
{
unsigned
int
count
,
maxcnt
;
/*
* Ok, we've completed that BIO, move on to next
* BIO in the chain. Note: this doesn't actually
* complete the BIO!
*/
if
(
!
process_that_request_first
(
req
,
req
->
current_nr_sectors
))
maxcnt
=
status
&
MCI_TXFIFOEMPTY
?
MCI_FIFOSIZE
:
MCI_FIFOHALFSIZE
;
count
=
min
(
remain
,
maxcnt
);
writesl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
ptr
+=
count
;
remain
-=
count
;
if
(
remain
==
0
)
break
;
host
->
offset
=
0
;
status
=
readl
(
base
+
MMCISTATUS
);
}
while
(
1
);
/*
* If we're nearing the end of the read, switch to
* "any data available" mode.
*/
if
(
host
->
size
<
MCI_FIFOSIZE
)
writel
(
MCI_RXDATAAVLBLMASK
,
base
+
MMCIMASK1
);
}
while
(
status
&
MCI_TXFIFOHALFEMPTY
);
return
ret
;
return
ptr
-
buffer
;
}
static
int
mmci_pio_write
(
struct
mmci_host
*
host
,
struct
request
*
req
,
u32
status
)
/*
* PIO data transfer IRQ handler.
*/
static
irqreturn_t
mmci_pio_irq
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
mmci_host
*
host
=
dev_id
;
void
*
base
=
host
->
base
;
int
ret
=
0
;
u32
status
;
status
=
readl
(
base
+
MMCISTATUS
);
DBG
(
host
,
"irq1 %08x
\n
"
,
status
);
do
{
unsigned
long
flags
;
unsigned
int
bio_remai
n
;
unsigned
int
remain
,
le
n
;
char
*
buffer
;
/*
* We only need to test the half-empty flag here - if
* the FIFO is completely empty, then by definition
* it is more than half empty.
* For write, we only need to test the half-empty flag
* here - if the FIFO is completely empty, then by
* definition it is more than half empty.
*
* For read, check for data available.
*/
if
(
!
(
status
&
MCI_TXFIFOHALFEMPTY
))
if
(
!
(
status
&
(
MCI_TXFIFOHALFEMPTY
|
MCI_RXDATAAVLBL
)
))
break
;
/*
* Map the
BIO
buffer.
* Map the
current scatter
buffer.
*/
buffer
=
bio_kmap_irq
(
req
->
cbio
,
&
flags
);
bio_remain
=
(
req
->
current_nr_sectors
<<
9
)
-
host
->
offset
;
do
{
unsigned
int
count
,
maxcnt
;
buffer
=
mmci_kmap_atomic
(
host
,
&
flags
)
+
host
->
sg_off
;
remain
=
host
->
sg_ptr
->
length
-
host
->
sg_off
;
maxcnt
=
status
&
MCI_TXFIFOEMPTY
?
MCI_FIFOSIZE
:
MCI_FIFOHALFSIZE
;
count
=
min
(
bio_remain
,
maxcnt
);
len
=
0
;
if
(
status
&
MCI_RXACTIVE
)
len
=
mmci_pio_read
(
host
,
buffer
,
remain
);
if
(
status
&
MCI_TXACTIVE
)
len
=
mmci_pio_write
(
host
,
buffer
,
remain
,
status
);
writesl
(
base
+
MMCIFIFO
,
buffer
+
host
->
offset
,
count
>>
2
);
host
->
offset
+=
count
;
host
->
size
-=
count
;
bio_remain
-=
count
;
ret
=
1
;
if
(
bio_remain
==
0
)
goto
next_bio
;
/*
* Unmap the buffer.
*/
mmci_kunmap_atomic
(
host
,
&
flags
);
status
=
readl
(
base
+
MMCISTATUS
);
}
while
(
status
&
MCI_TXFIFOHALFEMPTY
);
host
->
sg_off
+=
len
;
host
->
size
-=
len
;
remain
-=
len
;
bio_kunmap_irq
(
buffer
,
&
flags
);
break
;
next_bio:
bio_kunmap_irq
(
buffer
,
&
flags
);
if
(
remain
)
break
;
/*
* Ok, we've completed that BIO, move on to next
* BIO in the chain. Note: this doesn't actually
* complete the BIO!
*/
if
(
!
process_that_request_first
(
req
,
req
->
current_nr_sectors
))
if
(
!
mmci_next_sg
(
host
))
break
;
host
->
offset
=
0
;
status
=
readl
(
base
+
MMCISTATUS
);
}
while
(
1
);
return
ret
;
}
/*
* PIO data transfer IRQ handler.
*/
static
irqreturn_t
mmci_pio_irq
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
mmci_host
*
host
=
dev_id
;
struct
request
*
req
;
void
*
base
=
host
->
base
;
u32
status
;
int
ret
=
0
;
status
=
readl
(
base
+
MMCISTATUS
);
DBG
(
host
,
"irq1 %08x
\n
"
,
status
);
req
=
host
->
data
->
req
;
if
(
status
&
MCI_RXACTIVE
)
ret
=
mmci_pio_read
(
host
,
req
,
status
);
else
if
(
status
&
MCI_TXACTIVE
)
ret
=
mmci_pio_write
(
host
,
req
,
status
);
/*
* If we're nearing the end of the read, switch to
* "any data available" mode.
*/
if
(
status
&
MCI_RXACTIVE
&&
host
->
size
<
MCI_FIFOSIZE
)
writel
(
MCI_RXDATAAVLBLMASK
,
base
+
MMCIMASK1
);
/*
* If we run out of data, disable the data IRQs; this
...
...
@@ -356,7 +321,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
writel
(
readl
(
base
+
MMCIMASK0
)
|
MCI_DATAENDMASK
,
base
+
MMCIMASK0
);
}
return
IRQ_
RETVAL
(
ret
)
;
return
IRQ_
HANDLED
;
}
/*
...
...
drivers/mmc/mmci.h
View file @
019c21a8
...
...
@@ -115,6 +115,8 @@
#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
#define NR_SG 16
struct
clk
;
struct
mmci_host
{
...
...
@@ -137,7 +139,45 @@ struct mmci_host {
struct
timer_list
timer
;
unsigned
int
oldstat
;
struct
scatterlist
sg
[
NR_SG
];
unsigned
int
sg_len
;
/* pio stuff */
unsigned
int
offset
;
struct
scatterlist
*
sg_ptr
;
unsigned
int
sg_off
;
unsigned
int
size
;
};
static
inline
void
mmci_init_sg
(
struct
mmci_host
*
host
,
struct
mmc_data
*
data
)
{
struct
scatterlist
*
sg
=
host
->
sg
;
struct
request
*
req
=
data
->
req
;
/*
* Ideally, we want the higher levels to pass us a scatter list.
*/
host
->
sg_len
=
blk_rq_map_sg
(
req
->
q
,
req
,
sg
);
host
->
sg_ptr
=
sg
;
host
->
sg_off
=
0
;
}
static
inline
int
mmci_next_sg
(
struct
mmci_host
*
host
)
{
host
->
sg_ptr
++
;
host
->
sg_off
=
0
;
return
--
host
->
sg_len
;
}
static
inline
char
*
mmci_kmap_atomic
(
struct
mmci_host
*
host
,
unsigned
long
*
flags
)
{
struct
scatterlist
*
sg
=
host
->
sg_ptr
;
local_irq_save
(
*
flags
);
return
kmap_atomic
(
sg
->
page
,
KM_BIO_SRC_IRQ
)
+
sg
->
offset
;
}
static
inline
void
mmci_kunmap_atomic
(
struct
mmci_host
*
host
,
unsigned
long
*
flags
)
{
kunmap_atomic
(
host
->
sg_ptr
->
page
,
KM_BIO_SRC_IRQ
);
local_irq_restore
(
*
flags
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment