ppc64: Update the nvram driver to deal with PowerMac G5

This involves making the actual read/write routines be indirect
through ppc_md, and adding the various nvram partition types
used on a PowerMac.
parent d93aef75
......@@ -178,6 +178,10 @@ chrp_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
#ifdef CONFIG_PPC_PSERIES
pSeries_nvram_init();
#endif
}
void __init
......@@ -272,9 +276,6 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.progress = chrp_progress;
ppc_md.nvram_read = pSeries_nvram_read;
ppc_md.nvram_write = pSeries_nvram_write;
/* Build up the firmware_features bitmask field
* using contents of device-tree/ibm,hypertas-functions.
* Ultimately this functionality may be moved into prom.c prom_init().
......
......@@ -9,6 +9,10 @@
* /dev/nvram driver for PPC64
*
* This perhaps should live in drivers/char
*
* TODO: Split the /dev/nvram part (that one can use
* drivers/char/generic_nvram.c) from the arch & partition
* parsing code.
*/
#include <linux/module.h>
......@@ -34,16 +38,10 @@ static int nvram_scan_partitions(void);
static int nvram_setup_partition(void);
static int nvram_create_os_partition(void);
static int nvram_remove_os_partition(void);
static unsigned char nvram_checksum(struct nvram_header *p);
static int nvram_write_header(struct nvram_partition * part);
static unsigned int nvram_size;
static unsigned int nvram_fetch, nvram_store;
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
static struct nvram_partition * nvram_part;
static long nvram_error_log_index = -1;
static long nvram_error_log_size = 0;
static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
volatile int no_more_logging = 1; /* Until we initialize everything,
* make sure we don't try logging
......@@ -58,12 +56,18 @@ struct err_log_info {
static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
{
int size;
if (ppc_md.nvram_size == NULL)
return -ENODEV;
size = ppc_md.nvram_size();
switch (origin) {
case 1:
offset += file->f_pos;
break;
case 2:
offset += nvram_size;
offset += size;
break;
}
if (offset < 0)
......@@ -78,13 +82,18 @@ static ssize_t dev_nvram_read(struct file *file, char *buf,
{
ssize_t len;
char *tmp_buffer;
int size;
if (ppc_md.nvram_size == NULL)
return -ENODEV;
size = ppc_md.nvram_size();
if (verify_area(VERIFY_WRITE, buf, count))
return -EFAULT;
if (*ppos >= nvram_size)
if (*ppos >= size)
return 0;
if (count > nvram_size)
count = nvram_size;
if (count > size)
count = size;
tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
if (!tmp_buffer) {
......@@ -113,13 +122,18 @@ static ssize_t dev_nvram_write(struct file *file, const char *buf,
{
ssize_t len;
char * tmp_buffer;
int size;
if (ppc_md.nvram_size == NULL)
return -ENODEV;
size = ppc_md.nvram_size();
if (verify_area(VERIFY_READ, buf, count))
return -EFAULT;
if (*ppos >= nvram_size)
if (*ppos >= size)
return 0;
if (count > nvram_size)
count = nvram_size;
if (count > size)
count = size;
tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
if (!tmp_buffer) {
......@@ -145,6 +159,28 @@ static ssize_t dev_nvram_write(struct file *file, const char *buf,
static int dev_nvram_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
switch(cmd) {
#ifdef CONFIG_PPC_PMAC
case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
case IOC_NVRAM_GET_OFFSET: {
int part, offset;
if (systemcfg->platform != PLATFORM_POWERMAC)
return -EINVAL;
if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
return -EFAULT;
if (part < pmac_nvram_OF || part > pmac_nvram_NR)
return -EINVAL;
offset = pmac_get_partition(part);
if (offset < 0)
return offset;
if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
return -EFAULT;
return 0;
}
#endif /* CONFIG_PPC_PMAC */
}
return -EINVAL;
}
......@@ -162,259 +198,75 @@ static struct miscdevice nvram_dev = {
&nvram_fops
};
ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
{
unsigned int i;
unsigned long len, done;
unsigned long flags;
char *p = buf;
if (*index >= nvram_size)
return 0;
i = *index;
if (i + count > nvram_size)
count = nvram_size - i;
spin_lock_irqsave(&nvram_lock, flags);
for (; count != 0; count -= len) {
len = count;
if (len > NVRW_CNT)
len = NVRW_CNT;
if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),
len) != 0) || len != done) {
spin_unlock_irqrestore(&nvram_lock, flags);
return -EIO;
}
memcpy(p, nvram_buf, len);
p += len;
i += len;
}
spin_unlock_irqrestore(&nvram_lock, flags);
static void nvram_print_partitions(char * label)
{
struct list_head * p;
struct nvram_partition * tmp_part;
*index = i;
return p - buf;
printk(KERN_WARNING "--------%s---------\n", label);
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
list_for_each(p, &nvram_part->partition) {
tmp_part = list_entry(p, struct nvram_partition, partition);
printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n",
tmp_part->index, tmp_part->header.signature,
tmp_part->header.checksum, tmp_part->header.length,
tmp_part->header.name);
}
}
ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)
{
unsigned int i;
unsigned long len, done;
unsigned long flags;
const char *p = buf;
if (*index >= nvram_size)
return 0;
i = *index;
if (i + count > nvram_size)
count = nvram_size - i;
spin_lock_irqsave(&nvram_lock, flags);
for (; count != 0; count -= len) {
len = count;
if (len > NVRW_CNT)
len = NVRW_CNT;
memcpy(nvram_buf, p, len);
if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),
len) != 0) || len != done) {
spin_unlock_irqrestore(&nvram_lock, flags);
return -EIO;
}
p += len;
i += len;
}
spin_unlock_irqrestore(&nvram_lock, flags);
*index = i;
return p - buf;
}
int __init nvram_init(void)
static int nvram_write_header(struct nvram_partition * part)
{
struct device_node *nvram;
unsigned int *nbytes_p, proplen;
int error;
loff_t tmp_index;
int rc;
if ((nvram = of_find_node_by_type(NULL, "nvram")) != NULL) {
nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
if (nbytes_p && proplen == sizeof(unsigned int)) {
nvram_size = *nbytes_p;
} else {
return -EIO;
}
}
nvram_fetch = rtas_token("nvram-fetch");
nvram_store = rtas_token("nvram-store");
printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
of_node_put(nvram);
rc = misc_register(&nvram_dev);
/* If we don't know how big NVRAM is then we shouldn't touch
the nvram partitions */
if (nvram == NULL) {
return rc;
}
/* initialize our anchor for the nvram partition list */
nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
if (!nvram_part) {
printk(KERN_ERR "nvram_init: Failed kmalloc\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&nvram_part->partition);
/* Get all the NVRAM partitions */
error = nvram_scan_partitions();
if (error) {
printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
return error;
}
if(nvram_setup_partition())
printk(KERN_WARNING "nvram_init: Could not find nvram partition"
" for nvram buffered error logging.\n");
#ifdef DEBUG_NVRAM
nvram_print_partitions("NVRAM Partitions");
#endif
tmp_index = part->index;
rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index);
return rc;
return rc;
}
void __exit nvram_cleanup(void)
{
misc_deregister( &nvram_dev );
}
static int nvram_scan_partitions(void)
static unsigned char nvram_checksum(struct nvram_header *p)
{
loff_t cur_index = 0;
struct nvram_header phead;
struct nvram_partition * tmp_part;
unsigned char c_sum;
char * header;
long size;
header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
if (!header) {
printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
return -ENOMEM;
}
while (cur_index < nvram_size) {
size = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
if (size != NVRAM_HEADER_LEN) {
printk(KERN_ERR "nvram_scan_partitions: Error parsing "
"nvram partitions\n");
kfree(header);
return size;
}
cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
memcpy(&phead, header, NVRAM_HEADER_LEN);
c_sum = nvram_checksum(&phead);
if (c_sum != phead.checksum)
printk(KERN_WARNING "WARNING: nvram partition checksum "
"was %02x, should be %02x!\n", phead.checksum, c_sum);
tmp_part = (struct nvram_partition *)
kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
if (!tmp_part) {
printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
kfree(header);
return -ENOMEM;
}
memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
tmp_part->index = cur_index;
list_add_tail(&tmp_part->partition, &nvram_part->partition);
cur_index += phead.length * NVRAM_BLOCK_LEN;
}
unsigned int c_sum, c_sum2;
unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
kfree(header);
return 0;
/* The sum may have spilled into the 3rd byte. Fold it back. */
c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
/* The sum cannot exceed 2 bytes. Fold it into a checksum */
c_sum2 = (c_sum >> 8) + (c_sum << 8);
c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
return c_sum;
}
/* nvram_setup_partition
*
* This will setup the partition we need for buffering the
* error logs and cleanup partitions if needed.
*
* The general strategy is the following:
* 1.) If there is ppc64,linux partition large enough then use it.
* 2.) If there is not a ppc64,linux partition large enough, search
* for a free partition that is large enough.
* 3.) If there is not a free partition large enough remove
* _all_ OS partitions and consolidate the space.
* 4.) Will first try getting a chunk that will satisfy the maximum
* error log size (NVRAM_MAX_REQ).
* 5.) If the max chunk cannot be allocated then try finding a chunk
* that will satisfy the minum needed (NVRAM_MIN_REQ).
/*
* Find an nvram partition, sig can be 0 for any
* partition or name can be NULL for any name, else
* tries to match both
*/
static int nvram_setup_partition(void)
struct nvram_partition *nvram_find_partition(int sig, const char *name)
{
struct list_head * p;
struct nvram_partition * part;
int rc;
struct list_head * p;
/* see if we have an OS partition that meets our needs.
will try getting the max we need. If not we'll delete
partitions and try again. */
list_for_each(p, &nvram_part->partition) {
part = list_entry(p, struct nvram_partition, partition);
if (part->header.signature != NVRAM_SIG_OS)
continue;
if (strcmp(part->header.name, "ppc64,linux"))
if (sig && part->header.signature != sig)
continue;
if (part->header.length >= NVRAM_MIN_REQ) {
/* found our partition */
nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
nvram_error_log_size = ((part->header.length - 1) *
NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
return 0;
}
}
/* try creating a partition with the free space we have */
rc = nvram_create_os_partition();
if (!rc) {
return 0;
}
/* need to free up some space */
rc = nvram_remove_os_partition();
if (rc) {
return rc;
}
/* create a partition in this new space */
rc = nvram_create_os_partition();
if (rc) {
printk(KERN_ERR "nvram_create_os_partition: Could not find a "
"NVRAM partition large enough\n");
return rc;
if (name && 0 != strncmp(name, part->header.name, 12))
continue;
return part;
}
return 0;
return NULL;
}
EXPORT_SYMBOL(nvram_find_partition);
static int nvram_remove_os_partition(void)
{
......@@ -572,22 +424,185 @@ static int nvram_create_os_partition(void)
}
void nvram_print_partitions(char * label)
/* nvram_setup_partition
*
* This will setup the partition we need for buffering the
* error logs and cleanup partitions if needed.
*
* The general strategy is the following:
* 1.) If there is ppc64,linux partition large enough then use it.
* 2.) If there is not a ppc64,linux partition large enough, search
* for a free partition that is large enough.
* 3.) If there is not a free partition large enough remove
* _all_ OS partitions and consolidate the space.
* 4.) Will first try getting a chunk that will satisfy the maximum
* error log size (NVRAM_MAX_REQ).
* 5.) If the max chunk cannot be allocated then try finding a chunk
* that will satisfy the minum needed (NVRAM_MIN_REQ).
*/
static int nvram_setup_partition(void)
{
struct list_head * p;
struct nvram_partition * part;
int rc;
/* For now, we don't do any of this on pmac, until I
* have figured out if it's worth killing some unused stuffs
* in our nvram, as Apple defined partitions use pretty much
* all of the space
*/
if (systemcfg->platform == PLATFORM_POWERMAC)
return -ENOSPC;
/* see if we have an OS partition that meets our needs.
will try getting the max we need. If not we'll delete
partitions and try again. */
list_for_each(p, &nvram_part->partition) {
part = list_entry(p, struct nvram_partition, partition);
if (part->header.signature != NVRAM_SIG_OS)
continue;
if (strcmp(part->header.name, "ppc64,linux"))
continue;
if (part->header.length >= NVRAM_MIN_REQ) {
/* found our partition */
nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
nvram_error_log_size = ((part->header.length - 1) *
NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
return 0;
}
}
/* try creating a partition with the free space we have */
rc = nvram_create_os_partition();
if (!rc) {
return 0;
}
/* need to free up some space */
rc = nvram_remove_os_partition();
if (rc) {
return rc;
}
/* create a partition in this new space */
rc = nvram_create_os_partition();
if (rc) {
printk(KERN_ERR "nvram_create_os_partition: Could not find a "
"NVRAM partition large enough\n");
return rc;
}
return 0;
}
static int nvram_scan_partitions(void)
{
loff_t cur_index = 0;
struct nvram_header phead;
struct nvram_partition * tmp_part;
unsigned char c_sum;
char * header;
long size;
int total_size;
if (ppc_md.nvram_size == NULL)
return -ENODEV;
total_size = ppc_md.nvram_size();
printk(KERN_WARNING "--------%s---------\n", label);
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
list_for_each(p, &nvram_part->partition) {
tmp_part = list_entry(p, struct nvram_partition, partition);
printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n",
tmp_part->index, tmp_part->header.signature,
tmp_part->header.checksum, tmp_part->header.length,
tmp_part->header.name);
header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
if (!header) {
printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
return -ENOMEM;
}
while (cur_index < total_size) {
size = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
if (size != NVRAM_HEADER_LEN) {
printk(KERN_ERR "nvram_scan_partitions: Error parsing "
"nvram partitions\n");
kfree(header);
return size;
}
cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
memcpy(&phead, header, NVRAM_HEADER_LEN);
c_sum = nvram_checksum(&phead);
if (c_sum != phead.checksum)
printk(KERN_WARNING "WARNING: nvram partition checksum "
"was %02x, should be %02x!\n", phead.checksum, c_sum);
tmp_part = (struct nvram_partition *)
kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
if (!tmp_part) {
printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
kfree(header);
return -ENOMEM;
}
memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
tmp_part->index = cur_index;
list_add_tail(&tmp_part->partition, &nvram_part->partition);
cur_index += phead.length * NVRAM_BLOCK_LEN;
}
kfree(header);
return 0;
}
static int __init nvram_init(void)
{
int error;
int rc;
if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
return -ENODEV;
rc = misc_register(&nvram_dev);
if (rc != 0) {
printk(KERN_ERR "nvram_init: failed to register device\n");
return rc;
}
/* initialize our anchor for the nvram partition list */
nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
if (!nvram_part) {
printk(KERN_ERR "nvram_init: Failed kmalloc\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&nvram_part->partition);
/* Get all the NVRAM partitions */
error = nvram_scan_partitions();
if (error) {
printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
return error;
}
if(nvram_setup_partition())
printk(KERN_WARNING "nvram_init: Could not find nvram partition"
" for nvram buffered error logging.\n");
#ifdef DEBUG_NVRAM
nvram_print_partitions("NVRAM Partitions");
#endif
return rc;
}
void __exit nvram_cleanup(void)
{
misc_deregister( &nvram_dev );
}
/* nvram_write_error_log
*
* We need to buffer the error logs into nvram to ensure that we have
......@@ -711,30 +726,6 @@ int nvram_clear_error_log()
return 0;
}
static int nvram_write_header(struct nvram_partition * part)
{
loff_t tmp_index;
int rc;
tmp_index = part->index;
rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index);
return rc;
}
static unsigned char nvram_checksum(struct nvram_header *p)
{
unsigned int c_sum, c_sum2;
unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
/* The sum may have spilled into the 3rd byte. Fold it back. */
c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
/* The sum cannot exceed 2 bytes. Fold it into a checksum */
c_sum2 = (c_sum >> 8) + (c_sum << 8);
c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
return c_sum;
}
module_init(nvram_init);
module_exit(nvram_cleanup);
......
......@@ -40,6 +40,7 @@
#include <asm/time.h>
#include <asm/cputable.h>
#include <asm/sections.h>
#include <asm/nvram.h>
extern unsigned long klimit;
/* extern void *stab; */
......@@ -261,6 +262,8 @@ void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
void machine_restart(char *cmd)
{
if (ppc_md.nvram_sync)
ppc_md.nvram_sync();
ppc_md.restart(cmd);
}
......@@ -268,6 +271,8 @@ EXPORT_SYMBOL(machine_restart);
void machine_power_off(void)
{
if (ppc_md.nvram_sync)
ppc_md.nvram_sync();
ppc_md.power_off();
}
......@@ -275,6 +280,8 @@ EXPORT_SYMBOL(machine_power_off);
void machine_halt(void)
{
if (ppc_md.nvram_sync)
ppc_md.nvram_sync();
ppc_md.halt();
}
......
......@@ -94,6 +94,9 @@ struct machdep_calls {
ssize_t (*nvram_write)(char *buf, size_t count, loff_t *index);
ssize_t (*nvram_read)(char *buf, size_t count, loff_t *index);
ssize_t (*nvram_size)(void);
int (*nvram_sync)(void);
#ifdef CONFIG_SMP
/* functions for dealing with other cpus */
......
......@@ -38,12 +38,15 @@
#define NVRAM_SIG_OF 0x50 /* open firmware config */
#define NVRAM_SIG_FW 0x51 /* general firmware */
#define NVRAM_SIG_HW 0x52 /* hardware (VPD) */
#define NVRAM_SIG_FLIP 0x5a /* Apple flip/flop header */
#define NVRAM_SIG_APPL 0x5f /* Apple "system" (???) */
#define NVRAM_SIG_SYS 0x70 /* system env vars */
#define NVRAM_SIG_CFG 0x71 /* config data */
#define NVRAM_SIG_ELOG 0x72 /* error log */
#define NVRAM_SIG_VEND 0x7e /* vendor defined */
#define NVRAM_SIG_FREE 0x7f /* Free space */
#define NVRAM_SIG_OS 0xa0 /* OS defined */
#define NVRAM_SIG_PANIC 0xa1 /* Apple OSX "panic" */
/* If change this size, then change the size of NVNAME_LEN */
struct nvram_header {
......@@ -60,11 +63,53 @@ struct nvram_partition {
};
ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index);
ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index);
int nvram_write_error_log(char * buff, int length, unsigned int err_type);
int nvram_read_error_log(char * buff, int length, unsigned int * err_type);
int nvram_clear_error_log(void);
void nvram_print_partitions(char * label);
extern int nvram_write_error_log(char * buff, int length, unsigned int err_type);
extern int nvram_read_error_log(char * buff, int length, unsigned int * err_type);
extern int nvram_clear_error_log(void);
extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
extern int pSeries_nvram_init(void);
extern int pmac_nvram_init(void);
/* PowerMac specific nvram stuffs */
enum {
pmac_nvram_OF, /* Open Firmware partition */
pmac_nvram_XPRAM, /* MacOS XPRAM partition */
pmac_nvram_NR /* MacOS Name Registry partition */
};
/* Return partition offset in nvram */
extern int pmac_get_partition(int partition);
/* Direct access to XPRAM on PowerMacs */
extern u8 pmac_xpram_read(int xpaddr);
extern void pmac_xpram_write(int xpaddr, u8 data);
/* Synchronize NVRAM */
extern int nvram_sync(void);
/* Some offsets in XPRAM */
#define PMAC_XPRAM_MACHINE_LOC 0xe4
#define PMAC_XPRAM_SOUND_VOLUME 0x08
/* Machine location structure in PowerMac XPRAM */
struct pmac_machine_location {
unsigned int latitude; /* 2+30 bit Fractional number */
unsigned int longitude; /* 2+30 bit Fractional number */
unsigned int delta; /* mix of GMT delta and DLS */
};
/*
* /dev/nvram ioctls
*
* Note that PMAC_NVRAM_GET_OFFSET is still supported, but is
* definitely obsolete. Do not use it if you can avoid it
*/
#define OBSOLETE_PMAC_NVRAM_GET_OFFSET \
_IOWR('p', 0x40, int)
#define IOC_NVRAM_GET_OFFSET _IOWR('p', 0x42, int) /* Get NVRAM partition offset */
#endif /* _PPC64_NVRAM_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment