Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/powermac_nvram/powermac_nvram.c
Show All 28 Lines | |||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | |||||
#include <sys/sx.h> | |||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
static d_open_t powermac_nvram_open; | static d_open_t powermac_nvram_open; | ||||
static d_close_t powermac_nvram_close; | static d_close_t powermac_nvram_close; | ||||
static d_read_t powermac_nvram_read; | static d_read_t powermac_nvram_read; | ||||
static d_write_t powermac_nvram_write; | static d_write_t powermac_nvram_write; | ||||
static struct cdevsw powermac_nvram_cdevsw = { | static struct cdevsw powermac_nvram_cdevsw = { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_flags = D_NEEDGIANT, | |||||
.d_open = powermac_nvram_open, | .d_open = powermac_nvram_open, | ||||
.d_close = powermac_nvram_close, | .d_close = powermac_nvram_close, | ||||
.d_read = powermac_nvram_read, | .d_read = powermac_nvram_read, | ||||
.d_write = powermac_nvram_write, | .d_write = powermac_nvram_write, | ||||
.d_name = "powermac_nvram", | .d_name = "powermac_nvram", | ||||
}; | }; | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | powermac_nvram_attach(device_t dev) | ||||
sc->sc_bank = (gen0 > gen1) ? sc->sc_bank0 : sc->sc_bank1; | sc->sc_bank = (gen0 > gen1) ? sc->sc_bank0 : sc->sc_bank1; | ||||
bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); | bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); | ||||
sc->sc_cdev = make_dev(&powermac_nvram_cdevsw, 0, 0, 0, 0600, | sc->sc_cdev = make_dev(&powermac_nvram_cdevsw, 0, 0, 0, 0600, | ||||
"powermac_nvram"); | "powermac_nvram"); | ||||
sc->sc_cdev->si_drv1 = sc; | sc->sc_cdev->si_drv1 = sc; | ||||
sx_init(&sc->sc_lock, "powermac_nvram"); | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_detach(device_t dev) | powermac_nvram_detach(device_t dev) | ||||
{ | { | ||||
struct powermac_nvram_softc *sc; | struct powermac_nvram_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if ((void *)sc->sc_bank0 != NULL) | if ((void *)sc->sc_bank0 != NULL) | ||||
pmap_unmapdev(sc->sc_bank0, NVRAM_SIZE * 2); | pmap_unmapdev(sc->sc_bank0, NVRAM_SIZE * 2); | ||||
if (sc->sc_cdev != NULL) | if (sc->sc_cdev != NULL) | ||||
destroy_dev(sc->sc_cdev); | destroy_dev(sc->sc_cdev); | ||||
sx_destroy(&sc->sc_lock); | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td) | powermac_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td) | ||||
{ | { | ||||
struct powermac_nvram_softc *sc = dev->si_drv1; | struct powermac_nvram_softc *sc = dev->si_drv1; | ||||
int err; | |||||
err = 0; | |||||
sx_xlock(&sc->sc_lock); | |||||
if (sc->sc_isopen) | if (sc->sc_isopen) | ||||
return EBUSY; | err = EBUSY; | ||||
else | |||||
sc->sc_isopen = 1; | sc->sc_isopen = 1; | ||||
sc->sc_rpos = sc->sc_wpos = 0; | sc->sc_rpos = sc->sc_wpos = 0; | ||||
sx_xunlock(&sc->sc_lock); | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td) | powermac_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td) | ||||
{ | { | ||||
struct powermac_nvram_softc *sc = dev->si_drv1; | struct powermac_nvram_softc *sc = dev->si_drv1; | ||||
struct core99_header *header; | struct core99_header *header; | ||||
vm_offset_t bank; | vm_offset_t bank; | ||||
sx_xlock(&sc->sc_lock); | |||||
if (sc->sc_wpos != sizeof(sc->sc_data)) { | if (sc->sc_wpos != sizeof(sc->sc_data)) { | ||||
/* Short write, restore in-memory copy */ | /* Short write, restore in-memory copy */ | ||||
bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); | bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); | ||||
sc->sc_isopen = 0; | sc->sc_isopen = 0; | ||||
sx_xunlock(&sc->sc_lock); | |||||
return 0; | return 0; | ||||
} | } | ||||
header = (struct core99_header *)sc->sc_data; | header = (struct core99_header *)sc->sc_data; | ||||
header->generation = ((struct core99_header *)sc->sc_bank)->generation; | header->generation = ((struct core99_header *)sc->sc_bank)->generation; | ||||
header->generation++; | header->generation++; | ||||
header->chrp_header.signature = CORE99_SIGNATURE; | header->chrp_header.signature = CORE99_SIGNATURE; | ||||
header->adler_checksum = | header->adler_checksum = | ||||
adler_checksum((uint8_t *)&(header->generation), | adler_checksum((uint8_t *)&(header->generation), | ||||
NVRAM_SIZE - offsetof(struct core99_header, generation)); | NVRAM_SIZE - offsetof(struct core99_header, generation)); | ||||
header->chrp_header.chrp_checksum = chrp_checksum(header->chrp_header.signature, | header->chrp_header.chrp_checksum = chrp_checksum(header->chrp_header.signature, | ||||
(uint8_t *)&(header->chrp_header.length), | (uint8_t *)&(header->chrp_header.length), | ||||
(uint8_t *)&(header->adler_checksum)); | (uint8_t *)&(header->adler_checksum)); | ||||
bank = (sc->sc_bank == sc->sc_bank0) ? sc->sc_bank1 : sc->sc_bank0; | bank = (sc->sc_bank == sc->sc_bank0) ? sc->sc_bank1 : sc->sc_bank0; | ||||
if (erase_bank(sc->sc_dev, (uint8_t *)bank) != 0 || | if (erase_bank(sc->sc_dev, (uint8_t *)bank) != 0 || | ||||
write_bank(sc->sc_dev, (uint8_t *)bank, sc->sc_data) != 0) { | write_bank(sc->sc_dev, (uint8_t *)bank, sc->sc_data) != 0) { | ||||
sc->sc_isopen = 0; | sc->sc_isopen = 0; | ||||
sx_xunlock(&sc->sc_lock); | |||||
return ENOSPC; | return ENOSPC; | ||||
} | } | ||||
sc->sc_bank = bank; | sc->sc_bank = bank; | ||||
sc->sc_isopen = 0; | sc->sc_isopen = 0; | ||||
sx_xunlock(&sc->sc_lock); | |||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_read(struct cdev *dev, struct uio *uio, int ioflag) | powermac_nvram_read(struct cdev *dev, struct uio *uio, int ioflag) | ||||
{ | { | ||||
int rv, amnt, data_available; | int rv, amnt, data_available; | ||||
struct powermac_nvram_softc *sc = dev->si_drv1; | struct powermac_nvram_softc *sc = dev->si_drv1; | ||||
rv = 0; | rv = 0; | ||||
sx_xlock(&sc->sc_lock); | |||||
while (uio->uio_resid > 0) { | while (uio->uio_resid > 0) { | ||||
data_available = sizeof(sc->sc_data) - sc->sc_rpos; | data_available = sizeof(sc->sc_data) - sc->sc_rpos; | ||||
if (data_available > 0) { | if (data_available > 0) { | ||||
amnt = MIN(uio->uio_resid, data_available); | amnt = MIN(uio->uio_resid, data_available); | ||||
rv = uiomove((void *)(sc->sc_data + sc->sc_rpos), | rv = uiomove((void *)(sc->sc_data + sc->sc_rpos), | ||||
amnt, uio); | amnt, uio); | ||||
if (rv != 0) | if (rv != 0) | ||||
break; | break; | ||||
sc->sc_rpos += amnt; | sc->sc_rpos += amnt; | ||||
} else { | } else { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
sx_xunlock(&sc->sc_lock); | |||||
return rv; | return rv; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_write(struct cdev *dev, struct uio *uio, int ioflag) | powermac_nvram_write(struct cdev *dev, struct uio *uio, int ioflag) | ||||
{ | { | ||||
int rv, amnt, data_available; | int rv, amnt, data_available; | ||||
struct powermac_nvram_softc *sc = dev->si_drv1; | struct powermac_nvram_softc *sc = dev->si_drv1; | ||||
if (sc->sc_wpos >= sizeof(sc->sc_data)) | if (sc->sc_wpos >= sizeof(sc->sc_data)) | ||||
return EINVAL; | return EINVAL; | ||||
rv = 0; | rv = 0; | ||||
sx_xlock(&sc->sc_lock); | |||||
while (uio->uio_resid > 0) { | while (uio->uio_resid > 0) { | ||||
data_available = sizeof(sc->sc_data) - sc->sc_wpos; | data_available = sizeof(sc->sc_data) - sc->sc_wpos; | ||||
if (data_available > 0) { | if (data_available > 0) { | ||||
amnt = MIN(uio->uio_resid, data_available); | amnt = MIN(uio->uio_resid, data_available); | ||||
rv = uiomove((void *)(sc->sc_data + sc->sc_wpos), | rv = uiomove((void *)(sc->sc_data + sc->sc_wpos), | ||||
amnt, uio); | amnt, uio); | ||||
if (rv != 0) | if (rv != 0) | ||||
break; | break; | ||||
sc->sc_wpos += amnt; | sc->sc_wpos += amnt; | ||||
} else { | } else { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
sx_xunlock(&sc->sc_lock); | |||||
return rv; | return rv; | ||||
} | } | ||||
static int | static int | ||||
powermac_nvram_check(void *data) | powermac_nvram_check(void *data) | ||||
{ | { | ||||
struct core99_header *header; | struct core99_header *header; | ||||
▲ Show 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
erase_bank(device_t dev, uint8_t *bank) | erase_bank(device_t dev, uint8_t *bank) | ||||
{ | { | ||||
struct powermac_nvram_softc *sc; | struct powermac_nvram_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sx_assert(&sc->sc_lock, SA_XLOCKED); | |||||
if (sc->sc_type == FLASH_TYPE_AMD) | if (sc->sc_type == FLASH_TYPE_AMD) | ||||
return (erase_bank_amd(dev, bank)); | return (erase_bank_amd(dev, bank)); | ||||
else | else | ||||
return (erase_bank_sm(dev, bank)); | return (erase_bank_sm(dev, bank)); | ||||
} | } | ||||
static int | static int | ||||
write_bank(device_t dev, uint8_t *bank, uint8_t *data) | write_bank(device_t dev, uint8_t *bank, uint8_t *data) | ||||
{ | { | ||||
struct powermac_nvram_softc *sc; | struct powermac_nvram_softc *sc; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sx_assert(&sc->sc_lock, SA_XLOCKED); | |||||
if (sc->sc_type == FLASH_TYPE_AMD) | if (sc->sc_type == FLASH_TYPE_AMD) | ||||
return (write_bank_amd(dev, bank, data)); | return (write_bank_amd(dev, bank, data)); | ||||
else | else | ||||
return (write_bank_sm(dev, bank, data)); | return (write_bank_sm(dev, bank, data)); | ||||
} | } |