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
9510ba13
Commit
9510ba13
authored
Jun 10, 2002
by
Anton Blanchard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pSeries firmware flash support from Todd Inglett
parent
100531e9
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
371 additions
and
2 deletions
+371
-2
arch/ppc64/config.in
arch/ppc64/config.in
+2
-0
arch/ppc64/defconfig
arch/ppc64/defconfig
+8
-2
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/Makefile
+2
-0
arch/ppc64/kernel/proc_pmc.c
arch/ppc64/kernel/proc_pmc.c
+5
-0
arch/ppc64/kernel/rtas.c
arch/ppc64/kernel/rtas.c
+87
-0
arch/ppc64/kernel/rtas_flash.c
arch/ppc64/kernel/rtas_flash.c
+240
-0
include/asm-ppc64/rtas.h
include/asm-ppc64/rtas.h
+27
-0
No files found.
arch/ppc64/config.in
View file @
9510ba13
...
...
@@ -33,6 +33,8 @@ define_bool CONFIG_PREEMPT n
if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
define_bool CONFIG_MSCHUNKS y
else
tristate ' Firmware flash interface' CONFIG_RTAS_FLASH
fi
endmenu
...
...
arch/ppc64/defconfig
View file @
9510ba13
...
...
@@ -37,7 +37,9 @@ CONFIG_PPC64=y
CONFIG_SMP=y
CONFIG_IRQ_ALL_CPUS=y
# CONFIG_HMT is not set
# CONFIG_DISCONTIGMEM is not set
# CONFIG_PREEMPT is not set
# CONFIG_RTAS_FLASH is not set
#
# General setup
...
...
@@ -60,6 +62,7 @@ CONFIG_PCI_NAMES=y
#
# CONFIG_PARPORT is not set
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
#
# Memory Technology Devices (MTD)
...
...
@@ -83,6 +86,7 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_CISS_SCSI_TAPE is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
...
...
@@ -364,7 +368,7 @@ CONFIG_IBMOL=y
# CONFIG_WAN is not set
#
#
"Tulip"
family network device support
#
Tulip
family network device support
#
# CONFIG_NET_TULIP is not set
...
...
@@ -397,7 +401,6 @@ CONFIG_IBMOL=y
#
CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FB_RIVA is not set
# CONFIG_FB_CLGEN is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
...
...
@@ -409,6 +412,7 @@ CONFIG_FB_OF=y
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_S3TRIO is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_RIVA is not set
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_MILLENIUM=y
CONFIG_FB_MATROX_MYSTIQUE=y
...
...
@@ -422,6 +426,8 @@ CONFIG_FB_MATROX_G100=y
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
CONFIG_FBCON_CFB8=y
...
...
arch/ppc64/kernel/Makefile
View file @
9510ba13
...
...
@@ -32,6 +32,8 @@ obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o eeh.o
obj-y
+=
rtasd.o nvram.o
endif
obj-$(CONFIG_RTAS_FLASH)
+=
rtas_flash.o
obj-$(CONFIG_SMP)
+=
smp.o
obj-y
+=
prom.o lmb.o rtas.o rtas-proc.o chrp_setup.o i8259.o
...
...
arch/ppc64/kernel/proc_pmc.c
View file @
9510ba13
...
...
@@ -39,6 +39,7 @@
#include <asm/pmc.h>
#include <asm/uaccess.h>
#include <asm/naca.h>
#include <asm/rtas.h>
static
int
proc_pmc_control_mode
=
0
;
...
...
@@ -100,6 +101,9 @@ void proc_ppc64_init(void)
if
(
!
proc_ppc64_root
)
return
;
spin_unlock
(
&
proc_ppc64_lock
);
/* Placeholder for rtas interfaces. */
rtas_proc_dir
=
proc_mkdir
(
"rtas"
,
proc_ppc64_root
);
proc_ppc64_pmc_root
=
proc_mkdir
(
"pmc"
,
proc_ppc64_root
);
...
...
@@ -321,6 +325,7 @@ void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
if
(
!
ent
)
return
;
ent
->
nlink
=
1
;
ent
->
data
=
(
void
*
)
0
;
ent
->
size
=
0
;
ent
->
read_proc
=
proc_get_titanTod
;
ent
->
write_proc
=
NULL
;
...
...
arch/ppc64/kernel/rtas.c
View file @
9510ba13
...
...
@@ -19,12 +19,17 @@
#include <asm/init.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/semaphore.h>
#include <asm/machdep.h>
#include <asm/paca.h>
#include <asm/page.h>
#include <asm/system.h>
#include <asm/abs_addr.h>
#include <asm/udbg.h>
struct
proc_dir_entry
*
rtas_proc_dir
;
/* /proc/ppc64/rtas dir */
struct
flash_block_list_header
rtas_firmware_flash_list
=
{
0
,
0
};
/*
* prom_init() is called very early on, before the kernel text
* and data have been mapped to KERNELBASE. At this point the code
...
...
@@ -184,9 +189,87 @@ rtas_call(int token, int nargs, int nret,
return
(
ulong
)((
nret
>
0
)
?
rtas_args
->
rets
[
0
]
:
0
);
}
#define FLASH_BLOCK_LIST_VERSION (1UL)
static
void
rtas_flash_firmware
(
void
)
{
unsigned
long
image_size
;
struct
flash_block_list
*
f
,
*
next
,
*
flist
;
unsigned
long
rtas_block_list
;
int
i
,
status
,
update_token
;
update_token
=
rtas_token
(
"ibm,update-flash-64-and-reboot"
);
if
(
update_token
==
RTAS_UNKNOWN_SERVICE
)
{
printk
(
KERN_ALERT
"FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?
\n
"
);
printk
(
KERN_ALERT
"FLASH: firmware will not be flashed
\n
"
);
return
;
}
/* NOTE: the "first" block list is a global var with no data
* blocks in the kernel data segment. We do this because
* we want to ensure this block_list addr is under 4GB.
*/
rtas_firmware_flash_list
.
num_blocks
=
0
;
flist
=
(
struct
flash_block_list
*
)
&
rtas_firmware_flash_list
;
rtas_block_list
=
virt_to_absolute
((
unsigned
long
)
flist
);
if
(
rtas_block_list
>=
(
4UL
<<
20
))
{
printk
(
KERN_ALERT
"FLASH: kernel bug...flash list header addr above 4GB
\n
"
);
return
;
}
printk
(
KERN_ALERT
"FLASH: preparing saved firmware image for flash
\n
"
);
/* Update the block_list in place. */
image_size
=
0
;
for
(
f
=
flist
;
f
;
f
=
next
)
{
/* Translate data addrs to absolute */
for
(
i
=
0
;
i
<
f
->
num_blocks
;
i
++
)
{
f
->
blocks
[
i
].
data
=
(
char
*
)
virt_to_absolute
((
unsigned
long
)
f
->
blocks
[
i
].
data
);
image_size
+=
f
->
blocks
[
i
].
length
;
}
next
=
f
->
next
;
f
->
next
=
(
struct
flash_block_list
*
)
virt_to_absolute
((
unsigned
long
)
f
->
next
);
/* make num_blocks into the version/length field */
f
->
num_blocks
=
(
FLASH_BLOCK_LIST_VERSION
<<
56
)
|
((
f
->
num_blocks
+
1
)
*
16
);
}
printk
(
KERN_ALERT
"FLASH: flash image is %ld bytes
\n
"
,
image_size
);
printk
(
KERN_ALERT
"FLASH: performing flash and reboot
\n
"
);
ppc_md
.
progress
(
"Flashing
\n
"
,
0x0
);
ppc_md
.
progress
(
"Please Wait... "
,
0x0
);
printk
(
KERN_ALERT
"FLASH: this will take several minutes. Do not power off!
\n
"
);
status
=
rtas_call
(
update_token
,
1
,
1
,
NULL
,
rtas_block_list
);
switch
(
status
)
{
/* should only get "bad" status */
case
0
:
printk
(
KERN_ALERT
"FLASH: success
\n
"
);
break
;
case
-
1
:
printk
(
KERN_ALERT
"FLASH: hardware error. Firmware may not be not flashed
\n
"
);
break
;
case
-
3
:
printk
(
KERN_ALERT
"FLASH: image is corrupt or not correct for this platform. Firmware not flashed
\n
"
);
break
;
case
-
4
:
printk
(
KERN_ALERT
"FLASH: flash failed when partially complete. System may not reboot
\n
"
);
break
;
default:
printk
(
KERN_ALERT
"FLASH: unknown flash return code %d
\n
"
,
status
);
break
;
}
}
void
rtas_flash_bypass_warning
(
void
)
{
printk
(
KERN_ALERT
"FLASH: firmware flash requires a reboot
\n
"
);
printk
(
KERN_ALERT
"FLASH: the firmware image will NOT be flashed
\n
"
);
}
void
__chrp
rtas_restart
(
char
*
cmd
)
{
if
(
rtas_firmware_flash_list
.
next
)
rtas_flash_firmware
();
printk
(
"RTAS system-reboot returned %ld
\n
"
,
rtas_call
(
rtas_token
(
"system-reboot"
),
0
,
1
,
NULL
));
for
(;;);
...
...
@@ -195,6 +278,8 @@ rtas_restart(char *cmd)
void
__chrp
rtas_power_off
(
void
)
{
if
(
rtas_firmware_flash_list
.
next
)
rtas_flash_bypass_warning
();
/* allow power on only with power button press */
printk
(
"RTAS power-off returned %ld
\n
"
,
rtas_call
(
rtas_token
(
"power-off"
),
2
,
1
,
NULL
,
0xffffffff
,
0xffffffff
));
...
...
@@ -204,5 +289,7 @@ rtas_power_off(void)
void
__chrp
rtas_halt
(
void
)
{
if
(
rtas_firmware_flash_list
.
next
)
rtas_flash_bypass_warning
();
rtas_power_off
();
}
arch/ppc64/kernel/rtas_flash.c
0 → 100644
View file @
9510ba13
/*
* c 2001 PPC 64 Team, IBM Corp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* /proc/ppc64/rtas/firmware_flash interface
*
* This file implements a firmware_flash interface to pump a firmware
* image into the kernel. At reboot time rtas_restart() will see the
* firmware image and flash it as it reboots (see rtas.c).
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#define MODULE_VERSION "1.0"
#define MODULE_NAME "rtas_flash"
#define FIRMWARE_FLASH_NAME "firmware_flash"
/* Local copy of the flash block list.
* We only allow one open of the flash proc file and create this
* list as we go. This list will be put in the kernel's
* rtas_firmware_flash_list global var once it is fully read.
*
* For convenience as we build the list we use virtual addrs,
* we do not fill in the version number, and the length field
* is treated as the number of entries currently in the block
* (i.e. not a byte count). This is all fixed on release.
*/
static
struct
flash_block_list
*
flist
;
static
char
*
flash_msg
;
static
int
flash_possible
;
static
int
rtas_flash_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
((
file
->
f_mode
&
FMODE_WRITE
)
&&
flash_possible
)
{
if
(
flist
)
return
-
EBUSY
;
flist
=
(
struct
flash_block_list
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
flist
)
return
-
ENOMEM
;
}
return
0
;
}
/* Do simple sanity checks on the flash image. */
static
int
flash_list_valid
(
struct
flash_block_list
*
flist
)
{
struct
flash_block_list
*
f
;
int
i
;
unsigned
long
block_size
,
image_size
;
flash_msg
=
NULL
;
/* Paranoid self test here. We also collect the image size. */
image_size
=
0
;
for
(
f
=
flist
;
f
;
f
=
f
->
next
)
{
for
(
i
=
0
;
i
<
f
->
num_blocks
;
i
++
)
{
if
(
f
->
blocks
[
i
].
data
==
NULL
)
{
flash_msg
=
"error: internal error null data
\n
"
;
return
0
;
}
block_size
=
f
->
blocks
[
i
].
length
;
if
(
block_size
<=
0
||
block_size
>
PAGE_SIZE
)
{
flash_msg
=
"error: internal error bad length
\n
"
;
return
0
;
}
image_size
+=
block_size
;
}
}
if
(
image_size
<
(
256
<<
10
))
{
if
(
image_size
<
2
)
flash_msg
=
NULL
;
/* allow "clear" of image */
else
flash_msg
=
"error: flash image short
\n
"
;
return
0
;
}
printk
(
KERN_INFO
"FLASH: flash image with %ld bytes stored for hardware flash on reboot
\n
"
,
image_size
);
return
1
;
}
static
void
free_flash_list
(
struct
flash_block_list
*
f
)
{
struct
flash_block_list
*
next
;
int
i
;
while
(
f
)
{
for
(
i
=
0
;
i
<
f
->
num_blocks
;
i
++
)
free_page
((
unsigned
long
)(
f
->
blocks
[
i
].
data
));
next
=
f
->
next
;
free_page
((
unsigned
long
)
f
);
f
=
next
;
}
}
static
int
rtas_flash_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
flist
)
{
/* Always clear saved list on a new attempt. */
if
(
rtas_firmware_flash_list
.
next
)
{
free_flash_list
(
rtas_firmware_flash_list
.
next
);
rtas_firmware_flash_list
.
next
=
NULL
;
}
if
(
flash_list_valid
(
flist
))
rtas_firmware_flash_list
.
next
=
flist
;
else
free_flash_list
(
flist
);
flist
=
NULL
;
}
return
0
;
}
/* Reading the proc file will show status (not the firmware contents) */
static
ssize_t
rtas_flash_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
error
;
char
*
msg
;
int
msglen
;
if
(
!
flash_possible
)
{
msg
=
"error: this partition does not have service authority
\n
"
;
}
else
if
(
flist
)
{
msg
=
"info: this file is busy for write by some process
\n
"
;
}
else
if
(
flash_msg
)
{
msg
=
flash_msg
;
/* message from last flash attempt */
}
else
if
(
rtas_firmware_flash_list
.
next
)
{
msg
=
"ready: firmware image ready for flash on reboot
\n
"
;
}
else
{
msg
=
"info: no firmware image for flash
\n
"
;
}
msglen
=
strlen
(
msg
);
if
(
msglen
>
count
)
msglen
=
count
;
if
(
ppos
&&
*
ppos
!=
0
)
return
0
;
/* be cheap */
error
=
verify_area
(
VERIFY_WRITE
,
buf
,
msglen
);
if
(
error
)
return
-
EINVAL
;
copy_to_user
(
buf
,
msg
,
msglen
);
if
(
ppos
)
*
ppos
=
msglen
;
return
msglen
;
}
/* We could be much more efficient here. But to keep this function
* simple we allocate a page to the block list no matter how small the
* count is. If the system is low on memory it will be just as well
* that we fail....
*/
static
ssize_t
rtas_flash_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
off
)
{
size_t
len
=
count
;
char
*
p
;
int
next_free
;
struct
flash_block_list
*
fl
=
flist
;
if
(
!
flash_possible
||
len
==
0
)
return
len
;
/* discard data */
while
(
fl
->
next
)
fl
=
fl
->
next
;
/* seek to last block_list for append */
next_free
=
fl
->
num_blocks
;
if
(
next_free
==
FLASH_BLOCKS_PER_NODE
)
{
/* Need to allocate another block_list */
fl
->
next
=
(
struct
flash_block_list
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
fl
->
next
)
return
-
ENOMEM
;
fl
=
fl
->
next
;
next_free
=
0
;
}
if
(
len
>
PAGE_SIZE
)
len
=
PAGE_SIZE
;
p
=
(
char
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
p
)
return
-
ENOMEM
;
if
(
copy_from_user
(
p
,
buffer
,
len
))
{
free_page
((
unsigned
long
)
p
);
return
-
EFAULT
;
}
fl
->
blocks
[
next_free
].
data
=
p
;
fl
->
blocks
[
next_free
].
length
=
len
;
fl
->
num_blocks
++
;
return
len
;
}
static
struct
file_operations
rtas_flash_operations
=
{
read:
rtas_flash_read
,
write:
rtas_flash_write
,
open:
rtas_flash_open
,
release:
rtas_flash_release
,
};
int
__init
rtas_flash_init
(
void
)
{
struct
proc_dir_entry
*
ent
=
NULL
;
if
(
!
rtas_proc_dir
)
{
printk
(
KERN_WARNING
"rtas proc dir does not already exist"
);
return
-
ENOENT
;
}
if
(
rtas_token
(
"ibm,update-flash-64-and-reboot"
)
!=
RTAS_UNKNOWN_SERVICE
)
flash_possible
=
1
;
if
((
ent
=
create_proc_entry
(
FIRMWARE_FLASH_NAME
,
S_IRUSR
|
S_IWUSR
,
rtas_proc_dir
))
!=
NULL
)
{
ent
->
nlink
=
1
;
ent
->
proc_fops
=
&
rtas_flash_operations
;
ent
->
owner
=
THIS_MODULE
;
}
return
0
;
}
void
__exit
rtas_flash_cleanup
(
void
)
{
if
(
!
rtas_proc_dir
)
return
;
remove_proc_entry
(
FIRMWARE_FLASH_NAME
,
rtas_proc_dir
);
}
module_init
(
rtas_flash_init
);
module_exit
(
rtas_flash_cleanup
);
MODULE_LICENSE
(
"GPL"
);
include/asm-ppc64/rtas.h
View file @
9510ba13
...
...
@@ -2,6 +2,7 @@
#define _PPC64_RTAS_H
#include <linux/spinlock.h>
#include <asm/page.h>
/*
* Definitions for talking to the RTAS on CHRP machines.
...
...
@@ -128,6 +129,29 @@ struct rtas_error_log {
unsigned
char
buffer
[
1
];
/* allocated by klimit bump */
};
struct
flash_block
{
char
*
data
;
unsigned
long
length
;
};
/* This struct is very similar but not identical to
* that needed by the rtas flash update.
* All we need to do for rtas is rewrite num_blocks
* into a version/length and translate the pointers
* to absolute.
*/
#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
struct
flash_block_list
{
unsigned
long
num_blocks
;
struct
flash_block_list
*
next
;
struct
flash_block
blocks
[
FLASH_BLOCKS_PER_NODE
];
};
struct
flash_block_list_header
{
/* just the header of flash_block_list */
unsigned
long
num_blocks
;
struct
flash_block_list
*
next
;
};
extern
struct
flash_block_list_header
rtas_firmware_flash_list
;
extern
struct
rtas_t
rtas
;
extern
void
enter_rtas
(
struct
rtas_args
*
);
...
...
@@ -140,4 +164,7 @@ extern void rtas_restart(char *cmd);
extern
void
rtas_power_off
(
void
);
extern
void
rtas_halt
(
void
);
extern
struct
proc_dir_entry
*
rtas_proc_dir
;
#endif
/* _PPC64_RTAS_H */
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