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
nexedi
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