Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
85269eb5
Commit
85269eb5
authored
Aug 25, 2008
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sparc64: Add JBUS UltraSPARC-IIIi support to memory controller driver.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
41660e9a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
453 additions
and
83 deletions
+453
-83
arch/sparc64/kernel/chmc.c
arch/sparc64/kernel/chmc.c
+453
-83
No files found.
arch/sparc64/kernel/chmc.c
View file @
85269eb5
...
@@ -33,6 +33,12 @@ MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
...
@@ -33,6 +33,12 @@ MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
DRV_MODULE_VERSION
);
MODULE_VERSION
(
DRV_MODULE_VERSION
);
static
int
mc_type
;
#define MC_TYPE_SAFARI 1
#define MC_TYPE_JBUS 2
static
dimm_printer_t
us3mc_dimm_printer
;
#define CHMCTRL_NDGRPS 2
#define CHMCTRL_NDGRPS 2
#define CHMCTRL_NDIMMS 4
#define CHMCTRL_NDIMMS 4
...
@@ -96,8 +102,386 @@ struct chmc {
...
@@ -96,8 +102,386 @@ struct chmc {
struct
chmc_bank_info
logical_banks
[
CHMCTRL_NBANKS
];
struct
chmc_bank_info
logical_banks
[
CHMCTRL_NBANKS
];
};
};
#define JBUSMC_REGS_SIZE 8
#define JB_MC_REG1_DIMM2_BANK3 0x8000000000000000
#define JB_MC_REG1_DIMM1_BANK1 0x4000000000000000
#define JB_MC_REG1_DIMM2_BANK2 0x2000000000000000
#define JB_MC_REG1_DIMM1_BANK0 0x1000000000000000
#define JB_MC_REG1_XOR 0x0000010000000000
#define JB_MC_REG1_ADDR_GEN_2 0x000000e000000000
#define JB_MC_REG1_ADDR_GEN_2_SHIFT 37
#define JB_MC_REG1_ADDR_GEN_1 0x0000001c00000000
#define JB_MC_REG1_ADDR_GEN_1_SHIFT 34
#define JB_MC_REG1_INTERLEAVE 0x0000000001800000
#define JB_MC_REG1_INTERLEAVE_SHIFT 23
#define JB_MC_REG1_DIMM2_PTYPE 0x0000000000200000
#define JB_MC_REG1_DIMM2_PTYPE_SHIFT 21
#define JB_MC_REG1_DIMM1_PTYPE 0x0000000000100000
#define JB_MC_REG1_DIMM1_PTYPE_SHIFT 20
#define PART_TYPE_X8 0
#define PART_TYPE_X4 1
#define INTERLEAVE_NONE 0
#define INTERLEAVE_SAME 1
#define INTERLEAVE_INTERNAL 2
#define INTERLEAVE_BOTH 3
#define ADDR_GEN_128MB 0
#define ADDR_GEN_256MB 1
#define ADDR_GEN_512MB 2
#define ADDR_GEN_1GB 3
#define JB_NUM_DIMM_GROUPS 2
#define JB_NUM_DIMMS_PER_GROUP 2
#define JB_NUM_DIMMS (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
struct
jbusmc_obp_map
{
unsigned
char
dimm_map
[
18
];
unsigned
char
pin_map
[
144
];
};
struct
jbusmc_obp_mem_layout
{
/* One max 8-byte string label per DIMM. Usually
* this matches the label on the motherboard where
* that DIMM resides.
*/
char
dimm_labels
[
JB_NUM_DIMMS
][
DIMM_LABEL_SZ
];
/* If symmetric use map[0], else it is
* asymmetric and map[1] should be used.
*/
char
symmetric
;
struct
jbusmc_obp_map
map
;
char
_pad
;
};
struct
jbusmc_dimm_group
{
struct
jbusmc
*
controller
;
int
index
;
u64
base_addr
;
u64
size
;
};
struct
jbusmc
{
void
__iomem
*
regs
;
u64
mc_reg_1
;
u32
portid
;
struct
jbusmc_obp_mem_layout
layout
;
int
layout_len
;
int
num_dimm_groups
;
struct
jbusmc_dimm_group
dimm_groups
[
JB_NUM_DIMM_GROUPS
];
struct
list_head
list
;
};
static
DEFINE_SPINLOCK
(
mctrl_list_lock
);
static
LIST_HEAD
(
mctrl_list
);
static
LIST_HEAD
(
mctrl_list
);
static
void
mc_list_add
(
struct
list_head
*
list
)
{
spin_lock
(
&
mctrl_list_lock
);
list_add
(
list
,
&
mctrl_list
);
spin_unlock
(
&
mctrl_list_lock
);
}
static
void
mc_list_del
(
struct
list_head
*
list
)
{
spin_lock
(
&
mctrl_list_lock
);
list_del_init
(
list
);
spin_unlock
(
&
mctrl_list_lock
);
}
#define SYNDROME_MIN -1
#define SYNDROME_MAX 144
/* Covert syndrome code into the way the bits are positioned
* on the bus.
*/
static
int
syndrome_to_qword_code
(
int
syndrome_code
)
{
if
(
syndrome_code
<
128
)
syndrome_code
+=
16
;
else
if
(
syndrome_code
<
128
+
9
)
syndrome_code
-=
(
128
-
7
);
else
if
(
syndrome_code
<
(
128
+
9
+
3
))
syndrome_code
-=
(
128
+
9
-
4
);
else
syndrome_code
-=
(
128
+
9
+
3
);
return
syndrome_code
;
}
/* All this magic has to do with how a cache line comes over the wire
* on Safari and JBUS. A 64-bit line comes over in 1 or more quadword
* cycles, each of which transmit ECC/MTAG info as well as the actual
* data.
*/
#define L2_LINE_SIZE 64
#define L2_LINE_ADDR_MSK (L2_LINE_SIZE - 1)
#define QW_PER_LINE 4
#define QW_BYTES (L2_LINE_SIZE / QW_PER_LINE)
#define QW_BITS 144
#define SAFARI_LAST_BIT (576 - 1)
#define JBUS_LAST_BIT (144 - 1)
static
void
get_pin_and_dimm_str
(
int
syndrome_code
,
unsigned
long
paddr
,
int
*
pin_p
,
char
**
dimm_str_p
,
void
*
_prop
,
int
base_dimm_offset
)
{
int
qword_code
=
syndrome_to_qword_code
(
syndrome_code
);
int
cache_line_offset
;
int
offset_inverse
;
int
dimm_map_index
;
int
map_val
;
if
(
mc_type
==
MC_TYPE_JBUS
)
{
struct
jbusmc_obp_mem_layout
*
p
=
_prop
;
/* JBUS */
cache_line_offset
=
qword_code
;
offset_inverse
=
(
JBUS_LAST_BIT
-
cache_line_offset
);
dimm_map_index
=
offset_inverse
/
8
;
map_val
=
p
->
map
.
dimm_map
[
dimm_map_index
];
map_val
=
((
map_val
>>
((
7
-
(
offset_inverse
&
7
))))
&
1
);
*
dimm_str_p
=
p
->
dimm_labels
[
base_dimm_offset
+
map_val
];
*
pin_p
=
p
->
map
.
pin_map
[
cache_line_offset
];
}
else
{
struct
chmc_obp_mem_layout
*
p
=
_prop
;
struct
chmc_obp_map
*
mp
;
int
qword
;
/* Safari */
if
(
p
->
symmetric
)
mp
=
&
p
->
map
[
0
];
else
mp
=
&
p
->
map
[
1
];
qword
=
(
paddr
&
L2_LINE_ADDR_MSK
)
/
QW_BYTES
;
cache_line_offset
=
((
3
-
qword
)
*
QW_BITS
)
+
qword_code
;
offset_inverse
=
(
SAFARI_LAST_BIT
-
cache_line_offset
);
dimm_map_index
=
offset_inverse
>>
2
;
map_val
=
mp
->
dimm_map
[
dimm_map_index
];
map_val
=
((
map_val
>>
((
3
-
(
offset_inverse
&
3
))
<<
1
))
&
0x3
);
*
dimm_str_p
=
p
->
dimm_labels
[
base_dimm_offset
+
map_val
];
*
pin_p
=
mp
->
pin_map
[
cache_line_offset
];
}
}
static
struct
jbusmc_dimm_group
*
jbusmc_find_dimm_group
(
unsigned
long
phys_addr
)
{
struct
jbusmc
*
p
;
list_for_each_entry
(
p
,
&
mctrl_list
,
list
)
{
int
i
;
for
(
i
=
0
;
i
<
p
->
num_dimm_groups
;
i
++
)
{
struct
jbusmc_dimm_group
*
dp
=
&
p
->
dimm_groups
[
i
];
if
(
phys_addr
<
dp
->
base_addr
||
(
dp
->
base_addr
+
dp
->
size
)
<=
phys_addr
)
continue
;
return
dp
;
}
}
return
NULL
;
}
static
int
jbusmc_print_dimm
(
int
syndrome_code
,
unsigned
long
phys_addr
,
char
*
buf
,
int
buflen
)
{
struct
jbusmc_obp_mem_layout
*
prop
;
struct
jbusmc_dimm_group
*
dp
;
struct
jbusmc
*
p
;
int
first_dimm
;
dp
=
jbusmc_find_dimm_group
(
phys_addr
);
if
(
dp
==
NULL
||
syndrome_code
<
SYNDROME_MIN
||
syndrome_code
>
SYNDROME_MAX
)
{
buf
[
0
]
=
'?'
;
buf
[
1
]
=
'?'
;
buf
[
2
]
=
'?'
;
buf
[
3
]
=
'\0'
;
}
p
=
dp
->
controller
;
prop
=
&
p
->
layout
;
first_dimm
=
dp
->
index
*
JB_NUM_DIMMS_PER_GROUP
;
if
(
syndrome_code
!=
SYNDROME_MIN
)
{
char
*
dimm_str
;
int
pin
;
get_pin_and_dimm_str
(
syndrome_code
,
phys_addr
,
&
pin
,
&
dimm_str
,
prop
,
first_dimm
);
sprintf
(
buf
,
"%s, pin %3d"
,
dimm_str
,
pin
);
}
else
{
int
dimm
;
/* Multi-bit error, we just dump out all the
* dimm labels associated with this dimm group.
*/
for
(
dimm
=
0
;
dimm
<
JB_NUM_DIMMS_PER_GROUP
;
dimm
++
)
{
sprintf
(
buf
,
"%s "
,
prop
->
dimm_labels
[
first_dimm
+
dimm
]);
buf
+=
strlen
(
buf
);
}
}
return
0
;
}
static
u64
__devinit
jbusmc_dimm_group_size
(
u64
base
,
const
struct
linux_prom64_registers
*
mem_regs
,
int
num_mem_regs
)
{
u64
max
=
base
+
(
8UL
*
1024
*
1024
*
1024
);
u64
max_seen
=
base
;
int
i
;
for
(
i
=
0
;
i
<
num_mem_regs
;
i
++
)
{
const
struct
linux_prom64_registers
*
ent
;
u64
this_base
;
u64
this_end
;
ent
=
&
mem_regs
[
i
];
this_base
=
ent
->
phys_addr
;
this_end
=
this_base
+
ent
->
reg_size
;
if
(
base
<
this_base
||
base
>=
this_end
)
continue
;
if
(
this_end
>
max
)
this_end
=
max
;
if
(
this_end
>
max_seen
)
max_seen
=
this_end
;
}
return
max_seen
-
base
;
}
static
void
__devinit
jbusmc_construct_one_dimm_group
(
struct
jbusmc
*
p
,
unsigned
long
index
,
const
struct
linux_prom64_registers
*
mem_regs
,
int
num_mem_regs
)
{
struct
jbusmc_dimm_group
*
dp
=
&
p
->
dimm_groups
[
index
];
dp
->
controller
=
p
;
dp
->
index
=
index
;
dp
->
base_addr
=
(
p
->
portid
*
(
64UL
*
1024
*
1024
*
1024
));
dp
->
base_addr
+=
(
index
*
(
8UL
*
1024
*
1024
*
1024
));
dp
->
size
=
jbusmc_dimm_group_size
(
dp
->
base_addr
,
mem_regs
,
num_mem_regs
);
}
static
void
__devinit
jbusmc_construct_dimm_groups
(
struct
jbusmc
*
p
,
const
struct
linux_prom64_registers
*
mem_regs
,
int
num_mem_regs
)
{
if
(
p
->
mc_reg_1
&
JB_MC_REG1_DIMM1_BANK0
)
{
jbusmc_construct_one_dimm_group
(
p
,
0
,
mem_regs
,
num_mem_regs
);
p
->
num_dimm_groups
++
;
}
if
(
p
->
mc_reg_1
&
JB_MC_REG1_DIMM2_BANK2
)
{
jbusmc_construct_one_dimm_group
(
p
,
1
,
mem_regs
,
num_mem_regs
);
p
->
num_dimm_groups
++
;
}
}
static
int
__devinit
jbusmc_probe
(
struct
of_device
*
op
,
const
struct
of_device_id
*
match
)
{
const
struct
linux_prom64_registers
*
mem_regs
;
struct
device_node
*
mem_node
;
int
err
,
len
,
num_mem_regs
;
struct
jbusmc
*
p
;
const
u32
*
prop
;
const
void
*
ml
;
err
=
-
ENODEV
;
mem_node
=
of_find_node_by_path
(
"/memory"
);
if
(
!
mem_node
)
{
printk
(
KERN_ERR
PFX
"Cannot find /memory node.
\n
"
);
goto
out
;
}
mem_regs
=
of_get_property
(
mem_node
,
"reg"
,
&
len
);
if
(
!
mem_regs
)
{
printk
(
KERN_ERR
PFX
"Cannot get reg property of /memory node.
\n
"
);
goto
out
;
}
num_mem_regs
=
len
/
sizeof
(
*
mem_regs
);
err
=
-
ENOMEM
;
p
=
kzalloc
(
sizeof
(
*
p
),
GFP_KERNEL
);
if
(
!
p
)
{
printk
(
KERN_ERR
PFX
"Cannot allocate struct jbusmc.
\n
"
);
goto
out
;
}
INIT_LIST_HEAD
(
&
p
->
list
);
err
=
-
ENODEV
;
prop
=
of_get_property
(
op
->
node
,
"portid"
,
&
len
);
if
(
!
prop
||
len
!=
4
)
{
printk
(
KERN_ERR
PFX
"Cannot find portid.
\n
"
);
goto
out_free
;
}
p
->
portid
=
*
prop
;
prop
=
of_get_property
(
op
->
node
,
"memory-control-register-1"
,
&
len
);
if
(
!
prop
||
len
!=
8
)
{
printk
(
KERN_ERR
PFX
"Cannot get memory control register 1.
\n
"
);
goto
out_free
;
}
p
->
mc_reg_1
=
((
u64
)
prop
[
0
]
<<
32
)
|
(
u64
)
prop
[
1
];
err
=
-
ENOMEM
;
p
->
regs
=
of_ioremap
(
&
op
->
resource
[
0
],
0
,
JBUSMC_REGS_SIZE
,
"jbusmc"
);
if
(
!
p
->
regs
)
{
printk
(
KERN_ERR
PFX
"Cannot map jbusmc regs.
\n
"
);
goto
out_free
;
}
err
=
-
ENODEV
;
ml
=
of_get_property
(
op
->
node
,
"memory-layout"
,
&
p
->
layout_len
);
if
(
!
ml
)
{
printk
(
KERN_ERR
PFX
"Cannot get memory layout property.
\n
"
);
goto
out_iounmap
;
}
if
(
p
->
layout_len
>
sizeof
(
p
->
layout
))
{
printk
(
KERN_ERR
PFX
"Unexpected memory-layout size %d
\n
"
,
p
->
layout_len
);
goto
out_iounmap
;
}
memcpy
(
&
p
->
layout
,
ml
,
p
->
layout_len
);
jbusmc_construct_dimm_groups
(
p
,
mem_regs
,
num_mem_regs
);
mc_list_add
(
&
p
->
list
);
printk
(
KERN_INFO
PFX
"UltraSPARC-IIIi memory controller at %s
\n
"
,
op
->
node
->
full_name
);
dev_set_drvdata
(
&
op
->
dev
,
p
);
err
=
0
;
out:
return
err
;
out_iounmap:
of_iounmap
(
&
op
->
resource
[
0
],
p
->
regs
,
JBUSMC_REGS_SIZE
);
out_free:
kfree
(
p
);
goto
out
;
}
/* Does BANK decode PHYS_ADDR? */
/* Does BANK decode PHYS_ADDR? */
static
int
chmc_bank_match
(
struct
chmc_bank_info
*
bp
,
unsigned
long
phys_addr
)
static
int
chmc_bank_match
(
struct
chmc_bank_info
*
bp
,
unsigned
long
phys_addr
)
{
{
...
@@ -133,17 +517,11 @@ static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
...
@@ -133,17 +517,11 @@ static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
/* Given PHYS_ADDR, search memory controller banks for a match. */
/* Given PHYS_ADDR, search memory controller banks for a match. */
static
struct
chmc_bank_info
*
chmc_find_bank
(
unsigned
long
phys_addr
)
static
struct
chmc_bank_info
*
chmc_find_bank
(
unsigned
long
phys_addr
)
{
{
struct
list_head
*
mctrl_head
=
&
mctrl_list
;
struct
chmc
*
p
;
struct
list_head
*
mctrl_entry
=
mctrl_head
->
next
;
for
(;;)
{
list_for_each_entry
(
p
,
&
mctrl_list
,
list
)
{
struct
chmc
*
p
=
list_entry
(
mctrl_entry
,
struct
chmc
,
list
);
int
bank_no
;
int
bank_no
;
if
(
mctrl_entry
==
mctrl_head
)
break
;
mctrl_entry
=
mctrl_entry
->
next
;
for
(
bank_no
=
0
;
bank_no
<
CHMCTRL_NBANKS
;
bank_no
++
)
{
for
(
bank_no
=
0
;
bank_no
<
CHMCTRL_NBANKS
;
bank_no
++
)
{
struct
chmc_bank_info
*
bp
;
struct
chmc_bank_info
*
bp
;
...
@@ -157,8 +535,6 @@ static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
...
@@ -157,8 +535,6 @@ static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
}
}
/* This is the main purpose of this driver. */
/* This is the main purpose of this driver. */
#define SYNDROME_MIN -1
#define SYNDROME_MAX 144
static
int
chmc_print_dimm
(
int
syndrome_code
,
static
int
chmc_print_dimm
(
int
syndrome_code
,
unsigned
long
phys_addr
,
unsigned
long
phys_addr
,
char
*
buf
,
int
buflen
)
char
*
buf
,
int
buflen
)
...
@@ -184,54 +560,12 @@ static int chmc_print_dimm(int syndrome_code,
...
@@ -184,54 +560,12 @@ static int chmc_print_dimm(int syndrome_code,
first_dimm
*=
CHMCTRL_NDIMMS
;
first_dimm
*=
CHMCTRL_NDIMMS
;
if
(
syndrome_code
!=
SYNDROME_MIN
)
{
if
(
syndrome_code
!=
SYNDROME_MIN
)
{
struct
chmc_obp_map
*
map
;
char
*
dimm_str
;
int
qword
,
where_in_line
,
where
,
map_index
,
map_offset
;
int
pin
;
unsigned
int
map_val
;
/* Yaay, single bit error so we can figure out
* the exact dimm.
*/
if
(
prop
->
symmetric
)
map
=
&
prop
->
map
[
0
];
else
map
=
&
prop
->
map
[
1
];
/* Covert syndrome code into the way the bits are
* positioned on the bus.
*/
if
(
syndrome_code
<
144
-
16
)
syndrome_code
+=
16
;
else
if
(
syndrome_code
<
144
)
syndrome_code
-=
(
144
-
7
);
else
if
(
syndrome_code
<
(
144
+
3
))
syndrome_code
-=
(
144
+
3
-
4
);
else
syndrome_code
-=
144
+
3
;
/* All this magic has to do with how a cache line
get_pin_and_dimm_str
(
syndrome_code
,
phys_addr
,
&
pin
,
* comes over the wire on Safari. A 64-bit line
&
dimm_str
,
prop
,
first_dimm
);
* comes over in 4 quadword cycles, each of which
sprintf
(
buf
,
"%s, pin %3d"
,
dimm_str
,
pin
);
* transmit ECC/MTAG info as well as the actual
* data. 144 bits per quadword, 576 total.
*/
#define LINE_SIZE 64
#define LINE_ADDR_MSK (LINE_SIZE - 1)
#define QW_PER_LINE 4
#define QW_BYTES (LINE_SIZE / QW_PER_LINE)
#define QW_BITS 144
#define LAST_BIT (576 - 1)
qword
=
(
phys_addr
&
LINE_ADDR_MSK
)
/
QW_BYTES
;
where_in_line
=
((
3
-
qword
)
*
QW_BITS
)
+
syndrome_code
;
where
=
(
LAST_BIT
-
where_in_line
);
map_index
=
where
>>
2
;
map_offset
=
where
&
0x3
;
map_val
=
map
->
dimm_map
[
map_index
];
map_val
=
((
map_val
>>
((
3
-
map_offset
)
<<
1
))
&
(
2
-
1
));
sprintf
(
buf
,
"%s, pin %3d"
,
prop
->
dimm_labels
[
first_dimm
+
map_val
],
map
->
pin_map
[
where_in_line
]);
}
else
{
}
else
{
int
dimm
;
int
dimm
;
...
@@ -412,9 +746,8 @@ static int __devinit chmc_probe(struct of_device *op,
...
@@ -412,9 +746,8 @@ static int __devinit chmc_probe(struct of_device *op,
chmc_fetch_decode_regs
(
p
);
chmc_fetch_decode_regs
(
p
);
list_add
(
&
p
->
list
,
&
mctrl_
list
);
mc_list_add
(
&
p
->
list
);
/* Report the device. */
printk
(
KERN_INFO
PFX
"UltraSPARC-III memory controller at %s [%s]
\n
"
,
printk
(
KERN_INFO
PFX
"UltraSPARC-III memory controller at %s [%s]
\n
"
,
dp
->
full_name
,
dp
->
full_name
,
(
p
->
layout_size
?
"ACTIVE"
:
"INACTIVE"
));
(
p
->
layout_size
?
"ACTIVE"
:
"INACTIVE"
));
...
@@ -431,63 +764,100 @@ out_free:
...
@@ -431,63 +764,100 @@ out_free:
goto
out
;
goto
out
;
}
}
static
int
__devexit
chmc_remove
(
struct
of_device
*
op
)
static
int
__devinit
us3mc_probe
(
struct
of_device
*
op
,
const
struct
of_device_id
*
match
)
{
if
(
mc_type
==
MC_TYPE_SAFARI
)
return
chmc_probe
(
op
,
match
);
else
if
(
mc_type
==
MC_TYPE_JBUS
)
return
jbusmc_probe
(
op
,
match
);
return
-
ENODEV
;
}
static
void
__devexit
chmc_destroy
(
struct
of_device
*
op
,
struct
chmc
*
p
)
{
list_del
(
&
p
->
list
);
of_iounmap
(
&
op
->
resource
[
0
],
p
->
regs
,
0x48
);
kfree
(
p
);
}
static
void
__devexit
jbusmc_destroy
(
struct
of_device
*
op
,
struct
jbusmc
*
p
)
{
{
struct
chmc
*
p
=
dev_get_drvdata
(
&
op
->
dev
);
mc_list_del
(
&
p
->
list
);
of_iounmap
(
&
op
->
resource
[
0
],
p
->
regs
,
JBUSMC_REGS_SIZE
);
kfree
(
p
);
}
static
int
__devexit
us3mc_remove
(
struct
of_device
*
op
)
{
void
*
p
=
dev_get_drvdata
(
&
op
->
dev
);
if
(
p
)
{
if
(
p
)
{
list_del
(
&
p
->
list
);
if
(
mc_type
==
MC_TYPE_SAFARI
)
of_iounmap
(
&
op
->
resource
[
0
],
p
->
regs
,
0x48
);
chmc_destroy
(
op
,
p
);
kfree
(
p
);
else
if
(
mc_type
==
MC_TYPE_JBUS
)
jbusmc_destroy
(
op
,
p
);
}
}
return
0
;
return
0
;
}
}
static
struct
of_device_id
ch
mc_match
[]
=
{
static
struct
of_device_id
us3
mc_match
[]
=
{
{
{
.
name
=
"memory-controller"
,
.
name
=
"memory-controller"
,
},
},
{},
{},
};
};
MODULE_DEVICE_TABLE
(
of
,
ch
mc_match
);
MODULE_DEVICE_TABLE
(
of
,
us3
mc_match
);
static
struct
of_platform_driver
ch
mc_driver
=
{
static
struct
of_platform_driver
us3
mc_driver
=
{
.
name
=
"
ch
mc"
,
.
name
=
"
us3
mc"
,
.
match_table
=
ch
mc_match
,
.
match_table
=
us3
mc_match
,
.
probe
=
ch
mc_probe
,
.
probe
=
us3
mc_probe
,
.
remove
=
__devexit_p
(
ch
mc_remove
),
.
remove
=
__devexit_p
(
us3
mc_remove
),
};
};
static
inline
bool
ch
mc_platform
(
void
)
static
inline
bool
us3
mc_platform
(
void
)
{
{
if
(
tlb_type
==
cheetah
||
tlb_type
==
cheetah_plus
)
if
(
tlb_type
==
cheetah
||
tlb_type
==
cheetah_plus
)
return
true
;
return
true
;
return
false
;
return
false
;
}
}
static
int
__init
ch
mc_init
(
void
)
static
int
__init
us3
mc_init
(
void
)
{
{
unsigned
long
ver
;
int
ret
;
int
ret
;
if
(
!
ch
mc_platform
())
if
(
!
us3
mc_platform
())
return
-
ENODEV
;
return
-
ENODEV
;
ret
=
register_dimm_printer
(
chmc_print_dimm
);
__asm__
(
"rdpr %%ver, %0"
:
"=r"
(
ver
));
if
((
ver
>>
32UL
)
==
__JALAPENO_ID
||
(
ver
>>
32UL
)
==
__SERRANO_ID
)
{
mc_type
=
MC_TYPE_JBUS
;
us3mc_dimm_printer
=
jbusmc_print_dimm
;
}
else
{
mc_type
=
MC_TYPE_SAFARI
;
us3mc_dimm_printer
=
chmc_print_dimm
;
}
ret
=
register_dimm_printer
(
us3mc_dimm_printer
);
if
(
!
ret
)
{
if
(
!
ret
)
{
ret
=
of_register_driver
(
&
ch
mc_driver
,
&
of_bus_type
);
ret
=
of_register_driver
(
&
us3
mc_driver
,
&
of_bus_type
);
if
(
ret
)
if
(
ret
)
unregister_dimm_printer
(
chmc_print_dimm
);
unregister_dimm_printer
(
us3mc_dimm_printer
);
}
}
return
ret
;
return
ret
;
}
}
static
void
__exit
ch
mc_cleanup
(
void
)
static
void
__exit
us3
mc_cleanup
(
void
)
{
{
if
(
ch
mc_platform
())
{
if
(
us3
mc_platform
())
{
unregister_dimm_printer
(
chmc_print_dimm
);
unregister_dimm_printer
(
us3mc_dimm_printer
);
of_unregister_driver
(
&
ch
mc_driver
);
of_unregister_driver
(
&
us3
mc_driver
);
}
}
}
}
module_init
(
ch
mc_init
);
module_init
(
us3
mc_init
);
module_exit
(
ch
mc_cleanup
);
module_exit
(
us3
mc_cleanup
);
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