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
3e4d2650
Commit
3e4d2650
authored
Apr 25, 2007
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SPARC64]: Convert SBUS over to generic iommu/strbuf structs.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
66875088
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
132 additions
and
97 deletions
+132
-97
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/sbus.c
+132
-97
No files found.
arch/sparc64/kernel/sbus.c
View file @
3e4d2650
...
@@ -26,17 +26,9 @@
...
@@ -26,17 +26,9 @@
#define MAP_BASE ((u32)0xc0000000)
#define MAP_BASE ((u32)0xc0000000)
struct
sbus_iommu
{
struct
sbus_info
{
spinlock_t
lock
;
struct
iommu
iommu
;
struct
strbuf
strbuf
;
struct
iommu_arena
arena
;
iopte_t
*
page_table
;
unsigned
long
strbuf_regs
;
unsigned
long
iommu_regs
;
unsigned
long
sbus_control_reg
;
volatile
unsigned
long
strbuf_flushflag
;
};
};
/* Offsets from iommu_regs */
/* Offsets from iommu_regs */
...
@@ -52,16 +44,17 @@ struct sbus_iommu {
...
@@ -52,16 +44,17 @@ struct sbus_iommu {
#define IOMMU_DRAM_VALID (1UL << 30UL)
#define IOMMU_DRAM_VALID (1UL << 30UL)
static
void
__iommu_flushall
(
struct
sbus_
iommu
*
iommu
)
static
void
__iommu_flushall
(
struct
iommu
*
iommu
)
{
{
unsigned
long
tag
=
iommu
->
iommu_regs
+
IOMMU_TAGDIAG
;
unsigned
long
tag
;
int
entry
;
int
entry
;
tag
=
iommu
->
iommu_control
+
(
IOMMU_TAGDIAG
-
IOMMU_CONTROL
);
for
(
entry
=
0
;
entry
<
16
;
entry
++
)
{
for
(
entry
=
0
;
entry
<
16
;
entry
++
)
{
upa_writeq
(
0
,
tag
);
upa_writeq
(
0
,
tag
);
tag
+=
8UL
;
tag
+=
8UL
;
}
}
upa_readq
(
iommu
->
sbus_control
_reg
);
upa_readq
(
iommu
->
write_complete
_reg
);
}
}
/* Offsets from strbuf_regs */
/* Offsets from strbuf_regs */
...
@@ -76,15 +69,14 @@ static void __iommu_flushall(struct sbus_iommu *iommu)
...
@@ -76,15 +69,14 @@ static void __iommu_flushall(struct sbus_iommu *iommu)
#define STRBUF_TAG_VALID 0x02UL
#define STRBUF_TAG_VALID 0x02UL
static
void
sbus_strbuf_flush
(
struct
sbus_iommu
*
iommu
,
u32
base
,
unsigned
long
npages
,
int
direction
)
static
void
sbus_strbuf_flush
(
struct
iommu
*
iommu
,
struct
strbuf
*
strbuf
,
u32
base
,
unsigned
long
npages
,
int
direction
)
{
{
unsigned
long
n
;
unsigned
long
n
;
int
limit
;
int
limit
;
n
=
npages
;
n
=
npages
;
while
(
n
--
)
while
(
n
--
)
upa_writeq
(
base
+
(
n
<<
IO_PAGE_SHIFT
),
upa_writeq
(
base
+
(
n
<<
IO_PAGE_SHIFT
),
strbuf
->
strbuf_pflush
);
iommu
->
strbuf_regs
+
STRBUF_PFLUSH
);
/* If the device could not have possibly put dirty data into
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* the streaming cache, no flush-flag synchronization needs
...
@@ -93,15 +85,14 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
...
@@ -93,15 +85,14 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
if
(
direction
==
SBUS_DMA_TODEVICE
)
if
(
direction
==
SBUS_DMA_TODEVICE
)
return
;
return
;
iommu
->
strbuf_flushflag
=
0UL
;
*
(
strbuf
->
strbuf_flushflag
)
=
0UL
;
/* Whoopee cushion! */
/* Whoopee cushion! */
upa_writeq
(
__pa
(
&
iommu
->
strbuf_flushflag
),
upa_writeq
(
strbuf
->
strbuf_flushflag_pa
,
strbuf
->
strbuf_fsync
);
iommu
->
strbuf_regs
+
STRBUF_FSYNC
);
upa_readq
(
iommu
->
write_complete_reg
);
upa_readq
(
iommu
->
sbus_control_reg
);
limit
=
100000
;
limit
=
100000
;
while
(
iommu
->
strbuf_flushflag
==
0UL
)
{
while
(
*
(
strbuf
->
strbuf_flushflag
)
==
0UL
)
{
limit
--
;
limit
--
;
if
(
!
limit
)
if
(
!
limit
)
break
;
break
;
...
@@ -115,7 +106,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
...
@@ -115,7 +106,7 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long
}
}
/* Based largely upon the ppc64 iommu allocator. */
/* Based largely upon the ppc64 iommu allocator. */
static
long
sbus_arena_alloc
(
struct
sbus_
iommu
*
iommu
,
unsigned
long
npages
)
static
long
sbus_arena_alloc
(
struct
iommu
*
iommu
,
unsigned
long
npages
)
{
{
struct
iommu_arena
*
arena
=
&
iommu
->
arena
;
struct
iommu_arena
*
arena
=
&
iommu
->
arena
;
unsigned
long
n
,
i
,
start
,
end
,
limit
;
unsigned
long
n
,
i
,
start
,
end
,
limit
;
...
@@ -164,7 +155,7 @@ static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsig
...
@@ -164,7 +155,7 @@ static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsig
__clear_bit
(
i
,
arena
->
map
);
__clear_bit
(
i
,
arena
->
map
);
}
}
static
void
sbus_iommu_table_init
(
struct
sbus_
iommu
*
iommu
,
unsigned
int
tsbsize
)
static
void
sbus_iommu_table_init
(
struct
iommu
*
iommu
,
unsigned
int
tsbsize
)
{
{
unsigned
long
tsbbase
,
order
,
sz
,
num_tsb_entries
;
unsigned
long
tsbbase
,
order
,
sz
,
num_tsb_entries
;
...
@@ -172,13 +163,14 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
...
@@ -172,13 +163,14 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
/* Setup initial software IOMMU state. */
/* Setup initial software IOMMU state. */
spin_lock_init
(
&
iommu
->
lock
);
spin_lock_init
(
&
iommu
->
lock
);
iommu
->
page_table_map_base
=
MAP_BASE
;
/* Allocate and initialize the free area map. */
/* Allocate and initialize the free area map. */
sz
=
num_tsb_entries
/
8
;
sz
=
num_tsb_entries
/
8
;
sz
=
(
sz
+
7UL
)
&
~
7UL
;
sz
=
(
sz
+
7UL
)
&
~
7UL
;
iommu
->
arena
.
map
=
kzalloc
(
sz
,
GFP_KERNEL
);
iommu
->
arena
.
map
=
kzalloc
(
sz
,
GFP_KERNEL
);
if
(
!
iommu
->
arena
.
map
)
{
if
(
!
iommu
->
arena
.
map
)
{
prom_printf
(
"
PCI
_IOMMU: Error, kmalloc(arena.map) failed.
\n
"
);
prom_printf
(
"
SBUS
_IOMMU: Error, kmalloc(arena.map) failed.
\n
"
);
prom_halt
();
prom_halt
();
}
}
iommu
->
arena
.
limit
=
num_tsb_entries
;
iommu
->
arena
.
limit
=
num_tsb_entries
;
...
@@ -194,7 +186,7 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
...
@@ -194,7 +186,7 @@ static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize
memset
(
iommu
->
page_table
,
0
,
tsbsize
);
memset
(
iommu
->
page_table
,
0
,
tsbsize
);
}
}
static
inline
iopte_t
*
alloc_npages
(
struct
sbus_
iommu
*
iommu
,
unsigned
long
npages
)
static
inline
iopte_t
*
alloc_npages
(
struct
iommu
*
iommu
,
unsigned
long
npages
)
{
{
long
entry
;
long
entry
;
...
@@ -205,14 +197,15 @@ static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npag
...
@@ -205,14 +197,15 @@ static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npag
return
iommu
->
page_table
+
entry
;
return
iommu
->
page_table
+
entry
;
}
}
static
inline
void
free_npages
(
struct
sbus_
iommu
*
iommu
,
dma_addr_t
base
,
unsigned
long
npages
)
static
inline
void
free_npages
(
struct
iommu
*
iommu
,
dma_addr_t
base
,
unsigned
long
npages
)
{
{
sbus_arena_free
(
&
iommu
->
arena
,
base
>>
IO_PAGE_SHIFT
,
npages
);
sbus_arena_free
(
&
iommu
->
arena
,
base
>>
IO_PAGE_SHIFT
,
npages
);
}
}
void
*
sbus_alloc_consistent
(
struct
sbus_dev
*
sdev
,
size_t
size
,
dma_addr_t
*
dvma_addr
)
void
*
sbus_alloc_consistent
(
struct
sbus_dev
*
sdev
,
size_t
size
,
dma_addr_t
*
dvma_addr
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
iopte_t
*
iopte
;
iopte_t
*
iopte
;
unsigned
long
flags
,
order
,
first_page
;
unsigned
long
flags
,
order
,
first_page
;
void
*
ret
;
void
*
ret
;
...
@@ -228,7 +221,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
...
@@ -228,7 +221,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
return
NULL
;
return
NULL
;
memset
((
char
*
)
first_page
,
0
,
PAGE_SIZE
<<
order
);
memset
((
char
*
)
first_page
,
0
,
PAGE_SIZE
<<
order
);
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
iopte
=
alloc_npages
(
iommu
,
size
>>
IO_PAGE_SHIFT
);
iopte
=
alloc_npages
(
iommu
,
size
>>
IO_PAGE_SHIFT
);
...
@@ -239,7 +233,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
...
@@ -239,7 +233,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
return
NULL
;
return
NULL
;
}
}
*
dvma_addr
=
(
MAP_BASE
+
*
dvma_addr
=
(
iommu
->
page_table_map_base
+
((
iopte
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
));
((
iopte
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
));
ret
=
(
void
*
)
first_page
;
ret
=
(
void
*
)
first_page
;
npages
=
size
>>
IO_PAGE_SHIFT
;
npages
=
size
>>
IO_PAGE_SHIFT
;
...
@@ -257,18 +251,20 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
...
@@ -257,18 +251,20 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma
void
sbus_free_consistent
(
struct
sbus_dev
*
sdev
,
size_t
size
,
void
*
cpu
,
dma_addr_t
dvma
)
void
sbus_free_consistent
(
struct
sbus_dev
*
sdev
,
size_t
size
,
void
*
cpu
,
dma_addr_t
dvma
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
iopte_t
*
iopte
;
iopte_t
*
iopte
;
unsigned
long
flags
,
order
,
npages
;
unsigned
long
flags
,
order
,
npages
;
npages
=
IO_PAGE_ALIGN
(
size
)
>>
IO_PAGE_SHIFT
;
npages
=
IO_PAGE_ALIGN
(
size
)
>>
IO_PAGE_SHIFT
;
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
iopte
=
iommu
->
page_table
+
iopte
=
iommu
->
page_table
+
((
dvma
-
MAP_BASE
)
>>
IO_PAGE_SHIFT
);
((
dvma
-
iommu
->
page_table_map_base
)
>>
IO_PAGE_SHIFT
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
free_npages
(
iommu
,
dvma
-
MAP_BASE
,
npages
);
free_npages
(
iommu
,
dvma
-
iommu
->
page_table_map_base
,
npages
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
...
@@ -279,14 +275,16 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add
...
@@ -279,14 +275,16 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add
dma_addr_t
sbus_map_single
(
struct
sbus_dev
*
sdev
,
void
*
ptr
,
size_t
sz
,
int
direction
)
dma_addr_t
sbus_map_single
(
struct
sbus_dev
*
sdev
,
void
*
ptr
,
size_t
sz
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
iopte_t
*
base
;
iopte_t
*
base
;
unsigned
long
flags
,
npages
,
oaddr
;
unsigned
long
flags
,
npages
,
oaddr
;
unsigned
long
i
,
base_paddr
;
unsigned
long
i
,
base_paddr
;
u32
bus_addr
,
ret
;
u32
bus_addr
,
ret
;
unsigned
long
iopte_protection
;
unsigned
long
iopte_protection
;
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
BUG
();
BUG
();
...
@@ -302,7 +300,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
...
@@ -302,7 +300,7 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
if
(
unlikely
(
!
base
))
if
(
unlikely
(
!
base
))
BUG
();
BUG
();
bus_addr
=
(
MAP_BASE
+
bus_addr
=
(
iommu
->
page_table_map_base
+
((
base
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
));
((
base
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
));
ret
=
bus_addr
|
(
oaddr
&
~
IO_PAGE_MASK
);
ret
=
bus_addr
|
(
oaddr
&
~
IO_PAGE_MASK
);
base_paddr
=
__pa
(
oaddr
&
IO_PAGE_MASK
);
base_paddr
=
__pa
(
oaddr
&
IO_PAGE_MASK
);
...
@@ -319,7 +317,9 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
...
@@ -319,7 +317,9 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int dire
void
sbus_unmap_single
(
struct
sbus_dev
*
sdev
,
dma_addr_t
bus_addr
,
size_t
sz
,
int
direction
)
void
sbus_unmap_single
(
struct
sbus_dev
*
sdev
,
dma_addr_t
bus_addr
,
size_t
sz
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
=
sdev
->
bus
->
iommu
;
struct
sbus_info
*
info
=
sdev
->
bus
->
iommu
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
struct
strbuf
*
strbuf
=
&
info
->
strbuf
;
iopte_t
*
base
;
iopte_t
*
base
;
unsigned
long
flags
,
npages
,
i
;
unsigned
long
flags
,
npages
,
i
;
...
@@ -329,15 +329,15 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, in
...
@@ -329,15 +329,15 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, in
npages
=
IO_PAGE_ALIGN
(
bus_addr
+
sz
)
-
(
bus_addr
&
IO_PAGE_MASK
);
npages
=
IO_PAGE_ALIGN
(
bus_addr
+
sz
)
-
(
bus_addr
&
IO_PAGE_MASK
);
npages
>>=
IO_PAGE_SHIFT
;
npages
>>=
IO_PAGE_SHIFT
;
base
=
iommu
->
page_table
+
base
=
iommu
->
page_table
+
((
bus_addr
-
MAP_BASE
)
>>
IO_PAGE_SHIFT
);
((
bus_addr
-
iommu
->
page_table_map_base
)
>>
IO_PAGE_SHIFT
);
bus_addr
&=
IO_PAGE_MASK
;
bus_addr
&=
IO_PAGE_MASK
;
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
sbus_strbuf_flush
(
iommu
,
bus_addr
,
npages
,
direction
);
sbus_strbuf_flush
(
iommu
,
strbuf
,
bus_addr
,
npages
,
direction
);
for
(
i
=
0
;
i
<
npages
;
i
++
)
for
(
i
=
0
;
i
<
npages
;
i
++
)
iopte_val
(
base
[
i
])
=
0UL
;
iopte_val
(
base
[
i
])
=
0UL
;
free_npages
(
iommu
,
bus_addr
-
MAP_BASE
,
npages
);
free_npages
(
iommu
,
bus_addr
-
iommu
->
page_table_map_base
,
npages
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
}
}
...
@@ -419,7 +419,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
...
@@ -419,7 +419,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
int
sbus_map_sg
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
int
sbus_map_sg
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
unsigned
long
flags
,
npages
,
iopte_protection
;
unsigned
long
flags
,
npages
,
iopte_protection
;
iopte_t
*
base
;
iopte_t
*
base
;
u32
dma_base
;
u32
dma_base
;
...
@@ -436,7 +437,8 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
...
@@ -436,7 +437,8 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
return
1
;
return
1
;
}
}
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
BUG
();
BUG
();
...
@@ -450,7 +452,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
...
@@ -450,7 +452,7 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
if
(
unlikely
(
base
==
NULL
))
if
(
unlikely
(
base
==
NULL
))
BUG
();
BUG
();
dma_base
=
MAP_BASE
+
dma_base
=
iommu
->
page_table_map_base
+
((
base
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
);
((
base
-
iommu
->
page_table
)
<<
IO_PAGE_SHIFT
);
/* Normalize DVMA addresses. */
/* Normalize DVMA addresses. */
...
@@ -479,7 +481,9 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
...
@@ -479,7 +481,9 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, i
void
sbus_unmap_sg
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
void
sbus_unmap_sg
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
struct
strbuf
*
strbuf
;
iopte_t
*
base
;
iopte_t
*
base
;
unsigned
long
flags
,
i
,
npages
;
unsigned
long
flags
,
i
,
npages
;
u32
bus_addr
;
u32
bus_addr
;
...
@@ -487,7 +491,9 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
...
@@ -487,7 +491,9 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
if
(
unlikely
(
direction
==
SBUS_DMA_NONE
))
BUG
();
BUG
();
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
strbuf
=
&
info
->
strbuf
;
bus_addr
=
sglist
->
dma_address
&
IO_PAGE_MASK
;
bus_addr
=
sglist
->
dma_address
&
IO_PAGE_MASK
;
...
@@ -499,29 +505,33 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
...
@@ -499,29 +505,33 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems
bus_addr
)
>>
IO_PAGE_SHIFT
;
bus_addr
)
>>
IO_PAGE_SHIFT
;
base
=
iommu
->
page_table
+
base
=
iommu
->
page_table
+
((
bus_addr
-
MAP_BASE
)
>>
IO_PAGE_SHIFT
);
((
bus_addr
-
iommu
->
page_table_map_base
)
>>
IO_PAGE_SHIFT
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
sbus_strbuf_flush
(
iommu
,
bus_addr
,
npages
,
direction
);
sbus_strbuf_flush
(
iommu
,
strbuf
,
bus_addr
,
npages
,
direction
);
for
(
i
=
0
;
i
<
npages
;
i
++
)
for
(
i
=
0
;
i
<
npages
;
i
++
)
iopte_val
(
base
[
i
])
=
0UL
;
iopte_val
(
base
[
i
])
=
0UL
;
free_npages
(
iommu
,
bus_addr
-
MAP_BASE
,
npages
);
free_npages
(
iommu
,
bus_addr
-
iommu
->
page_table_map_base
,
npages
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
}
}
void
sbus_dma_sync_single_for_cpu
(
struct
sbus_dev
*
sdev
,
dma_addr_t
bus_addr
,
size_t
sz
,
int
direction
)
void
sbus_dma_sync_single_for_cpu
(
struct
sbus_dev
*
sdev
,
dma_addr_t
bus_addr
,
size_t
sz
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
struct
strbuf
*
strbuf
;
unsigned
long
flags
,
npages
;
unsigned
long
flags
,
npages
;
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
strbuf
=
&
info
->
strbuf
;
npages
=
IO_PAGE_ALIGN
(
bus_addr
+
sz
)
-
(
bus_addr
&
IO_PAGE_MASK
);
npages
=
IO_PAGE_ALIGN
(
bus_addr
+
sz
)
-
(
bus_addr
&
IO_PAGE_MASK
);
npages
>>=
IO_PAGE_SHIFT
;
npages
>>=
IO_PAGE_SHIFT
;
bus_addr
&=
IO_PAGE_MASK
;
bus_addr
&=
IO_PAGE_MASK
;
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
sbus_strbuf_flush
(
iommu
,
bus_addr
,
npages
,
direction
);
sbus_strbuf_flush
(
iommu
,
strbuf
,
bus_addr
,
npages
,
direction
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
}
}
...
@@ -531,11 +541,15 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz
...
@@ -531,11 +541,15 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz
void
sbus_dma_sync_sg_for_cpu
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
void
sbus_dma_sync_sg_for_cpu
(
struct
sbus_dev
*
sdev
,
struct
scatterlist
*
sglist
,
int
nelems
,
int
direction
)
{
{
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
struct
iommu
*
iommu
;
struct
strbuf
*
strbuf
;
unsigned
long
flags
,
npages
,
i
;
unsigned
long
flags
,
npages
,
i
;
u32
bus_addr
;
u32
bus_addr
;
iommu
=
sdev
->
bus
->
iommu
;
info
=
sdev
->
bus
->
iommu
;
iommu
=
&
info
->
iommu
;
strbuf
=
&
info
->
strbuf
;
bus_addr
=
sglist
[
0
].
dma_address
&
IO_PAGE_MASK
;
bus_addr
=
sglist
[
0
].
dma_address
&
IO_PAGE_MASK
;
for
(
i
=
0
;
i
<
nelems
;
i
++
)
{
for
(
i
=
0
;
i
<
nelems
;
i
++
)
{
...
@@ -547,7 +561,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist,
...
@@ -547,7 +561,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist,
-
bus_addr
)
>>
IO_PAGE_SHIFT
;
-
bus_addr
)
>>
IO_PAGE_SHIFT
;
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
spin_lock_irqsave
(
&
iommu
->
lock
,
flags
);
sbus_strbuf_flush
(
iommu
,
bus_addr
,
npages
,
direction
);
sbus_strbuf_flush
(
iommu
,
strbuf
,
bus_addr
,
npages
,
direction
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
iommu
->
lock
,
flags
);
}
}
...
@@ -558,12 +572,13 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
...
@@ -558,12 +572,13 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
/* Enable 64-bit DVMA mode for the given device. */
/* Enable 64-bit DVMA mode for the given device. */
void
sbus_set_sbus64
(
struct
sbus_dev
*
sdev
,
int
bursts
)
void
sbus_set_sbus64
(
struct
sbus_dev
*
sdev
,
int
bursts
)
{
{
struct
sbus_iommu
*
iommu
=
sdev
->
bus
->
iommu
;
struct
sbus_info
*
info
=
sdev
->
bus
->
iommu
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
int
slot
=
sdev
->
slot
;
int
slot
=
sdev
->
slot
;
unsigned
long
cfg_reg
;
unsigned
long
cfg_reg
;
u64
val
;
u64
val
;
cfg_reg
=
iommu
->
sbus_control
_reg
;
cfg_reg
=
iommu
->
write_complete
_reg
;
switch
(
slot
)
{
switch
(
slot
)
{
case
0
:
case
0
:
cfg_reg
+=
0x20UL
;
cfg_reg
+=
0x20UL
;
...
@@ -698,8 +713,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
...
@@ -698,8 +713,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
unsigned
int
sbus_build_irq
(
void
*
buscookie
,
unsigned
int
ino
)
unsigned
int
sbus_build_irq
(
void
*
buscookie
,
unsigned
int
ino
)
{
{
struct
sbus_bus
*
sbus
=
(
struct
sbus_bus
*
)
buscookie
;
struct
sbus_bus
*
sbus
=
(
struct
sbus_bus
*
)
buscookie
;
struct
sbus_iommu
*
iommu
=
sbus
->
iommu
;
struct
sbus_info
*
info
=
sbus
->
iommu
;
unsigned
long
reg_base
=
iommu
->
sbus_control_reg
-
0x2000UL
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
unsigned
long
reg_base
=
iommu
->
write_complete_reg
-
0x2000UL
;
unsigned
long
imap
,
iclr
;
unsigned
long
imap
,
iclr
;
int
sbus_level
=
0
;
int
sbus_level
=
0
;
...
@@ -760,8 +776,9 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
...
@@ -760,8 +776,9 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
static
irqreturn_t
sysio_ue_handler
(
int
irq
,
void
*
dev_id
)
static
irqreturn_t
sysio_ue_handler
(
int
irq
,
void
*
dev_id
)
{
{
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_iommu
*
iommu
=
sbus
->
iommu
;
struct
sbus_info
*
info
=
sbus
->
iommu
;
unsigned
long
reg_base
=
iommu
->
sbus_control_reg
-
0x2000UL
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
unsigned
long
reg_base
=
iommu
->
write_complete_reg
-
0x2000UL
;
unsigned
long
afsr_reg
,
afar_reg
;
unsigned
long
afsr_reg
,
afar_reg
;
unsigned
long
afsr
,
afar
,
error_bits
;
unsigned
long
afsr
,
afar
,
error_bits
;
int
reported
;
int
reported
;
...
@@ -832,8 +849,9 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
...
@@ -832,8 +849,9 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
static
irqreturn_t
sysio_ce_handler
(
int
irq
,
void
*
dev_id
)
static
irqreturn_t
sysio_ce_handler
(
int
irq
,
void
*
dev_id
)
{
{
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_iommu
*
iommu
=
sbus
->
iommu
;
struct
sbus_info
*
info
=
sbus
->
iommu
;
unsigned
long
reg_base
=
iommu
->
sbus_control_reg
-
0x2000UL
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
unsigned
long
reg_base
=
iommu
->
write_complete_reg
-
0x2000UL
;
unsigned
long
afsr_reg
,
afar_reg
;
unsigned
long
afsr_reg
,
afar_reg
;
unsigned
long
afsr
,
afar
,
error_bits
;
unsigned
long
afsr
,
afar
,
error_bits
;
int
reported
;
int
reported
;
...
@@ -909,12 +927,13 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
...
@@ -909,12 +927,13 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
static
irqreturn_t
sysio_sbus_error_handler
(
int
irq
,
void
*
dev_id
)
static
irqreturn_t
sysio_sbus_error_handler
(
int
irq
,
void
*
dev_id
)
{
{
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_bus
*
sbus
=
dev_id
;
struct
sbus_iommu
*
iommu
=
sbus
->
iommu
;
struct
sbus_info
*
info
=
sbus
->
iommu
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
unsigned
long
afsr_reg
,
afar_reg
,
reg_base
;
unsigned
long
afsr_reg
,
afar_reg
,
reg_base
;
unsigned
long
afsr
,
afar
,
error_bits
;
unsigned
long
afsr
,
afar
,
error_bits
;
int
reported
;
int
reported
;
reg_base
=
iommu
->
sbus_control
_reg
-
0x2000UL
;
reg_base
=
iommu
->
write_complete
_reg
-
0x2000UL
;
afsr_reg
=
reg_base
+
SYSIO_SBUS_AFSR
;
afsr_reg
=
reg_base
+
SYSIO_SBUS_AFSR
;
afar_reg
=
reg_base
+
SYSIO_SBUS_AFAR
;
afar_reg
=
reg_base
+
SYSIO_SBUS_AFAR
;
...
@@ -976,8 +995,9 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
...
@@ -976,8 +995,9 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
static
void
__init
sysio_register_error_handlers
(
struct
sbus_bus
*
sbus
)
static
void
__init
sysio_register_error_handlers
(
struct
sbus_bus
*
sbus
)
{
{
struct
sbus_iommu
*
iommu
=
sbus
->
iommu
;
struct
sbus_info
*
info
=
sbus
->
iommu
;
unsigned
long
reg_base
=
iommu
->
sbus_control_reg
-
0x2000UL
;
struct
iommu
*
iommu
=
&
info
->
iommu
;
unsigned
long
reg_base
=
iommu
->
write_complete_reg
-
0x2000UL
;
unsigned
int
irq
;
unsigned
int
irq
;
u64
control
;
u64
control
;
...
@@ -1011,9 +1031,9 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
...
@@ -1011,9 +1031,9 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
SYSIO_ECNTRL_CEEN
),
SYSIO_ECNTRL_CEEN
),
reg_base
+
ECC_CONTROL
);
reg_base
+
ECC_CONTROL
);
control
=
upa_readq
(
iommu
->
sbus_control
_reg
);
control
=
upa_readq
(
iommu
->
write_complete
_reg
);
control
|=
0x100UL
;
/* SBUS Error Interrupt Enable */
control
|=
0x100UL
;
/* SBUS Error Interrupt Enable */
upa_writeq
(
control
,
iommu
->
sbus_control
_reg
);
upa_writeq
(
control
,
iommu
->
write_complete
_reg
);
}
}
/* Boot time initialization. */
/* Boot time initialization. */
...
@@ -1021,8 +1041,10 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
...
@@ -1021,8 +1041,10 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
{
const
struct
linux_prom64_registers
*
pr
;
const
struct
linux_prom64_registers
*
pr
;
struct
device_node
*
dp
;
struct
device_node
*
dp
;
struct
sbus_iommu
*
iommu
;
struct
sbus_info
*
info
;
unsigned
long
regs
;
struct
iommu
*
iommu
;
struct
strbuf
*
strbuf
;
unsigned
long
regs
,
reg_base
;
u64
control
;
u64
control
;
int
i
;
int
i
;
...
@@ -1037,33 +1059,42 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
...
@@ -1037,33 +1059,42 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
}
}
regs
=
pr
->
phys_addr
;
regs
=
pr
->
phys_addr
;
iommu
=
kmalloc
(
sizeof
(
*
iommu
)
+
SMP_CACHE_BYTES
,
GFP_ATOMIC
);
info
=
kzalloc
(
sizeof
(
*
info
),
GFP_ATOMIC
);
if
(
iommu
==
NULL
)
{
if
(
info
==
NULL
)
{
prom_printf
(
"sbus_iommu_init: Fatal error, kmalloc(iommu) failed
\n
"
);
prom_printf
(
"sbus_iommu_init: Fatal error, "
"kmalloc(info) failed
\n
"
);
prom_halt
();
prom_halt
();
}
}
/* Align on E$ line boundary. */
iommu
=
&
info
->
iommu
;
iommu
=
(
struct
sbus_iommu
*
)
strbuf
=
&
info
->
strbuf
;
(((
unsigned
long
)
iommu
+
(
SMP_CACHE_BYTES
-
1UL
))
&
~
(
SMP_CACHE_BYTES
-
1UL
));
memset
(
iommu
,
0
,
sizeof
(
*
iommu
));
reg_base
=
regs
+
SYSIO_IOMMUREG_BASE
;
iommu
->
iommu_control
=
reg_base
+
IOMMU_CONTROL
;
iommu
->
iommu_tsbbase
=
reg_base
+
IOMMU_TSBBASE
;
iommu
->
iommu_flush
=
reg_base
+
IOMMU_FLUSH
;
/* Setup spinlock. */
reg_base
=
regs
+
SYSIO_STRBUFREG_BASE
;
spin_lock_init
(
&
iommu
->
lock
);
strbuf
->
strbuf_control
=
reg_base
+
STRBUF_CONTROL
;
strbuf
->
strbuf_pflush
=
reg_base
+
STRBUF_PFLUSH
;
strbuf
->
strbuf_fsync
=
reg_base
+
STRBUF_FSYNC
;
strbuf
->
strbuf_enabled
=
1
;
/* Init register offsets. */
strbuf
->
strbuf_flushflag
=
(
volatile
unsigned
long
*
)
iommu
->
iommu_regs
=
regs
+
SYSIO_IOMMUREG_BASE
;
((((
unsigned
long
)
&
strbuf
->
__flushflag_buf
[
0
])
iommu
->
strbuf_regs
=
regs
+
SYSIO_STRBUFREG_BASE
;
+
63UL
)
&
~
63UL
);
strbuf
->
strbuf_flushflag_pa
=
(
unsigned
long
)
__pa
(
strbuf
->
strbuf_flushflag
);
/* The SYSIO SBUS control register is used for dummy reads
/* The SYSIO SBUS control register is used for dummy reads
* in order to ensure write completion.
* in order to ensure write completion.
*/
*/
iommu
->
sbus_control
_reg
=
regs
+
0x2000UL
;
iommu
->
write_complete
_reg
=
regs
+
0x2000UL
;
/* Link into SYSIO software state. */
/* Link into SYSIO software state. */
sbus
->
iommu
=
i
ommu
;
sbus
->
iommu
=
i
nfo
;
printk
(
"SYSIO: UPA portID %x, at %016lx
\n
"
,
printk
(
"SYSIO: UPA portID %x, at %016lx
\n
"
,
sbus
->
portid
,
regs
);
sbus
->
portid
,
regs
);
...
@@ -1071,40 +1102,44 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
...
@@ -1071,40 +1102,44 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
sbus_iommu_table_init
(
iommu
,
IO_TSB_SIZE
);
sbus_iommu_table_init
(
iommu
,
IO_TSB_SIZE
);
control
=
upa_readq
(
iommu
->
iommu_
regs
+
IOMMU_CONTROL
);
control
=
upa_readq
(
iommu
->
iommu_
control
);
control
=
((
7UL
<<
16UL
)
|
control
=
((
7UL
<<
16UL
)
|
(
0UL
<<
2UL
)
|
(
0UL
<<
2UL
)
|
(
1UL
<<
1UL
)
|
(
1UL
<<
1UL
)
|
(
1UL
<<
0UL
));
(
1UL
<<
0UL
));
upa_writeq
(
control
,
iommu
->
iommu_
regs
+
IOMMU_CONTROL
);
upa_writeq
(
control
,
iommu
->
iommu_
control
);
/* Clean out any cruft in the IOMMU using
/* Clean out any cruft in the IOMMU using
* diagnostic accesses.
* diagnostic accesses.
*/
*/
for
(
i
=
0
;
i
<
16
;
i
++
)
{
for
(
i
=
0
;
i
<
16
;
i
++
)
{
unsigned
long
dram
=
iommu
->
iommu_regs
+
IOMMU_DRAMDIAG
;
unsigned
long
dram
,
tag
;
unsigned
long
tag
=
iommu
->
iommu_regs
+
IOMMU_TAGDIAG
;
dram
=
iommu
->
iommu_control
+
(
IOMMU_DRAMDIAG
-
IOMMU_CONTROL
);
tag
=
iommu
->
iommu_control
+
(
IOMMU_TAGDIAG
-
IOMMU_CONTROL
);
dram
+=
(
unsigned
long
)
i
*
8UL
;
dram
+=
(
unsigned
long
)
i
*
8UL
;
tag
+=
(
unsigned
long
)
i
*
8UL
;
tag
+=
(
unsigned
long
)
i
*
8UL
;
upa_writeq
(
0
,
dram
);
upa_writeq
(
0
,
dram
);
upa_writeq
(
0
,
tag
);
upa_writeq
(
0
,
tag
);
}
}
upa_readq
(
iommu
->
sbus_control
_reg
);
upa_readq
(
iommu
->
write_complete
_reg
);
/* Give the TSB to SYSIO. */
/* Give the TSB to SYSIO. */
upa_writeq
(
__pa
(
iommu
->
page_table
),
iommu
->
iommu_
regs
+
IOMMU_TSBBASE
);
upa_writeq
(
__pa
(
iommu
->
page_table
),
iommu
->
iommu_
tsbbase
);
/* Setup streaming buffer, DE=1 SB_EN=1 */
/* Setup streaming buffer, DE=1 SB_EN=1 */
control
=
(
1UL
<<
1UL
)
|
(
1UL
<<
0UL
);
control
=
(
1UL
<<
1UL
)
|
(
1UL
<<
0UL
);
upa_writeq
(
control
,
iommu
->
strbuf_regs
+
STRBUF_CONTROL
);
upa_writeq
(
control
,
strbuf
->
strbuf_control
);
/* Clear out the tags using diagnostics. */
/* Clear out the tags using diagnostics. */
for
(
i
=
0
;
i
<
16
;
i
++
)
{
for
(
i
=
0
;
i
<
16
;
i
++
)
{
unsigned
long
ptag
,
ltag
;
unsigned
long
ptag
,
ltag
;
ptag
=
iommu
->
strbuf_regs
+
STRBUF_PTAGDIAG
;
ptag
=
strbuf
->
strbuf_control
+
ltag
=
iommu
->
strbuf_regs
+
STRBUF_LTAGDIAG
;
(
STRBUF_PTAGDIAG
-
STRBUF_CONTROL
);
ltag
=
strbuf
->
strbuf_control
+
(
STRBUF_LTAGDIAG
-
STRBUF_CONTROL
);
ptag
+=
(
unsigned
long
)
i
*
8UL
;
ptag
+=
(
unsigned
long
)
i
*
8UL
;
ltag
+=
(
unsigned
long
)
i
*
8UL
;
ltag
+=
(
unsigned
long
)
i
*
8UL
;
...
@@ -1113,9 +1148,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
...
@@ -1113,9 +1148,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
}
}
/* Enable DVMA arbitration for all devices/slots. */
/* Enable DVMA arbitration for all devices/slots. */
control
=
upa_readq
(
iommu
->
sbus_control
_reg
);
control
=
upa_readq
(
iommu
->
write_complete
_reg
);
control
|=
0x3fUL
;
control
|=
0x3fUL
;
upa_writeq
(
control
,
iommu
->
sbus_control
_reg
);
upa_writeq
(
control
,
iommu
->
write_complete
_reg
);
/* Now some Xfire specific grot... */
/* Now some Xfire specific grot... */
if
(
this_is_starfire
)
if
(
this_is_starfire
)
...
...
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