D: SRM environment driver (for Alpha systems)
P: 1024D/8399E1BB 250D 3BCF 7127 0D8C A444 A961 1DBD 5E75 8399 E1BB
+N: Thomas Gleixner
+E: tglx@linutronix.de
+D: NAND flash hardware support, JFFS2 on NAND flash
+
N: Richard E. Gooch
E: rgooch@atnf.csiro.au
D: parent process death signal to children
used to change the file attributes on hugetlbfs.
Also, it is important to note that no such mount command is required if the
-applications are going to use only shmat/shmget system calls. Users who
-wish to use hugetlb page via shared memory segment should be a member of
-a supplementary group and system admin needs to configure that gid into
-/proc/sys/vm/hugetlb_shm_group. It is possible for same or different
-applications to use any combination of mmaps and shm* calls. Though the
-mount of filesystem will be required for using mmaps.
+applications are going to use only shmat/shmget system calls. It is possible
+for same or different applications to use any combination of mmaps and shm*
+calls. Though the mount of filesystem will be required for using mmaps.
/* Example of using hugepage in user application using Sys V shared memory
* system calls. In this example, app is requesting memory of size 256MB that
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 7
-EXTRAVERSION = -1.492-ckrm.E15-vs1.9.1
+EXTRAVERSION = -1.494-ckrm.E15-vs1.9.1.12
NAME=Zonked Quokka
# *DOCUMENTATION*
jmp $31, do_sys_ptrace
.end sys_ptrace
+ .align 4
+ .globl sys_execve
+ .ent sys_execve
+sys_execve:
+ .prologue 0
+ mov $sp, $19
+ jmp $31, do_sys_execve
+.end sys_execve
+
+ .align 4
+ .globl osf_sigprocmask
+ .ent osf_sigprocmask
+osf_sigprocmask:
+ .prologue 0
+ mov $sp, $18
+ jmp $31, do_osf_sigprocmask
+.end osf_sigprocmask
+
.align 4
.globl alpha_ni_syscall
.ent alpha_ni_syscall
/*
* sys_execve() executes a new program.
- *
- * This works due to the alpha calling sequence: the first 6 args
- * are gotten from registers, while the rest is on the stack, so
- * we get a0-a5 for free, and then magically find "struct pt_regs"
- * on the stack for us..
- *
- * Don't do this at home.
*/
asmlinkage int
-sys_execve(char __user *ufilename, char __user * __user *argv,
- char __user * __user *envp,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs)
+do_sys_execve(char __user *ufilename, char __user * __user *argv,
+ char __user * __user *envp, struct pt_regs *regs)
{
int error;
char *filename;
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, ®s);
+ error = do_execve(filename, argv, envp, regs);
putname(filename);
out:
return error;
* operation, as all of this is local to this thread.
*/
asmlinkage unsigned long
-osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
- long a4, long a5, struct pt_regs regs)
+do_osf_sigprocmask(int how, unsigned long newmask, struct pt_regs *regs)
{
unsigned long oldmask = -EINVAL;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
- (®s)->r0 = 0; /* special no error return */
+ regs->r0 = 0; /* special no error return */
}
return oldmask;
}
data8 sys_mq_notify
data8 sys_mq_getsetattr
data8 sys_ni_syscall // reserved for kexec_load
- data8 sys_ni_syscall
+ data8 sys_vserver
data8 sys_ni_syscall // 1270
data8 sys_ni_syscall
data8 sys_ni_syscall
grow = PAGE_SIZE >> PAGE_SHIFT;
if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur
- || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur))
+ || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+ current->rlim[RLIMIT_AS].rlim_cur))
return -ENOMEM;
- if (!vx_vmpages_avail(vma->vm_mm, grow)
+ if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+ ((vma->vm_flags & VM_LOCKED) &&
+ !vx_vmlocked_avail(vma->vm_mm, grow)))
return -ENOMEM;
vma->vm_end += PAGE_SIZE;
// vma->vm_mm->total_vm += grow;
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
+#include <linux/vs_cvirt.h>
#include <asm/branch.h>
#include <asm/cachectl.h>
#include <linux/socket.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/vs_cvirt.h>
#include <asm/ptrace.h>
#include <asm/page.h>
More information is available at:
<http://linux-apus.sourceforge.net/>.
+config KATANA
+ bool "Artesyn-Katana"
+
+config DMV182
+ bool "Dy-4 SVME/DMV-182"
+
config WILLOW
bool "Cogent-Willow"
bool "Force-PowerPMC250"
config EV64260
- bool "Galileo-EV-64260-BP"
+ bool "Marvell-EV64260BP"
+ help
+ Select EV64260 if configuring of a Marvell (formerly Galileo)
+ EV64260BP Evaluation platofm.
config SPRUCE
bool "IBM-Spruce"
depends on PPC_PMAC || PPC_CHRP
default y
+menu "Set bridge options"
+ depends on MV64X60
+
+config MV64X60_BASE
+ hex "Set bridge base used by firmware"
+ default "0xf1000000"
+ help
+ A firmware can leave the base address of the bridge's registers at
+ a non-standard location. If so, set this value to reflect the
+ address of that non-standard location.
+
+config MV64X60_NEW_BASE
+ hex "Set bridge base used by kernel"
+ default "0xf1000000"
+ help
+ If the current base address of the bridge's registers is not where
+ you want it, set this value to the address that you want it moved to.
+
+endmenu
+
config PPC_GEN550
bool
- depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800
+ depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800 || (EV64260 && !MV64X60_MPSC) || DMV182
default y
config FORCE
depends on EV64260
default y
+config MV64360
+ bool
+ depends on KATANA || DMV182
+ default y
+
+config MV64X60
+ bool
+ depends on (GT64260 || MV64360)
+ default y
+
config NONMONARCH_SUPPORT
bool "Enable Non-Monarch Support"
depends on PRPMC800
depends on 8xx
default y
-config SERIAL_CONSOLE_BAUD
- int
- depends on EV64260
- default "115200"
-
config PPCBUG_NVRAM
bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC
default y if PPC_PREP
config SERIAL_TEXT_DEBUG
bool "Support for early boot texts over serial port"
- depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550
+ depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || PPC_GEN550
config PPC_OCP
bool
- depends on IBM_OCP || FSL_OCP
+ depends on IBM_OCP || FSL_OCP || MV64X60
default y
endmenu
void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap);
unsigned char *ISA_io = NULL;
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+ defined(CONFIG_SERIAL_MPSC_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
int tstc(void)
{
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+ defined(CONFIG_SERIAL_MPSC_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
int getc(void)
{
while (1) {
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+ defined(CONFIG_SERIAL_MPSC_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
{
int x,y;
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+ defined(CONFIG_SERIAL_MPSC_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
y = orig_y;
while ( ( c = *s++ ) != '\0' ) {
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+ defined(CONFIG_SERIAL_MPSC_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
end-$(CONFIG_OCOTEA) := ocotea
entrypoint-$(CONFIG_OCOTEA) := 0x01000000
- extra.o-$(CONFIG_EV64260) := direct.o misc-ev64260.o
+ extra.o-$(CONFIG_EV64260) := misc-ev64260.o
end-$(CONFIG_EV64260) := ev64260
cacheflag-$(CONFIG_EV64260) := -include $(clear_L2_L3)
boot-$(CONFIG_8260) += embed_config.o
boot-$(CONFIG_BSEIP) += iic.o
boot-$(CONFIG_MBX) += iic.o pci.o qspan_pci.o
+boot-$(CONFIG_MV64X60) += misc-mv64x60.o
+boot-$(CONFIG_DMV182) += mv64x60_stub.o
boot-$(CONFIG_RPXCLASSIC) += iic.o pci.o qspan_pci.o
boot-$(CONFIG_RPXLITE) += iic.o
# Different boards need different serial implementations.
ifeq ($(CONFIG_SERIAL_CONSOLE),y)
boot-$(CONFIG_8xx) += m8xx_tty.o
boot-$(CONFIG_8260) += m8260_tty.o
-boot-$(CONFIG_GT64260_CONSOLE) += gt64260_tty.o
endif
+boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
+++ /dev/null
-/*
- * arch/ppc/boot/simple/gt64260_tty.c
- *
- * Bootloader version of the embedded MPSC/UART driver for the GT64260[A].
- * Note: Due to 64260A errata, DMA will be used for UART input (via SDMA).
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/* This code assumes that the data cache has been disabled (L1, L2, L3). */
-
-#include <linux/config.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-#include <asm/gt64260_defs.h>
-
-extern void udelay(long);
-static void stop_dma(int chan);
-
-static u32 gt64260_base = EV64260_BRIDGE_REG_BASE; /* base addr of 64260 */
-
-inline unsigned
-gt64260_in_le32(volatile unsigned *addr)
-{
- unsigned ret;
-
- __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
- "r" (addr), "m" (*addr));
- return ret;
-}
-
-inline void
-gt64260_out_le32(volatile unsigned *addr, int val)
-{
- __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
- "r" (val), "r" (addr));
-}
-
-#define GT64260_REG_READ(offs) \
- (gt64260_in_le32((volatile uint *)(gt64260_base + (offs))))
-#define GT64260_REG_WRITE(offs, d) \
- (gt64260_out_le32((volatile uint *)(gt64260_base + (offs)), (int)(d)))
-
-
-static struct {
- u32 sdc;
- u32 sdcm;
- u32 rx_desc;
- u32 rx_buf_ptr;
- u32 scrdp;
- u32 tx_desc;
- u32 sctdp;
- u32 sftdp;
-} sdma_regs;
-
-#define SDMA_REGS_INIT(chan) { \
- sdma_regs.sdc = GT64260_SDMA_##chan##_SDC; \
- sdma_regs.sdcm = GT64260_SDMA_##chan##_SDCM; \
- sdma_regs.rx_desc = GT64260_SDMA_##chan##_RX_DESC; \
- sdma_regs.rx_buf_ptr = GT64260_SDMA_##chan##_RX_BUF_PTR; \
- sdma_regs.scrdp = GT64260_SDMA_##chan##_SCRDP; \
- sdma_regs.tx_desc = GT64260_SDMA_##chan##_TX_DESC; \
- sdma_regs.sctdp = GT64260_SDMA_##chan##_SCTDP; \
- sdma_regs.sftdp = GT64260_SDMA_##chan##_SFTDP; \
-}
-
-typedef struct {
- volatile u16 bufsize;
- volatile u16 bytecnt;
- volatile u32 cmd_stat;
- volatile u32 next_desc_ptr;
- volatile u32 buffer;
-} gt64260_rx_desc_t;
-
-typedef struct {
- volatile u16 bytecnt;
- volatile u16 shadow;
- volatile u32 cmd_stat;
- volatile u32 next_desc_ptr;
- volatile u32 buffer;
-} gt64260_tx_desc_t;
-
-#define MAX_RESET_WAIT 10000
-#define MAX_TX_WAIT 10000
-
-#define RX_NUM_DESC 2
-#define TX_NUM_DESC 2
-
-#define RX_BUF_SIZE 16
-#define TX_BUF_SIZE 16
-
-static gt64260_rx_desc_t rd[RX_NUM_DESC] __attribute__ ((aligned(32)));
-static gt64260_tx_desc_t td[TX_NUM_DESC] __attribute__ ((aligned(32)));
-
-static char rx_buf[RX_NUM_DESC * RX_BUF_SIZE] __attribute__ ((aligned(32)));
-static char tx_buf[TX_NUM_DESC * TX_BUF_SIZE] __attribute__ ((aligned(32)));
-
-static int cur_rd = 0;
-static int cur_td = 0;
-
-
-#define RX_INIT_RDP(rdp) { \
- (rdp)->bufsize = 2; \
- (rdp)->bytecnt = 0; \
- (rdp)->cmd_stat = GT64260_SDMA_DESC_CMDSTAT_L | \
- GT64260_SDMA_DESC_CMDSTAT_F | \
- GT64260_SDMA_DESC_CMDSTAT_O; \
-}
-
-unsigned long
-serial_init(int chan, void *ignored)
-{
- u32 mpsc_adjust, sdma_adjust, brg_bcr;
- int i;
-
- stop_dma(0);
- stop_dma(1);
-
- if (chan != 1) {
- chan = 0; /* default to chan 0 if anything but 1 */
- mpsc_adjust = 0;
- sdma_adjust = 0;
- brg_bcr = GT64260_BRG_0_BCR;
- SDMA_REGS_INIT(0);
- }
- else {
- mpsc_adjust = 0x1000;
- sdma_adjust = 0x2000;
- brg_bcr = GT64260_BRG_1_BCR;
- SDMA_REGS_INIT(1);
- }
-
- /* Set up ring buffers */
- for (i=0; i<RX_NUM_DESC; i++) {
- RX_INIT_RDP(&rd[i]);
- rd[i].buffer = (u32)&rx_buf[i * RX_BUF_SIZE];
- rd[i].next_desc_ptr = (u32)&rd[i+1];
- }
- rd[RX_NUM_DESC - 1].next_desc_ptr = (u32)&rd[0];
-
- for (i=0; i<TX_NUM_DESC; i++) {
- td[i].bytecnt = 0;
- td[i].shadow = 0;
- td[i].buffer = (u32)&tx_buf[i * TX_BUF_SIZE];
- td[i].cmd_stat = GT64260_SDMA_DESC_CMDSTAT_F |
- GT64260_SDMA_DESC_CMDSTAT_L;
- td[i].next_desc_ptr = (u32)&td[i+1];
- }
- td[TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[0];
-
- /* Set MPSC Routing */
- GT64260_REG_WRITE(GT64260_MPSC_MRR, 0x3ffffe38);
- GT64260_REG_WRITE(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
-
- /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
- GT64260_REG_WRITE(GT64260_MPSC_RCRR, 0x00000100);
- GT64260_REG_WRITE(GT64260_MPSC_TCRR, 0x00000100);
-
- /* clear pending interrupts */
- GT64260_REG_WRITE(GT64260_SDMA_INTR_MASK, 0);
-
- GT64260_REG_WRITE(GT64260_SDMA_0_SCRDP + sdma_adjust, &rd[0]);
- GT64260_REG_WRITE(GT64260_SDMA_0_SCTDP + sdma_adjust,
- &td[TX_NUM_DESC - 1]);
- GT64260_REG_WRITE(GT64260_SDMA_0_SFTDP + sdma_adjust,
- &td[TX_NUM_DESC - 1]);
-
- GT64260_REG_WRITE(GT64260_SDMA_0_SDC + sdma_adjust,
- GT64260_SDMA_SDC_RFT | GT64260_SDMA_SDC_SFM |
- GT64260_SDMA_SDC_BLMR | GT64260_SDMA_SDC_BLMT |
- (3 << 12));
-
- /* Set BRG to generate proper baud rate */
- GT64260_REG_WRITE(brg_bcr, ((8 << 18) | (1 << 16) | 36));
-
- /* Put MPSC into UART mode, no null modem, 16x clock mode */
- GT64260_REG_WRITE(GT64260_MPSC_0_MMCRL + mpsc_adjust, 0x000004c4);
- GT64260_REG_WRITE(GT64260_MPSC_0_MMCRH + mpsc_adjust, 0x04400400);
-
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_1 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_9 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_10 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_3 + mpsc_adjust, 4);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_4 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_5 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_6 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_7 + mpsc_adjust, 0);
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_8 + mpsc_adjust, 0);
-
- /* 8 data bits, 1 stop bit */
- GT64260_REG_WRITE(GT64260_MPSC_0_MPCR + mpsc_adjust, (3 << 12));
-
- GT64260_REG_WRITE(GT64260_SDMA_0_SDCM + sdma_adjust,
- GT64260_SDMA_SDCM_ERD);
-
- GT64260_REG_WRITE(GT64260_MPSC_0_CHR_2 + sdma_adjust,
- GT64260_MPSC_UART_CR_EH);
-
- udelay(100);
-
- return (ulong)chan;
-}
-
-static void
-stop_dma(int chan)
-{
- u32 sdma_sdcm = GT64260_SDMA_0_SDCM;
- int i;
-
- if (chan == 1) {
- sdma_sdcm = GT64260_SDMA_1_SDCM;
- }
-
- /* Abort SDMA Rx, Tx */
- GT64260_REG_WRITE(sdma_sdcm,
- GT64260_SDMA_SDCM_AR | GT64260_SDMA_SDCM_STD);
-
- for (i=0; i<MAX_RESET_WAIT; i++) {
- if ((GT64260_REG_READ(sdma_sdcm) & (GT64260_SDMA_SDCM_AR |
- GT64260_SDMA_SDCM_AT)) == 0) break;
- udelay(100);
- }
-
- return;
-}
-
-static int
-wait_for_ownership(void)
-{
- int i;
-
- for (i=0; i<MAX_TX_WAIT; i++) {
- if ((GT64260_REG_READ(sdma_regs.sdcm) &
- GT64260_SDMA_SDCM_TXD) == 0) break;
- udelay(1000);
- }
-
- return (i < MAX_TX_WAIT);
-}
-
-void
-serial_putc(unsigned long com_port, unsigned char c)
-{
- gt64260_tx_desc_t *tdp;
-
- if (wait_for_ownership() == 0) return;
-
- tdp = &td[cur_td];
- if (++cur_td >= TX_NUM_DESC) cur_td = 0;
-
- *(unchar *)(tdp->buffer ^ 7) = c;
- tdp->bytecnt = 1;
- tdp->shadow = 1;
- tdp->cmd_stat = GT64260_SDMA_DESC_CMDSTAT_L |
- GT64260_SDMA_DESC_CMDSTAT_F | GT64260_SDMA_DESC_CMDSTAT_O;
-
- GT64260_REG_WRITE(sdma_regs.sctdp, tdp);
- GT64260_REG_WRITE(sdma_regs.sftdp, tdp);
- GT64260_REG_WRITE(sdma_regs.sdcm,
- GT64260_REG_READ(sdma_regs.sdcm) | GT64260_SDMA_SDCM_TXD);
-
- return;
-}
-
-unsigned char
-serial_getc(unsigned long com_port)
-{
- gt64260_rx_desc_t *rdp;
- unchar c = '\0';
-
- rdp = &rd[cur_rd];
-
- if ((rdp->cmd_stat & (GT64260_SDMA_DESC_CMDSTAT_O |
- GT64260_SDMA_DESC_CMDSTAT_ES)) == 0) {
- c = *(unchar *)(rdp->buffer ^ 7);
- RX_INIT_RDP(rdp);
- if (++cur_rd >= RX_NUM_DESC) cur_rd = 0;
- }
-
- return c;
-}
-
-int
-serial_tstc(unsigned long com_port)
-{
- gt64260_rx_desc_t *rdp;
- int loop_count = 0;
- int rc = 0;
-
- rdp = &rd[cur_rd];
-
- /* Go thru rcv desc's until empty looking for one with data (no error)*/
- while (((rdp->cmd_stat & GT64260_SDMA_DESC_CMDSTAT_O) == 0) &&
- (loop_count++ < RX_NUM_DESC)) {
-
- /* If there was an error, reinit the desc & continue */
- if ((rdp->cmd_stat & GT64260_SDMA_DESC_CMDSTAT_ES) != 0) {
- RX_INIT_RDP(rdp);
- if (++cur_rd >= RX_NUM_DESC) cur_rd = 0;
- rdp = (gt64260_rx_desc_t *)rdp->next_desc_ptr;
- }
- else {
- rc = 1;
- break;
- }
- }
-
- return rc;
-}
-
-void
-serial_close(unsigned long com_port)
-{
- stop_dma(com_port);
- return;
-}
*/
#endif
-#ifdef CONFIG_EV64260
- /* Move 64260's base regs & CS window for external UART */
- bl ev64260_init
+#ifdef CONFIG_MV64X60
+ /* mv64x60 specific hook to do things like moving register base, etc. */
+ bl mv64x60_init
#endif
/* Get the load address.
/*
* arch/ppc/boot/simple/misc-ev64260.S
- *
+ *
* Host bridge init code for the Marvell/Galileo EV-64260-BP evaluation board
* with a GT64260 onboard.
*
* Author: Mark Greer <mgreer@mvista.com>
*
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
*/
#include <asm/ppc_asm.h>
+#include <asm/processor.h>
#include <asm/cache.h>
-#include <asm/gt64260_defs.h>
-
+#include <asm/mv64x60_defs.h>
#include <platforms/ev64260.h>
- .globl ev64260_init
-ev64260_init:
- li r20,0
+ .globl mv64x60_board_init
+mv64x60_board_init:
+ /* DINK doesn't enable 745x timebase, so enable here (Adrian Cox) */
+ mfspr r25,PVR
+ srwi r25,r25,16
+ cmplwi r25,(PVR_7450 >> 16)
+ bne 1f
+ mfspr r25,HID0
+ oris r25,r25,(HID0_TBEN >> 16)
+ mtspr HID0,r25
+1:
+#if (CONFIG_MV64X60_NEW_BASE != CONFIG_MV64X60_BASE)
li r23,20
- /* Relocate galileo's regs */
- addis r25,0,GT64260_INTERNAL_SPACE_DEFAULT_ADDR@h
- ori r25,r25,GT64260_INTERNAL_SPACE_DECODE
- lwbrx r26,0,(r25)
- lis r24,0xffff
- and r26,r26,r24
- addis r24,0,EV64260_BRIDGE_REG_BASE@h
- srw r24,r24,r23
- or r26,r26,r24
- stwbrx r26,0,(r25)
- sync
-
- /* Wait for write to take effect */
- addis r25,0,EV64260_BRIDGE_REG_BASE@h
- ori r25,r25,GT64260_INTERNAL_SPACE_DECODE
-1: lwbrx r24,0,(r25)
- cmpw r24,r26
- bne 1b
-
- /* Change CS2 (UARTS on device module) window */
- addis r25,0,EV64260_BRIDGE_REG_BASE@h
- ori r25,r25,GT64260_CPU_CS_DECODE_2_BOT
+ /*
+ * Change the CS2 window for the UART so that the bootloader
+ * can do I/O thru the UARTs.
+ */
+ addis r25,0,CONFIG_MV64X60_NEW_BASE@h
+ ori r25,r25,MV64x60_CPU2DEV_2_BASE
addis r26,0,EV64260_UART_BASE@h
srw r26,r26,r23
stwbrx r26,0,(r25)
sync
- addis r25,0,EV64260_BRIDGE_REG_BASE@h
- ori r25,r25,GT64260_CPU_CS_DECODE_2_TOP
+ addis r25,0,CONFIG_MV64X60_NEW_BASE@h
+ ori r25,r25,MV64x60_CPU2DEV_2_SIZE
addis r26,0,EV64260_UART_END@h
srw r26,r26,r23
stwbrx r26,0,(r25)
sync
-
+#endif
blr
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+.data
+ .globl mv64x60_console_baud
+mv64x60_console_baud:
+.long EV64260_DEFAULT_BAUD
+
+ .globl mv64x60_mpsc_clk_src
+mv64x60_mpsc_clk_src:
+.long EV64260_MPSC_CLK_SRC
+
+ .globl mv64x60_mpsc_clk_freq
+mv64x60_mpsc_clk_freq:
+.long EV64260_MPSC_CLK_FREQ
+#endif
* user to edit the cmdline or not.
*/
#if (defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
- && !defined(CONFIG_GEMINI)
+ && !defined(CONFIG_GEMINI) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
#define INTERACTIVE_CONSOLE 1
#endif
unsigned long initrd_loc, TotalMemory = 0;
serial_fixups();
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
com_port = serial_init(0, NULL);
#endif
CONFIG_MMU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
CONFIG_KMOD=y
#
-# Platform support
+# Processor
#
-CONFIG_PPC=y
-CONFIG_PPC32=y
CONFIG_6xx=y
# CONFIG_40x is not set
+# CONFIG_44x is not set
# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
# CONFIG_8xx is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_STD_MMU=y
#
-# IBM 4xx options
+# Platform options
#
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
# CONFIG_PPC_MULTIPLATFORM is not set
# CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
# CONFIG_PCORE is not set
# CONFIG_POWERPMC250 is not set
CONFIG_EV64260=y
# CONFIG_K2 is not set
# CONFIG_PAL4 is not set
# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+
+#
+# Set bridge base address
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xfbe00000
+CONFIG_PPC_GEN550=y
CONFIG_GT64260=y
+CONFIG_MV64X60=y
CONFIG_SERIAL_CONSOLE_BAUD=115200
# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-# CONFIG_CPU_FREQ is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 ip=on"
#
-# General setup
+# Bus options
#
-# CONFIG_HIGHMEM is not set
+CONFIG_GENERIC_ISA_DMA=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,115200 ip=on"
#
# Advanced setup
CONFIG_TASK_SIZE=0x80000000
CONFIG_BOOT_LOAD=0x00800000
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
#
# Plug and Play support
#
-# CONFIG_PNP is not set
#
# Block devices
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
#
-# Multi-device support (RAID and LVM)
+# ATA/ATAPI/MFM/RLL support
#
-# CONFIG_MD is not set
+# CONFIG_IDE is not set
#
-# ATA/IDE/MFM/RLL support
+# SCSI device support
#
-# CONFIG_IDE is not set
+# CONFIG_SCSI is not set
#
-# SCSI support
+# Multi-device support (RAID and LVM)
#
-# CONFIG_SCSI is not set
+# CONFIG_MD is not set
#
# Fusion MPT device support
#
#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
#
# CONFIG_IEEE1394 is not set
#
# CONFIG_I2O is not set
+#
+# Macintosh device drivers
+#
+
#
# Networking support
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
+# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
-CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
# CONFIG_OAKNET is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
#
# Tulip family network device support
#
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
# CONFIG_DGRS is not set
CONFIG_EEPRO100=y
# CONFIG_EEPRO100_PIO is not set
# Ethernet (10000 Mbit)
#
# CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_S2IO is not set
#
-# Wireless LAN (non-hamradio)
+# Token Ring devices
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
#
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
#
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
#
# ISDN subsystem
#
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
#
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
#
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
#
# Input device support
#
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
#
# Userland interfaces
#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
#
# Input Device Drivers
#
-
-#
-# Macintosh device drivers
-#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
#
# Character devices
#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_MPSC is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=m
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_QIC02_TAPE is not set
#
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
#
# Multimedia devices
#
# CONFIG_DVB is not set
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
#
# File systems
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
CONFIG_DEVFS_FS=y
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
# CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
CONFIG_MSDOS_PARTITION=y
#
-# Sound
+# Native Language Support
#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
#
# Library routines
#
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
#
# Kernel hacking
#
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_PPC_OCP=y
#
# Security options
#include <linux/utsname.h>
#include <linux/file.h>
#include <linux/unistd.h>
+#include <linux/vs_cvirt.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
obj-$(CONFIG_EST8260) += est8260_setup.o
obj-$(CONFIG_PQ2ADS) += pq2ads_setup.o
obj-$(CONFIG_TQM8260) += tqm8260_setup.o
-obj-$(CONFIG_EV64260) += ev64260_setup.o
+obj-$(CONFIG_EV64260) += ev64260.o
+obj-$(CONFIG_DMV182) += dmv182.o
obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o
obj-$(CONFIG_K2) += k2.o
obj-$(CONFIG_LOPEC) += lopec_setup.o lopec_pci.o
/*
* arch/ppc/platforms/ev64260.h
- *
+ *
* Definitions for Marvell/Galileo EV-64260-BP Evaluation Board.
*
* Author: Mark A. Greer <mgreer@mvista.com>
*
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
/*
- * The GT64260 has 2 PCI buses each with 1 window from the CPU bus to
+ * The MV64x60 has 2 PCI buses each with 1 window from the CPU bus to
* PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
* We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 1MB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ * 0xfc000000-0xffffffff - External FLASH on device module
+ * 0xfbf00000-0xfbffffff - Embedded (on board) FLASH
+ * 0xfbe00000-0xfbefffff - GT64260 Registers (preferably)
+ * but really a config option
+ * 0xfbd00000-0xfbdfffff - External SRAM on device module
+ * 0xfbc00000-0xfbcfffff - TODC chip on device module
+ * 0xfbb00000-0xfbbfffff - External UART on device module
+ * 0xa2000000-0xfbafffff - <hole>
+ * 0xa1000000-0xa1ffffff - PCI 1 I/O (defined in gt64260.h)
+ * 0xa0000000-0xa0ffffff - PCI 0 I/O (defined in gt64260.h)
+ * 0x90000000-0x9fffffff - PCI 1 MEM (defined in gt64260.h)
+ * 0x80000000-0x8fffffff - PCI 0 MEM (defined in gt64260.h)
*/
#ifndef __PPC_PLATFORMS_EV64260_H
#define __PPC_PLATFORMS_EV64260_H
-#define EV64260_BRIDGE_REG_BASE 0xf8000000
-#define EV64260_BRIDGE_REG_BASE_TO_TOP 0x08000000U
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*
+ * CPU Physical Memory Map setup.
+ */
+#define EV64260_EXT_FLASH_BASE 0xfc000000
+#define EV64260_EMB_FLASH_BASE 0xfbf00000
+#define EV64260_EXT_SRAM_BASE 0xfbd00000
+#define EV64260_TODC_BASE 0xfbc00000
+#define EV64260_UART_BASE 0xfbb00000
-#define EV64260_TODC_BASE 0xfc800000
-#define EV64260_TODC_LEN 0x00800000
-#define EV64260_TODC_END (EV64260_TODC_BASE + \
- EV64260_TODC_LEN - 1)
+#define EV64260_EXT_FLASH_SIZE_ACTUAL 0x04000000 /* <= 64MB Extern FLASH */
+#define EV64260_EMB_FLASH_SIZE_ACTUAL 0x00080000 /* 512KB of Embed FLASH */
+#define EV64260_EXT_SRAM_SIZE_ACTUAL 0x00100000 /* 1MB SDRAM */
+#define EV64260_TODC_SIZE_ACTUAL 0x00000020 /* 32 bytes for TODC */
+#define EV64260_UART_SIZE_ACTUAL 0x00000040 /* 64 bytes for DUART */
+
+#define EV64260_EXT_FLASH_SIZE MAX(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EXT_FLASH_SIZE_ACTUAL)
+#define EV64260_EMB_FLASH_SIZE MAX(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EMB_FLASH_SIZE_ACTUAL)
+#define EV64260_EXT_SRAM_SIZE MAX(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_EXT_SRAM_SIZE_ACTUAL)
+#define EV64260_TODC_SIZE MAX(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_TODC_SIZE_ACTUAL)
+#if 0 /* XXXX blows up assembler in bootloader */
+#define EV64260_UART_SIZE MAX(GT64260_WINDOW_SIZE_MIN, \
+ EV64260_UART_SIZE_ACTUAL)
+#else
+#define EV64260_UART_SIZE GT64260_WINDOW_SIZE_MIN
+#endif
+#define EV64260_UART_END ((EV64260_UART_BASE + \
+ EV64260_UART_SIZE - 1) & 0xfff00000)
+
+/*
+ * Board-specific IRQ info
+ */
+#define EV64260_UART_0_IRQ 85
+#define EV64260_UART_1_IRQ 86
+#define EV64260_PCI_0_IRQ 91
+#define EV64260_PCI_1_IRQ 93
-#define EV64260_UART_BASE 0xfd000000
-#define EV64260_UART_LEN 0x00800000
-#define EV64260_UART_END (EV64260_UART_BASE + \
- EV64260_UART_LEN - 1)
-/* Serial driver setup. */
+/*
+ * Serial port setup.
+ */
+#define EV64260_DEFAULT_BAUD 115200
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+#define SERIAL_PORT_DFNS
+
+#define EV64260_MPSC_CLK_SRC 8 /* TCLK */
+#define EV64260_MPSC_CLK_FREQ 100000000 /* 100MHz clk */
+#else
#define EV64260_SERIAL_0 (EV64260_UART_BASE + 0x20)
#define EV64260_SERIAL_1 EV64260_UART_BASE
-#define BASE_BAUD ( 3686400 / 16 )
+#define BASE_BAUD (EV64260_DEFAULT_BAUD * 2)
#ifdef CONFIG_SERIAL_MANY_PORTS
#define RS_TABLE_SIZE 64
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
#endif
-#if !defined(CONFIG_GT64260_CONSOLE)
/* Required for bootloader's ns16550.c code */
#define STD_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, EV64260_SERIAL_0, 85, STD_COM_FLAGS, /* ttyS0 */\
- iomem_base: (u8 *)EV64260_SERIAL_0, \
+ { 0, BASE_BAUD, EV64260_SERIAL_0, EV64260_UART_0_IRQ, STD_COM_FLAGS, \
+ iomem_base: (u8 *)EV64260_SERIAL_0, /* ttyS0 */ \
+ iomem_reg_shift: 2, \
+ io_type: SERIAL_IO_MEM },
+
+#if 0
+ { 1, BASE_BAUD, EV64260_SERIAL_1, EV64260_UART_1_IRQ, STD_COM_FLAGS, \
+ iomem_base: (u8 *)EV64260_SERIAL_1, /* ttyS1 */ \
iomem_reg_shift: 2, \
io_type: SERIAL_IO_MEM },
+#endif
#define SERIAL_PORT_DFNS \
STD_SERIAL_PORT_DFNS
-#else
-#define SERIAL_PORT_DFNS
#endif
-
#endif /* __PPC_PLATFORMS_EV64260_H */
+++ /dev/null
-/*
- * arch/ppc/platforms/ev64260_setup.c
- *
- * Board setup routines for the Marvell/Galileo EV-64260-BP Evaluation Board.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-/*
- * The EV-64260-BP port is the result of hard work from many people from
- * many companies. In particular, employees of Marvell/Galileo, Mission
- * Critical Linux, Xyterra, and MontaVista Software were heavily involved.
- */
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#if !defined(CONFIG_GT64260_CONSOLE)
-#include <linux/serial.h>
-#endif
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/time.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-#include <asm/gt64260.h>
-#include <platforms/ev64260.h>
-
-
-extern char cmd_line[];
-unsigned long ev64260_find_end_of_memory(void);
-
-TODC_ALLOC();
-
-/*
- * Marvell/Galileo EV-64260-BP Evaluation Board PCI interrupt routing.
- */
-static int __init
-ev64260_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
- struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-
- if (hose->index == 0) {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- { 91, 0, 0, 0 }, /* IDSEL 7 - PCI bus 0 */
- { 91, 0, 0, 0 }, /* IDSEL 8 - PCI bus 0 */
- };
-
- const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- }
- else {
- static char pci_irq_table[][4] =
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {
- { 93, 0, 0, 0 }, /* IDSEL 7 - PCI bus 1 */
- { 93, 0, 0, 0 }, /* IDSEL 8 - PCI bus 1 */
- };
-
- const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
- return PCI_IRQ_TABLE_LOOKUP;
- }
-}
-
-static void __init
-ev64260_setup_bridge(void)
-{
- gt64260_bridge_info_t info;
- int window;
-
- GT64260_BRIDGE_INFO_DEFAULT(&info, ev64260_find_end_of_memory());
-
- /* Lookup PCI host bridges */
- if (gt64260_find_bridges(EV64260_BRIDGE_REG_BASE,
- &info,
- ev64260_map_irq)) {
- printk("Bridge initialization failed.\n");
- }
-
- /*
- * Enabling of PCI internal-vs-external arbitration
- * is a platform- and errata-dependent decision.
- */
- if(gt64260_revision == GT64260) {
- /* FEr#35 */
- gt_clr_bits(GT64260_PCI_0_ARBITER_CNTL, (1<<31));
- gt_clr_bits(GT64260_PCI_1_ARBITER_CNTL, (1<<31));
- } else if( gt64260_revision == GT64260A ) {
- gt_set_bits(GT64260_PCI_0_ARBITER_CNTL, (1<<31));
- gt_set_bits(GT64260_PCI_1_ARBITER_CNTL, (1<<31));
- /* Make external GPP interrupts level sensitive */
- gt_set_bits(GT64260_COMM_ARBITER_CNTL, (1<<10));
- /* Doc Change 9: > 100 MHz so must be set */
- gt_set_bits(GT64260_CPU_CONFIG, (1<<23));
- }
-
- gt_set_bits(GT64260_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */
-
- /* SCS windows not disabled above, disable all but SCS 0 */
- for (window=1; window<GT64260_CPU_SCS_DECODE_WINDOWS; window++) {
- gt64260_cpu_scs_set_window(window, 0, 0);
- }
-
- /* Set up windows to RTC/TODC and DUART on device module (CS 1 & 2) */
- gt64260_cpu_cs_set_window(1, EV64260_TODC_BASE, EV64260_TODC_LEN);
- gt64260_cpu_cs_set_window(2, EV64260_UART_BASE, EV64260_UART_LEN);
-
- /*
- * The EV-64260-BP uses several Multi-Purpose Pins (MPP) on the 64260
- * bridge as interrupt inputs (via the General Purpose Ports (GPP)
- * register). Need to route the MPP inputs to the GPP and set the
- * polarity correctly.
- *
- * In MPP Control 2 Register
- * MPP 21 -> GPP 21 (DUART channel A intr)
- * MPP 22 -> GPP 22 (DUART channel B intr)
- *
- * In MPP Control 3 Register
- * MPP 27 -> GPP 27 (PCI 0 INTA)
- * MPP 29 -> GPP 29 (PCI 1 INTA)
- */
- gt_clr_bits(GT64260_MPP_CNTL_2,
- ((1<<20) | (1<<21) | (1<<22) | (1<<23) |
- (1<<24) | (1<<25) | (1<<26) | (1<<27)));
-
- gt_clr_bits(GT64260_MPP_CNTL_3,
- ((1<<12) | (1<<13) | (1<<14) | (1<<15) |
- (1<<20) | (1<<21) | (1<<22) | (1<<23)));
-
- gt_write(GT64260_GPP_LEVEL_CNTL, 0x000002c6);
-
- /* DUART & PCI interrupts are active low */
- gt_set_bits(GT64260_GPP_LEVEL_CNTL,
- ((1<<21) | (1<<22) | (1<<27) | (1<<29)));
-
- /* Clear any pending interrupts for these inputs and enable them. */
- gt_write(GT64260_GPP_INTR_CAUSE,
- ~((1<<21) | (1<<22) | (1<<27) | (1<<29)));
- gt_set_bits(GT64260_GPP_INTR_MASK,
- ((1<<21) | (1<<22)| (1<<27) | (1<<29)));
- gt_set_bits(GT64260_IC_CPU_INTR_MASK_HI, ((1<<26) | (1<<27)));
-
- /* Set MPSC Multiplex RMII */
- /* NOTE: ethernet driver modifies bit 0 and 1 */
- gt_write(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
-
- return;
-}
-
-
-static void __init
-ev64260_setup_arch(void)
-{
-#if !defined(CONFIG_GT64260_CONSOLE)
- struct serial_struct serial_req;
-#endif
-
- if ( ppc_md.progress )
- ppc_md.progress("ev64260_setup_arch: enter", 0);
-
- loops_per_jiffy = 50000000 / HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
- if (initrd_start)
- ROOT_DEV = Root_RAM0;
- else
-#endif
-#ifdef CONFIG_ROOT_NFS
- ROOT_DEV = Root_NFS;
-#else
- ROOT_DEV = Root_SDA2;
-#endif
-
- if ( ppc_md.progress )
- ppc_md.progress("ev64260_setup_arch: find_bridges", 0);
-
- /*
- * Set up the L2CR register.
- * L2 cache was invalidated by bootloader.
- */
- switch (PVR_VER(mfspr(PVR))) {
- case PVR_VER(PVR_750):
- _set_L2CR(0xfd100000);
- break;
- case PVR_VER(PVR_7400):
- case PVR_VER(PVR_7410):
- _set_L2CR(0xcd100000);
- break;
- /* case PVR_VER(PVR_7450): */
- /* XXXX WHAT VALUE?? FIXME */
- break;
- }
-
- ev64260_setup_bridge();
-
- TODC_INIT(TODC_TYPE_DS1501, 0, 0, ioremap(EV64260_TODC_BASE,0x20), 8);
-
-#if !defined(CONFIG_GT64260_CONSOLE)
- memset(&serial_req, 0, sizeof(serial_req));
- serial_req.line = 0;
- serial_req.baud_base = BASE_BAUD;
- serial_req.port = 0;
- serial_req.irq = 85;
- serial_req.flags = STD_COM_FLAGS;
- serial_req.io_type = SERIAL_IO_MEM;
- serial_req.iomem_base = ioremap(EV64260_SERIAL_0, 0x20);
- serial_req.iomem_reg_shift = 2;
-
- if (early_serial_setup(&serial_req) != 0) {
- printk("Early serial init of port 0 failed\n");
- }
-
- /* Assume early_serial_setup() doesn't modify serial_req */
- serial_req.line = 1;
- serial_req.port = 1;
- serial_req.irq = 86;
- serial_req.iomem_base = ioremap(EV64260_SERIAL_1, 0x20);
-
- if (early_serial_setup(&serial_req) != 0) {
- printk("Early serial init of port 1 failed\n");
- }
-#endif
-
- printk("Marvell/Galileo EV-64260-BP Evaluation Board\n");
- printk("EV-64260-BP port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
-
- if ( ppc_md.progress )
- ppc_md.progress("ev64260_setup_arch: exit", 0);
-
- return;
-}
-
-static void __init
-ev64260_init_irq(void)
-{
- gt64260_init_irq();
-
- if(gt64260_revision != GT64260) {
- /* XXXX Kludge--need to fix gt64260_init_irq() interface */
- /* Mark PCI intrs level sensitive */
- irq_desc[91].status |= IRQ_LEVEL;
- irq_desc[93].status |= IRQ_LEVEL;
- }
-}
-
-unsigned long __init
-ev64260_find_end_of_memory(void)
-{
- return 32*1024*1024; /* XXXX FIXME */
-}
-
-static void
-ev64260_reset_board(void)
-{
- local_irq_disable();
-
- /* Set exception prefix high - to the firmware */
- _nmask_and_or_msr(0, MSR_IP);
-
- /* XXX FIXME */
- printk("XXXX **** trying to reset board ****\n");
- return;
-}
-
-static void
-ev64260_restart(char *cmd)
-{
- volatile ulong i = 10000000;
-
- ev64260_reset_board();
-
- while (i-- > 0);
- panic("restart failed\n");
-}
-
-static void
-ev64260_halt(void)
-{
- local_irq_disable();
- while (1);
- /* NOTREACHED */
-}
-
-static void
-ev64260_power_off(void)
-{
- ev64260_halt();
- /* NOTREACHED */
-}
-
-static int
-ev64260_show_cpuinfo(struct seq_file *m)
-{
- uint pvid;
-
- pvid = mfspr(PVR);
- seq_printf(m, "vendor\t\t: Marvell/Galileo\n");
- seq_printf(m, "machine\t\t: EV-64260-BP\n");
- seq_printf(m, "PVID\t\t: 0x%x, vendor: %s\n",
- pvid, (pvid & (1<<15) ? "IBM" : "Motorola"));
-
- return 0;
-}
-
-/* DS1501 RTC has too much variation to use RTC for calibration */
-static void __init
-ev64260_calibrate_decr(void)
-{
- ulong freq;
-
- freq = 100000000 / 4;
-
- printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
- freq/1000000, freq%1000000);
-
- tb_ticks_per_jiffy = freq / HZ;
- tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
- return;
-}
-
-#if defined(CONFIG_SERIAL_TEXT_DEBUG)
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-ev64260_set_bat(void)
-{
- unsigned long bat3u, bat3l;
- static int mapping_set = 0;
-
- if (!mapping_set) {
-
- __asm__ __volatile__(
- " lis %0,0xf000\n \
- ori %1,%0,0x002a\n \
- ori %0,%0,0x1ffe\n \
- mtspr 0x21e,%0\n \
- mtspr 0x21f,%1\n \
- isync\n \
- sync "
- : "=r" (bat3u), "=r" (bat3l));
-
- mapping_set = 1;
- }
-
- return;
-}
-
-#if !defined(CONFIG_GT64260_CONSOLE)
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
- SERIAL_PORT_DFNS /* Defined in <asm/serial.h> */
-};
-
-static void
-ev64260_16550_progress(char *s, unsigned short hex)
-{
- volatile char c;
- volatile unsigned long com_port;
- u16 shift;
-
- com_port = rs_table[0].port;
- shift = rs_table[0].iomem_reg_shift;
-
- while ((c = *s++) != 0) {
- while ((*((volatile unsigned char *)com_port +
- (UART_LSR << shift)) & UART_LSR_THRE) == 0)
- ;
- *(volatile unsigned char *)com_port = c;
-
- if (c == '\n') {
- while ((*((volatile unsigned char *)com_port +
- (UART_LSR << shift)) & UART_LSR_THRE) == 0)
- ;
- *(volatile unsigned char *)com_port = '\r';
- }
- }
-
- /* Move to next line on */
- while ((*((volatile unsigned char *)com_port +
- (UART_LSR << shift)) & UART_LSR_THRE) == 0)
- ;
- *(volatile unsigned char *)com_port = '\n';
- while ((*((volatile unsigned char *)com_port +
- (UART_LSR << shift)) & UART_LSR_THRE) == 0)
- ;
- *(volatile unsigned char *)com_port = '\r';
-
- return;
-}
-#endif /* !CONFIG_GT64260_CONSOLE */
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7)
-{
- parse_bootinfo(find_bootinfo());
-
- isa_mem_base = 0;
-
- ppc_md.setup_arch = ev64260_setup_arch;
- ppc_md.show_cpuinfo = ev64260_show_cpuinfo;
- ppc_md.irq_canonicalize = NULL;
- ppc_md.init_IRQ = ev64260_init_irq;
- ppc_md.get_irq = gt64260_get_irq;
- ppc_md.init = NULL;
-
- ppc_md.restart = ev64260_restart;
- ppc_md.power_off = ev64260_power_off;
- ppc_md.halt = ev64260_halt;
-
- ppc_md.find_end_of_memory = ev64260_find_end_of_memory;
-
- ppc_md.time_init = todc_time_init;
- ppc_md.set_rtc_time = todc_set_rtc_time;
- ppc_md.get_rtc_time = todc_get_rtc_time;
- ppc_md.calibrate_decr = ev64260_calibrate_decr;
-
- ppc_md.nvram_read_val = todc_direct_read_val;
- ppc_md.nvram_write_val = todc_direct_write_val;
-
- ppc_md.heartbeat = NULL;
- ppc_md.heartbeat_reset = 0;
- ppc_md.heartbeat_count = 0;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
- ev64260_set_bat();
-#ifdef CONFIG_GT64260_CONSOLE
- gt64260_base = EV64260_BRIDGE_REG_BASE;
- ppc_md.progress = gt64260_mpsc_progress; /* embedded UART */
-#else
- ppc_md.progress = ev64260_16550_progress; /* Dev module DUART */
-#endif
-#else /* !CONFIG_SERIAL_TEXT_DEBUG */
- ppc_md.progress = NULL;
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
- return;
-}
obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \
todc_time.o
obj-$(CONFIG_EBONY) += indirect_pci.o pci_auto.o todc_time.o
-obj-$(CONFIG_EV64260) += gt64260_common.o gt64260_pic.o \
- indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_EV64260) += indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_DMV182) += indirect_pci.o todc_time.o pci_auto.o
obj-$(CONFIG_GEMINI) += open_pic.o indirect_pci.o
+obj-$(CONFIG_GT64260) += gt64260_pic.o
obj-$(CONFIG_K2) += i8259.o indirect_pci.o todc_time.o \
pci_auto.o
obj-$(CONFIG_LOPEC) += i8259.o pci_auto.o todc_time.o
open_pic.o i8259.o hawk_common.o
obj-$(CONFIG_MENF1) += todc_time.o i8259.o mpc10x_common.o \
pci_auto.o indirect_pci.o
+obj-$(CONFIG_MV64360) += mv64360_pic.o
+obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_ocp.o
obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o indirect_pci.o \
i8259.o pci_auto.o hawk_common.o
obj-$(CONFIG_OCOTEA) += indirect_pci.o pci_auto.o todc_time.o
*
* Interrupt controller support for Galileo's GT64260.
*
- * Author: Chris Zankel <chris@mvista.com>
+ * Author: Chris Zankel <source@mvista.com>
* Modified by: Mark A. Greer <mgreer@mvista.com>
*
* Based on sources from Rabeeh Khoury / Galileo Technology
#include <asm/io.h>
#include <asm/system.h>
#include <asm/irq.h>
-#include <asm/gt64260.h>
+#include <asm/ocp.h>
+#include <asm/mv64x60.h>
/* ========================== forward declaration ========================== */
u32 gt64260_irq_base = 0; /* GT64260 handles the next 96 IRQs from here */
+static mv64x60_handle_t base_bh;
+static mv64x60_handle_t ic_bh;
+
/* gt64260_init_irq()
*
* This function initializes the interrupt controller. It assigns
__init void
gt64260_init_irq(void)
{
+ struct ocp_def *def;
int i;
+/* XXXX extract reg base, irq base from ocp */
+/* XXXX rewrite read/write macros to not use 'bh'?? */
+/* XXXX Have to use ocp b/c can pass arg to this routine */
+
if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0);
+ if ((def = ocp_get_one_device(OCP_VENDOR_MARVELL, OCP_FUNC_HB,
+ OCP_ANY_INDEX)) == NULL) {
+ /* XXXX SCREAM */
+ return;
+ }
+ base_bh.v_base = (u32)ioremap(def->paddr, 0x10000); /* XXXX */
+
+ if ((def = ocp_get_one_device(OCP_VENDOR_MARVELL, OCP_FUNC_PIC,
+ OCP_ANY_INDEX)) == NULL) {
+ /* XXXX SCREAM */
+ return;
+ }
+ ic_bh.v_base = (u32)ioremap(def->paddr, 0x1000); /* XXXX */
+
ppc_cached_irq_mask[0] = 0;
ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
ppc_cached_irq_mask[2] = 0;
/* disable all interrupts and clear current interrupts */
- gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
- gt_write(GT64260_GPP_INTR_CAUSE,0);
- gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
- gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
+ mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
+ mv64x60_write(&base_bh, MV64x60_GPP_INTR_CAUSE,0);
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
/* use the gt64260 for all (possible) interrupt sources */
for( i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++ ) {
}
-/* gt64260_get_irq()
+/*
+ * gt64260_get_irq()
*
* This function returns the lowest interrupt number of all interrupts that
* are currently asserted.
int irq;
int irq_gpp;
- irq = gt_read(GT64260_IC_MAIN_CAUSE_LO);
+ irq = mv64x60_read(&ic_bh, GT64260_IC_MAIN_CAUSE_LO);
irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
if (irq == -1) {
- irq = gt_read(GT64260_IC_MAIN_CAUSE_HI);
+ irq = mv64x60_read(&ic_bh, GT64260_IC_MAIN_CAUSE_HI);
irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]);
if (irq == -1) {
irq = -2; /* bogus interrupt, should never happen */
} else {
if (irq >= 24) {
- irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE);
+ irq_gpp = mv64x60_read(&base_bh, MV64x60_GPP_INTR_CAUSE);
irq_gpp = __ilog2(irq_gpp &
ppc_cached_irq_mask[2]);
irq = -2;
} else {
irq = irq_gpp + 64;
- gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64)));
+ mv64x60_write(&base_bh, MV64x60_GPP_INTR_CAUSE, ~(1<<(irq-64)));
}
} else {
irq += 32;
static void
gt64260_unmask_irq(unsigned int irq)
{
+ /* XXXX
+ printk("XXXX: *** unmask irq: %d\n", irq);
+ */
irq -= gt64260_irq_base;
if (irq > 31) {
if (irq > 63) {
/* unmask GPP irq */
- gt_write(GT64260_GPP_INTR_MASK,
+ mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK,
ppc_cached_irq_mask[2] |= (1<<(irq-64)));
} else {
/* mask high interrupt register */
- gt_write(GT64260_IC_CPU_INTR_MASK_HI,
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI,
ppc_cached_irq_mask[1] |= (1<<(irq-32)));
}
} else {
/* mask low interrupt register */
- gt_write(GT64260_IC_CPU_INTR_MASK_LO,
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO,
ppc_cached_irq_mask[0] |= (1<<irq));
}
}
static void
gt64260_mask_irq(unsigned int irq)
{
+ /* XXXX
+ printk("XXXX: *** mask irq: %d\n", irq);
+ */
irq -= gt64260_irq_base;
if (irq > 31) {
if (irq > 63) {
/* mask GPP irq */
- gt_write(GT64260_GPP_INTR_MASK,
+ mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK,
ppc_cached_irq_mask[2] &= ~(1<<(irq-64)));
} else {
/* mask high interrupt register */
- gt_write(GT64260_IC_CPU_INTR_MASK_HI,
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI,
ppc_cached_irq_mask[1] &= ~(1<<(irq-32)));
}
} else {
/* mask low interrupt register */
- gt_write(GT64260_IC_CPU_INTR_MASK_LO,
+ mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO,
ppc_cached_irq_mask[0] &= ~(1<<irq));
}
/* Timer Interrupts */
static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-static void openpic_maptimer(u_int timer, u_int cpumask);
+static void openpic_maptimer(u_int timer, cpumask_t cpumask);
/* Interrupt Sources */
static void openpic_enable_irq(u_int irq);
static void openpic_disable_irq(u_int irq);
static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask);
+static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask);
/*
* These functions are not used but the code is kept here
*/
static void openpic_end_irq(unsigned int irq_nr);
static void openpic_ack_irq(unsigned int irq_nr);
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
+static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
struct hw_interrupt_type open_pic = {
- " OpenPIC ",
- NULL,
- NULL,
- openpic_enable_irq,
- openpic_disable_irq,
- openpic_ack_irq,
- openpic_end_irq,
- openpic_set_affinity
+ .typename = " OpenPIC ",
+ .enable = openpic_enable_irq,
+ .disable = openpic_disable_irq,
+ .ack = openpic_ack_irq,
+ .end = openpic_end_irq,
+ .set_affinity = openpic_set_affinity,
};
#ifdef CONFIG_SMP
static void openpic_disable_ipi(unsigned int irq_nr);
struct hw_interrupt_type open_pic_ipi = {
- " OpenPIC ",
- NULL,
- NULL,
- openpic_enable_ipi,
- openpic_disable_ipi,
- openpic_ack_ipi,
- openpic_end_ipi,
- 0
+ .typename = " OpenPIC ",
+ .enable = openpic_enable_ipi,
+ .disable = openpic_disable_ipi,
+ .ack = openpic_ack_ipi,
+ .end = openpic_end_ipi,
};
#endif /* CONFIG_SMP */
/* Disabled, Priority 0 */
openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
/* No processor */
- openpic_maptimer(i, 0);
+ openpic_maptimer(i, CPU_MASK_NONE);
}
#ifdef CONFIG_SMP
openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
(sense & IRQ_SENSE_MASK));
/* Processor 0 */
- openpic_mapirq(i, 1<<0, 0);
+ openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
}
/* Init descriptors */
/*
* Convert a cpu mask from logical to physical cpu numbers.
*/
-static inline u32 physmask(u32 cpumask)
+static inline cpumask_t physmask(cpumask_t cpumask)
{
int i;
- u32 mask = 0;
+ cpumask_t mask = CPU_MASK_NONE;
+
+ cpus_and(cpumask, cpu_online_map, cpumask);
+
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_isset(i, cpumask))
+ cpu_set(smp_hw_index[i], mask);
- for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
- if (cpu_online(i))
- mask |= (cpumask & 1) << smp_hw_index[i];
return mask;
}
#else
{
#ifdef CONFIG_IRQ_ALL_CPUS
int i;
- u32 msk;
+ cpumask_t msk = CPU_MASK_NONE;
#endif
spin_lock(&openpic_setup_lock);
#ifdef CONFIG_IRQ_ALL_CPUS
- msk = 1 << smp_hw_index[smp_processor_id()];
+ cpu_set(smp_hw_index[smp_processor_id()], mask);
/* let the openpic know we want intrs. default affinity
* is 0xffffffff until changed via /proc
* in irq.c.
*/
for (i = 0; i < NumSources; i++)
- openpic_mapirq(i, msk, ~0U);
+ openpic_mapirq(i, msk, CPU_MASK_ALL);
#endif /* CONFIG_IRQ_ALL_CPUS */
openpic_set_priority(0);
/*
* Map a timer interrupt to one or more CPUs
*/
-static void __init openpic_maptimer(u_int timer, u_int cpumask)
+static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
{
+ cpumask_t phys = physmask(cpumask);
check_arg_timer(timer);
openpic_write(&OpenPIC->Global.Timer[timer].Destination,
- physmask(cpumask));
+ cpus_addr(phys)[0]);
}
/*
/*
* Map an interrupt source to one or more CPUs
*/
-static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask)
+static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask)
{
if (ISR[irq] == 0)
return;
- if (keepmask != 0)
- physmask |= openpic_read(&ISR[irq]->Destination) & keepmask;
- openpic_write(&ISR[irq]->Destination, physmask);
+ if (!cpus_empty(keepmask)) {
+ cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) };
+ cpus_and(irqdest, irqdest, keepmask);
+ cpus_or(physmask, physmask, irqdest);
+ }
+ openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]);
}
#ifdef notused
#endif
}
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
+static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
{
- openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0);
+ openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE);
}
#ifdef CONFIG_SMP
#include <linux/ptrace.h>
#include <linux/aio_abi.h>
#include <linux/elf.h>
+#include <linux/vs_cvirt.h>
#include <net/scm.h>
#include <net/sock.h>
#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/vs_cvirt.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
#include <linux/syscalls.h>
#include <linux/ipc.h>
#include <linux/personality.h>
+#include <linux/vs_cvirt.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
late_initcall(stdio_init);
-static void console_write(struct console *console, const char *string,
- unsigned len)
+static void stdio_console_write(struct console *console, const char *string,
+ unsigned len)
{
struct line *line = &vts[console->index];
up(&line->sem);
}
-static struct tty_driver *console_device(struct console *c, int *index)
+static struct tty_driver *stdio_console_device(struct console *c, int *index)
{
*index = c->index;
return console_driver;
}
-static int console_setup(struct console *co, char *options)
+static int stdio_console_setup(struct console *co, char *options)
{
return(0);
}
static struct console stdiocons = {
name: "tty",
- write: console_write,
- device: console_device,
- setup: console_setup,
+ write: stdio_console_write,
+ device: stdio_console_device,
+ setup: stdio_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
#define __UM_SYSDEP_CHECKSUM_H
#include "linux/string.h"
+#include "linux/in6.h"
/*
* computes the checksum of a memory block at buff, length len,
#include "linux/unistd.h"
#include "linux/slab.h"
#include "linux/utime.h"
+#include <linux/vs_cvirt.h>
+
#include "asm/mman.h"
#include "asm/uaccess.h"
#include "asm/ipc.h"
obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \
- semaphore.o sigcontext.o syscalls.o sysrq.o time.o
+ semaphore.o bitops.o sigcontext.o syscalls.o sysrq.o time.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-SYMLINKS = semaphore.c highmem.c module.c
+SYMLINKS = semaphore.c highmem.c module.c bitops.c
SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
clean-files := $(SYMLINKS)
semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
+bitops.c-dir = lib
define make_link
-rm -f $1
.quad sys_tgkill /* 270 */
.quad compat_sys_utimes
.quad sys32_fadvise64_64
- .quad quiet_ni_syscall /* sys_vserver */
+ .quad sys_vserver
.quad sys_mbind
.quad compat_get_mempolicy /* 275 */
.quad sys_set_mempolicy
#include <linux/ptrace.h>
#include <linux/highuid.h>
#include <linux/vmalloc.h>
+#include <linux/vs_cvirt.h>
#include <asm/mman.h>
#include <asm/types.h>
#include <asm/uaccess.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/personality.h>
+#include <linux/vs_cvirt.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
-# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $
+# $Id: Kconfig,v 1.5 2004/06/04 15:59:32 gleixner Exp $
menu "Memory Technology Devices (MTD)"
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
+config MTD_REDBOOT_PARTS_UNALLOCATED
+ bool " Include unallocated flash regions"
+ depends on MTD_REDBOOT_PARTS
+ help
+ If you need to register each unallocated flash region as a MTD
+ 'partition', enable this option.
+
+config MTD_REDBOOT_PARTS_READONLY
+ bool " Force read-only for RedBoot system images"
+ depends on MTD_REDBOOT_PARTS
+ help
+ If you need to force read-only for 'RedBoot', 'RedBoot Config' and
+ 'FIS directory' images, enable this option.
+
config MTD_CMDLINE_PARTS
- tristate "Command line partition table parsing"
- depends on MTD_PARTITIONS
+ bool "Command line partition table parsing"
+ depends on MTD_PARTITIONS = "y"
---help---
Allow generic configuration of the MTD paritition tables via the kernel
command line. Multiple flash resources are supported for hardware where
#
# Makefile for the memory technology device drivers.
#
-# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $
-
-# *** BIG UGLY NOTE ***
-#
-# The shiny new inter_module_xxx has introduced yet another ugly link
-# order dependency, which I'd previously taken great care to avoid.
-# We now have to ensure that the chip drivers are initialised before the
-# map drivers, and that the doc200[01] drivers are initialised before
-# docprobe.
-#
-# We'll hopefully merge the doc200[01] drivers and docprobe back into
-# a single driver some time soon, but the CFI drivers are going to have
-# to stay like that.
-#
-# Urgh.
-#
-# dwmw2 21/11/0
+# $Id: Makefile.common,v 1.3 2004/07/12 16:07:30 dwmw2 Exp $
# Core functionality.
obj-$(CONFIG_MTD) += mtdcore.o
This is access code for flashes using ARM's flash partitioning
standards.
- $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $
+ $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
======================================================================*/
# drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.3 2003/05/28 15:13:24 dwmw2 Exp $
+# $Id: Kconfig,v 1.8 2004/07/13 22:32:02 dwmw2 Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
arrangements of CFI chips. If unsure, say 'N' and all options
which are supported by the current code will be enabled.
-config MTD_CFI_B1
- bool "Support 8-bit buswidth"
- depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_1
+ bool "Support 8-bit buswidth" if MTD_CFI_GEOMETRY
+ default y
help
If you wish to support CFI devices on a physical bus which is
8 bits wide, say 'Y'.
-config MTD_CFI_B2
- bool "Support 16-bit buswidth"
- depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_2
+ bool "Support 16-bit buswidth" if MTD_CFI_GEOMETRY
+ default y
help
If you wish to support CFI devices on a physical bus which is
16 bits wide, say 'Y'.
-config MTD_CFI_B4
- bool "Support 32-bit buswidth"
- depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_4
+ bool "Support 32-bit buswidth" if MTD_CFI_GEOMETRY
+ default y
help
If you wish to support CFI devices on a physical bus which is
32 bits wide, say 'Y'.
-config MTD_CFI_B8
- bool "Support 64-bit buswidth"
- depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_8
+ bool "Support 64-bit buswidth" if MTD_CFI_GEOMETRY
+ default n
help
If you wish to support CFI devices on a physical bus which is
64 bits wide, say 'Y'.
+config MTD_MAP_BANK_WIDTH_16
+ bool "Support 128-bit buswidth" if MTD_CFI_GEOMETRY
+ default n
+ help
+ If you wish to support CFI devices on a physical bus which is
+ 128 bits wide, say 'Y'.
+
+config MTD_MAP_BANK_WIDTH_32
+ bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
+ default n
+ help
+ If you wish to support CFI devices on a physical bus which is
+ 256 bits wide, say 'Y'.
+
config MTD_CFI_I1
- bool "Support 1-chip flash interleave" if !MTD_CFI_B1
- depends on MTD_CFI_GEOMETRY
- default y if MTD_CFI_B1
+ bool "Support 1-chip flash interleave" if MTD_CFI_GEOMETRY
+ default y
help
If your flash chips are not interleaved - i.e. you only have one
flash chip addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I2
- bool "Support 2-chip flash interleave"
- depends on MTD_CFI_GEOMETRY
+ bool "Support 2-chip flash interleave" if MTD_CFI_GEOMETRY
+ default y
help
If your flash chips are interleaved in pairs - i.e. you have two
flash chips addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I4
- bool "Support 4-chip flash interleave"
- depends on MTD_CFI_GEOMETRY
+ bool "Support 4-chip flash interleave" if MTD_CFI_GEOMETRY
+ default n
help
If your flash chips are interleaved in fours - i.e. you have four
flash chips addressed by each bus cycle, then say 'Y'.
config MTD_CFI_I8
- bool "Support 8-chip flash interleave"
- depends on MTD_CFI_GEOMETRY
+ bool "Support 8-chip flash interleave" if MTD_CFI_GEOMETRY
+ default n
help
If your flash chips are interleaved in eights - i.e. you have eight
flash chips addressed by each bus cycle, then say 'Y'.
provides support for one of those command sets, used on chips
including the AMD Am29LV320.
+config MTD_CFI_AMDSTD_RETRY
+ int "Retry failed commands (erase/program)"
+ depends on MTD_CFI_AMDSTD
+ default "0"
+ help
+ Some chips, when attached to a shared bus, don't properly filter
+ bus traffic that is destined to other devices. This broken
+ behavior causes erase and program sequences to be aborted when
+ the sequences are mixed with traffic for other devices.
+
+ SST49LF040 (and related) chips are know to be broken.
+
+config MTD_CFI_AMDSTD_RETRY_MAX
+ int "Max retries of failed commands (erase/program)"
+ depends on MTD_CFI_AMDSTD_RETRY
+ default "0"
+ help
+ If you have an SST49LF040 (or related chip) then this value should
+ be set to at least 1. This can also be adjusted at driver load
+ time with the retry_cmd_max module parameter.
+
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
sets which a CFI-compliant chip may claim to implement. This code
provides support for one of those command sets.
+config MTD_CFI_UTIL
+ tristate
+ default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
+ default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
+
config MTD_RAM
tristate "Support for RAM chips in bus mapping"
depends on MTD
#
# linux/drivers/chips/Makefile
#
-# $Id: Makefile.common,v 1.1 2003/05/21 15:00:01 dwmw2 Exp $
+# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $
# *** BIG UGLY NOTE ***
#
# The removal of get_module_symbol() and replacement with
# inter_module_register() et al has introduced a link order dependency
# here where previously there was none. We now have to ensure that
-# the CFI command set drivers are linked before cfi_probe.o
+# the CFI command set drivers are linked before gen_probe.o
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
+obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o
obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
- * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.24 2004/07/12 13:34:30 dwmw2 Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0001.c,v 1.126 2003/06/23 07:45:48 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.153 2004/07/12 21:52:20 dwmw2 Exp $
*
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
#include <linux/mtd/compatmac.h>
#include <linux/mtd/cfi.h>
+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
+
// debugging, turns off buffer write mode if set to 1
#define FORCE_WORD_WRITE 0
static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
static struct mtd_info *cfi_intelext_setup (struct map_info *);
+static int cfi_intelext_partition_fixup(struct map_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf);
static void cfi_tell_features(struct cfi_pri_intelext *extp)
{
int i;
- printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
- printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
- printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
- printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
- printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
- printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
- printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
- printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
- printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
- printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
- for (i=9; i<32; i++) {
+ printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+ printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+ printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+ printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+ printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+ printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+ printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+ printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+ printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+ printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+ printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
+ for (i=10; i<32; i++) {
if (extp->FeatureSupport & (1<<i))
printk(" - Unknown Bit %X: supported\n", i);
}
}
printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
- extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+ extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
if (extp->VppOptimal)
printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
- extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+ extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
+}
+#endif
+
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
+static void fixup_intel_strataflash(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+
+ printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+ "erase on write disabled.\n");
+ extp->SuspendCmdSupport &= ~1;
+}
+#endif
+
+static void fixup_st_m28w320ct(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */
+ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
}
+
+static void fixup_st_m28w320cb(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ /* Note this is done after the region info is endian swapped */
+ cfi->cfiq->EraseRegionInfo[1] =
+ (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
+};
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+ {
+ CFI_MFR_ANY, CFI_ID_ANY,
+ fixup_intel_strataflash, NULL
+ },
#endif
+ {
+ 0x0020, /* STMicroelectronics */
+ 0x00ba, /* M28W320CT */
+ fixup_st_m28w320ct, NULL
+ }, {
+ 0x0020, /* STMicroelectronics */
+ 0x00bb, /* M28W320CB */
+ fixup_st_m28w320cb, NULL
+ }, {
+ 0, 0, NULL, NULL
+ }
+};
/* This routine is made available to other mtd code via
* inter_module_register. It must only be accessed through
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode == CFI_MODE_CFI) {
/*
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;
- int ofs_factor = cfi->interleave * cfi->device_type;
- //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
- if (!adr)
+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
+ if (!extp)
return NULL;
-
- /* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
- if (!extp) {
- printk(KERN_ERR "Failed to allocate memory\n");
- return NULL;
- }
-
- /* Read in the Extended Query Table */
- for (i=0; i<sizeof(*extp); i++) {
- ((unsigned char *)extp)[i] =
- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
- }
-
- if (extp->MajorVersion != '1' ||
- (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
- printk(KERN_WARNING " Unknown IntelExt Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
- return NULL;
- }
/* Do some byteswapping if necessary */
extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+
+ /* Install our own private info structure */
+ cfi->cmdset_priv = extp;
+
+ cfi_fixup(map, fixup_table);
#ifdef DEBUG_CFI_FEATURES
/* Tell the user about it in lots of lovely detail */
#endif
if(extp->SuspendCmdSupport & 1) {
-//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
- printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
- "erase on write disabled.\n");
- extp->SuspendCmdSupport &= ~1;
-#else
printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
-#endif
}
- /* Install our own private info structure */
- cfi->cmdset_priv = extp;
}
for (i=0; i< cfi->numchips; i++) {
map->fldrv = &cfi_intelext_chipdrv;
- /* Make sure it's in read mode */
- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_intelext_setup(map);
}
printk(KERN_INFO "Using word write method\n" );
mtd->write = cfi_intelext_write_words;
}
+#if 0
mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+#endif
mtd->sync = cfi_intelext_sync;
mtd->lock = cfi_intelext_lock;
mtd->unlock = cfi_intelext_unlock;
mtd->flags = MTD_CAP_NORFLASH;
map->fldrv = &cfi_intelext_chipdrv;
mtd->name = map->name;
+
+ /* This function has the potential to distort the reality
+ a bit and therefore should be called last. */
+ if (cfi_intelext_partition_fixup(map, &cfi) != 0)
+ goto setup_err;
+
__module_get(THIS_MODULE);
return mtd;
kfree(mtd);
}
kfree(cfi->cmdset_priv);
- kfree(cfi->cfiq);
return NULL;
}
+static int cfi_intelext_partition_fixup(struct map_info *map,
+ struct cfi_private **pcfi)
+{
+ struct cfi_private *cfi = *pcfi;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+
+ /*
+ * Probing of multi-partition flash ships.
+ *
+ * This is extremely crude at the moment and should probably be
+ * extracted entirely from the Intel extended query data instead.
+ * Right now a L18 flash is assumed if multiple operations is
+ * detected.
+ *
+ * To support multiple partitions when available, we simply arrange
+ * for each of them to have their own flchip structure even if they
+ * are on the same physical chip. This means completely recreating
+ * a new cfi_private structure right here which is a blatent code
+ * layering violation, but this is still the least intrusive
+ * arrangement at this point. This can be rearranged in the future
+ * if someone feels motivated enough. --nico
+ */
+ if (extp && extp->FeatureSupport & (1 << 9)) {
+ struct cfi_private *newcfi;
+ struct flchip *chip;
+ struct flchip_shared *shared;
+ int numparts, partshift, numvirtchips, i, j;
+
+ /*
+ * The L18 flash memory array is divided
+ * into multiple 8-Mbit partitions.
+ */
+ numparts = 1 << (cfi->cfiq->DevSize - 20);
+ partshift = 20 + __ffs(cfi->interleave);
+ numvirtchips = cfi->numchips * numparts;
+
+ newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
+ if (!newcfi)
+ return -ENOMEM;
+ shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL);
+ if (!shared) {
+ kfree(newcfi);
+ return -ENOMEM;
+ }
+ memcpy(newcfi, cfi, sizeof(struct cfi_private));
+ newcfi->numchips = numvirtchips;
+ newcfi->chipshift = partshift;
+
+ chip = &newcfi->chips[0];
+ for (i = 0; i < cfi->numchips; i++) {
+ shared[i].writing = shared[i].erasing = NULL;
+ spin_lock_init(&shared[i].lock);
+ for (j = 0; j < numparts; j++) {
+ *chip = cfi->chips[i];
+ chip->start += j << partshift;
+ chip->priv = &shared[i];
+ /* those should be reset too since
+ they create memory references. */
+ init_waitqueue_head(&chip->wq);
+ spin_lock_init(&chip->_spinlock);
+ chip->mutex = &chip->_spinlock;
+ chip++;
+ }
+ }
+
+ printk(KERN_DEBUG "%s: %d sets of %d interleaved chips "
+ "--> %d partitions of %#x bytes\n",
+ map->name, cfi->numchips, cfi->interleave,
+ newcfi->numchips, 1<<newcfi->chipshift);
+
+ map->fldrv_priv = newcfi;
+ *pcfi = newcfi;
+ kfree(cfi);
+ }
+
+ return 0;
+}
+
/*
* *********** CHIP ACCESS FUNCTIONS ***********
*/
{
DECLARE_WAITQUEUE(wait, current);
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK = CMD(0x80);
+ map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
unsigned long timeo;
- struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv;
+ struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
resettime:
timeo = jiffies + HZ;
retry:
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+ /*
+ * OK. We have possibility for contension on the write/erase
+ * operations which are global to the real chip and not per
+ * partition. So let's fight it over in the partition which
+ * currently has authority on the operation.
+ *
+ * The rules are as follows:
+ *
+ * - any write operation must own shared->writing.
+ *
+ * - any erase operation must own _both_ shared->writing and
+ * shared->erasing.
+ *
+ * - contension arbitration is handled in the owner's context.
+ *
+ * The 'shared' struct can be read when its lock is taken.
+ * However any writes to it can only be made when the current
+ * owner's lock is also held.
+ */
+ struct flchip_shared *shared = chip->priv;
+ struct flchip *contender;
+ spin_lock(&shared->lock);
+ contender = shared->writing;
+ if (contender && contender != chip) {
+ /*
+ * The engine to perform desired operation on this
+ * partition is already in use by someone else.
+ * Let's fight over it in the context of the chip
+ * currently using it. If it is possible to suspend,
+ * that other partition will do just that, otherwise
+ * it'll happily send us to sleep. In any case, when
+ * get_chip returns success we're clear to go ahead.
+ */
+ int ret = spin_trylock(contender->mutex);
+ spin_unlock(&shared->lock);
+ if (!ret)
+ goto retry;
+ spin_unlock(chip->mutex);
+ ret = get_chip(map, contender, contender->start, mode);
+ spin_lock(chip->mutex);
+ if (ret) {
+ spin_unlock(contender->mutex);
+ return ret;
+ }
+ timeo = jiffies + HZ;
+ spin_lock(&shared->lock);
+ }
+
+ /* We now own it */
+ shared->writing = chip;
+ if (mode == FL_ERASING)
+ shared->erasing = chip;
+ if (contender && contender != chip)
+ spin_unlock(contender->mutex);
+ spin_unlock(&shared->lock);
+ }
+
switch (chip->state) {
case FL_STATUS:
for (;;) {
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* At this point we're fine with write operations
+ in other partitions as they don't conflict. */
+ if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
break;
if (time_after(jiffies, timeo)) {
- printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n",
- (long long)status);
- spin_unlock(chip->mutex);
+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n",
+ status.x[0]);
return -EIO;
}
spin_unlock(chip->mutex);
/* Erase suspend */
- cfi_write(map, CMD(0xB0), adr);
+ map_write(map, CMD(0xB0), adr);
/* If the flash has finished erasing, then 'erase suspend'
* appears to make some (28F320) flash devices switch to
* 'read' mode. Make sure that we switch to 'read status'
* mode so we get the right data. --rmk
*/
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1;
for (;;) {
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
if (time_after(jiffies, timeo)) {
/* Urgh. Resume and pretend we weren't here. */
- cfi_write(map, CMD(0xd0), adr);
+ map_write(map, CMD(0xd0), adr);
/* Make sure we're in 'read status' mode if it had finished */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_ERASING;
chip->oldstate = FL_READY;
printk(KERN_ERR "Chip not ready after erase "
- "suspended: status = 0x%llx\n", status);
+ "suspended: status = 0x%lx\n", status.x[0]);
return -EIO;
}
{
struct cfi_private *cfi = map->fldrv_priv;
+ if (chip->priv) {
+ struct flchip_shared *shared = chip->priv;
+ spin_lock(&shared->lock);
+ if (shared->writing == chip) {
+ /* We own the ability to write, but we're done */
+ shared->writing = shared->erasing;
+ if (shared->writing && shared->writing != chip) {
+ /* give back ownership to who we loaned it from */
+ struct flchip *loaner = shared->writing;
+ spin_lock(loaner->mutex);
+ spin_unlock(&shared->lock);
+ spin_unlock(chip->mutex);
+ put_chip(map, loaner, loaner->start);
+ spin_lock(chip->mutex);
+ spin_unlock(loaner->mutex);
+ } else {
+ if (chip->oldstate != FL_ERASING) {
+ shared->erasing = NULL;
+ if (chip->oldstate != FL_WRITING)
+ shared->writing = NULL;
+ }
+ spin_unlock(&shared->lock);
+ }
+ }
+ }
+
switch(chip->oldstate) {
case FL_ERASING:
chip->state = chip->oldstate;
sending the 0x70 (Read Status) command to an erasing
chip and expecting it to be ignored, that's what we
do. */
- cfi_write(map, CMD(0xd0), adr);
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0xd0), adr);
+ map_write(map, CMD(0x70), adr);
chip->oldstate = FL_READY;
chip->state = FL_ERASING;
break;
case FL_READY:
case FL_STATUS:
+ case FL_JEDEC_QUERY:
/* We should really make set_vpp() count, rather than doing this */
DISABLE_VPP(map);
break;
adr += chip->start;
/* Ensure cmd read/writes are aligned. */
- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
+ cmd_addr = adr & ~(map_bankwidth(map)-1);
spin_lock(chip->mutex);
if (!ret) {
if (chip->state != FL_POINT && chip->state != FL_READY)
- cfi_write(map, CMD(0xff), cmd_addr);
+ map_write(map, CMD(0xff), cmd_addr);
chip->state = FL_POINT;
chip->ref_point_counter++;
int chipnum;
int ret = 0;
- if (from + len > mtd->size)
+ if (!map->virt || (from + len > mtd->size))
return -EINVAL;
*mtdbuf = (void *)map->virt + from;
- if(*mtdbuf == NULL)
- return -EINVAL; /* can not point this region */
*retlen = 0;
/* Now lock the chip(s) to POINT state */
adr += chip->start;
/* Ensure cmd read/writes are aligned. */
- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
+ cmd_addr = adr & ~(map_bankwidth(map)-1);
spin_lock(chip->mutex);
ret = get_chip(map, chip, cmd_addr, FL_READY);
}
if (chip->state != FL_POINT && chip->state != FL_READY) {
- cfi_write(map, CMD(0xff), cmd_addr);
+ map_write(map, CMD(0xff), cmd_addr);
chip->state = FL_READY;
}
}
return ret;
}
-
+#if 0
static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
{
struct map_info *map = mtd->priv;
}
if (chip->state != FL_JEDEC_QUERY) {
- cfi_write(map, CMD(0x90), chip->start);
+ map_write(map, CMD(0x90), chip->start);
chip->state = FL_JEDEC_QUERY;
}
return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
}
+#endif
-
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK;
+ map_word status, status_OK;
unsigned long timeo;
int z, ret=0;
}
ENABLE_VPP(map);
- cfi_write(map, CMD(0x40), adr);
- cfi_write(map, datum, adr);
+ map_write(map, CMD(0x40), adr);
+ map_write(map, datum, adr);
chip->state = FL_WRITING;
spin_unlock(chip->mutex);
+ INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
cfi_udelay(chip->word_write_time);
spin_lock(chip->mutex);
continue;
}
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
/* Done and happy. */
chip->state = FL_STATUS;
/* check for lock bit */
- if (status & CMD(0x02)) {
+ if (map_word_bitsset(map, status, CMD(0x02))) {
/* clear status */
- cfi_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x50), adr);
/* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
ret = -EROFS;
}
out:
ofs = to - (chipnum << cfi->chipshift);
/* If it's not bus-aligned, do the first byte write */
- if (ofs & (CFIDEV_BUSWIDTH-1)) {
- unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
+ if (ofs & (map_bankwidth(map)-1)) {
+ unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
int gap = ofs - bus_ofs;
- int i = 0, n = 0;
- u_char tmp_buf[8];
- cfi_word datum;
-
- while (gap--)
- tmp_buf[i++] = 0xff;
- while (len && i < CFIDEV_BUSWIDTH)
- tmp_buf[i++] = buf[n++], len--;
- while (i < CFIDEV_BUSWIDTH)
- tmp_buf[i++] = 0xff;
-
- if (cfi_buswidth_is_2()) {
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
- } else if (cfi_buswidth_is_8()) {
- datum = *(__u64*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
- }
+ int n;
+ map_word datum;
+
+ n = min_t(int, len, map_bankwidth(map)-gap);
+ datum = map_word_ff(map);
+ datum = map_word_load_partial(map, datum, buf, gap, n);
ret = do_write_oneword(map, &cfi->chips[chipnum],
bus_ofs, datum);
if (ret)
return ret;
-
+
+ len -= n;
ofs += n;
buf += n;
(*retlen) += n;
}
}
- while(len >= CFIDEV_BUSWIDTH) {
- cfi_word datum;
-
- if (cfi_buswidth_is_1()) {
- datum = *(__u8*)buf;
- } else if (cfi_buswidth_is_2()) {
- datum = *(__u16*)buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)buf;
- } else if (cfi_buswidth_is_8()) {
- datum = *(__u64*)buf;
- } else {
- return -EINVAL;
- }
+ while(len >= map_bankwidth(map)) {
+ map_word datum = map_word_load(map, buf);
ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum);
if (ret)
return ret;
- ofs += CFIDEV_BUSWIDTH;
- buf += CFIDEV_BUSWIDTH;
- (*retlen) += CFIDEV_BUSWIDTH;
- len -= CFIDEV_BUSWIDTH;
+ ofs += map_bankwidth(map);
+ buf += map_bankwidth(map);
+ (*retlen) += map_bankwidth(map);
+ len -= map_bankwidth(map);
if (ofs >> cfi->chipshift) {
chipnum ++;
}
}
- if (len & (CFIDEV_BUSWIDTH-1)) {
- int i = 0, n = 0;
- u_char tmp_buf[8];
- cfi_word datum;
-
- while (len--)
- tmp_buf[i++] = buf[n++];
- while (i < CFIDEV_BUSWIDTH)
- tmp_buf[i++] = 0xff;
-
- if (cfi_buswidth_is_2()) {
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
- } else if (cfi_buswidth_is_8()) {
- datum = *(__u64*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
- }
+ if (len & (map_bankwidth(map)-1)) {
+ map_word datum;
+
+ datum = map_word_ff(map);
+ datum = map_word_load_partial(map, datum, buf, 0, len);
ret = do_write_oneword(map, &cfi->chips[chipnum],
ofs, datum);
if (ret)
return ret;
- (*retlen) += n;
+ (*retlen) += len;
}
return 0;
unsigned long adr, const u_char *buf, int len)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK;
+ map_word status, status_OK;
unsigned long cmd_adr, timeo;
int wbufsize, z, ret=0, bytes, words;
- wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+ wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
adr += chip->start;
cmd_adr = adr & ~(wbufsize-1);
return ret;
}
- if (chip->state != FL_STATUS)
- cfi_write(map, CMD(0x70), cmd_adr);
-
- status = cfi_read(map, cmd_adr);
-
/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
[...], the device will not accept any more Write to Buffer commands".
So we must check here and reset those bits if they're set. Otherwise
we're just pissing in the wind */
- if (status & CMD(0x30)) {
- printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %llx). Clearing.\n", status);
- cfi_write(map, CMD(0x50), cmd_adr);
- cfi_write(map, CMD(0x70), cmd_adr);
+ if (chip->state != FL_STATUS)
+ map_write(map, CMD(0x70), cmd_adr);
+ status = map_read(map, cmd_adr);
+ if (map_word_bitsset(map, status, CMD(0x30))) {
+ printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
+ map_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
}
+
ENABLE_VPP(map);
chip->state = FL_WRITING_TO_BUFFER;
z = 0;
for (;;) {
- cfi_write(map, CMD(0xe8), cmd_adr);
+ map_write(map, CMD(0xe8), cmd_adr);
- status = cfi_read(map, cmd_adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
spin_unlock(chip->mutex);
if (++z > 20) {
/* Argh. Not ready for write to buffer */
- cfi_write(map, CMD(0x70), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
+ printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
+ status.x[0], map_read(map, cmd_adr).x[0]);
/* Odd. Clear status bits */
- cfi_write(map, CMD(0x50), cmd_adr);
- cfi_write(map, CMD(0x70), cmd_adr);
+ map_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
ret = -EIO;
goto out;
}
}
/* Write length of data to come */
- bytes = len & (CFIDEV_BUSWIDTH-1);
- words = len / CFIDEV_BUSWIDTH;
- cfi_write(map, CMD(words - !bytes), cmd_adr );
+ bytes = len & (map_bankwidth(map)-1);
+ words = len / map_bankwidth(map);
+ map_write(map, CMD(words - !bytes), cmd_adr );
/* Write data */
z = 0;
- while(z < words * CFIDEV_BUSWIDTH) {
- if (cfi_buswidth_is_1()) {
- u8 *b = (u8 *)buf;
-
- map_write8 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else if (cfi_buswidth_is_2()) {
- u16 *b = (u16 *)buf;
-
- map_write16 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else if (cfi_buswidth_is_4()) {
- u32 *b = (u32 *)buf;
-
- map_write32 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else if (cfi_buswidth_is_8()) {
- u64 *b = (u64 *)buf;
-
- map_write64 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else {
- ret = -EINVAL;
- goto out;
- }
- z += CFIDEV_BUSWIDTH;
+ while(z < words * map_bankwidth(map)) {
+ map_word datum = map_word_load(map, buf);
+ map_write(map, datum, adr+z);
+
+ z += map_bankwidth(map);
+ buf += map_bankwidth(map);
}
+
if (bytes) {
- int i = 0, n = 0;
- u_char tmp_buf[8], *tmp_p = tmp_buf;
-
- while (bytes--)
- tmp_buf[i++] = buf[n++];
- while (i < CFIDEV_BUSWIDTH)
- tmp_buf[i++] = 0xff;
- if (cfi_buswidth_is_2()) {
- u16 *b = (u16 *)tmp_p;
-
- map_write16 (map, *b++, adr+z);
- tmp_p = (u_char *)b;
- } else if (cfi_buswidth_is_4()) {
- u32 *b = (u32 *)tmp_p;
-
- map_write32 (map, *b++, adr+z);
- tmp_p = (u_char *)b;
- } else if (cfi_buswidth_is_8()) {
- u64 *b = (u64 *)tmp_p;
-
- map_write64 (map, *b++, adr+z);
- tmp_p = (u_char *)b;
- } else {
- ret = -EINVAL;
- goto out;
- }
+ map_word datum;
+
+ datum = map_word_ff(map);
+ datum = map_word_load_partial(map, datum, buf, 0, bytes);
+ map_write(map, datum, adr+z);
}
+
/* GO GO GO */
- cfi_write(map, CMD(0xd0), cmd_adr);
+ map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
spin_unlock(chip->mutex);
+ INVALIDATE_CACHED_RANGE(map, adr, len);
cfi_udelay(chip->buffer_write_time);
spin_lock(chip->mutex);
continue;
}
- status = cfi_read(map, cmd_adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
chip->state = FL_STATUS;
/* check for lock bit */
- if (status & CMD(0x02)) {
+ if (map_word_bitsset(map, status, CMD(0x02))) {
/* clear status */
- cfi_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x50), cmd_adr);
/* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
ret = -EROFS;
}
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
int ret = 0;
int chipnum;
unsigned long ofs;
ofs = to - (chipnum << cfi->chipshift);
/* If it's not bus-aligned, do the first word write */
- if (ofs & (CFIDEV_BUSWIDTH-1)) {
- size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1);
+ if (ofs & (map_bankwidth(map)-1)) {
+ size_t local_len = (-ofs)&(map_bankwidth(map)-1);
if (local_len > len)
local_len = len;
ret = cfi_intelext_write_words(mtd, to, local_len,
}
}
- /* Write buffer is worth it only if more than one word to write... */
while(len) {
/* We must not cross write block boundaries */
int size = wbufsize - (ofs & (wbufsize-1));
}
typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
- unsigned long adr, void *thunk);
+ unsigned long adr, int len, void *thunk);
static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
loff_t ofs, size_t len, void *thunk)
i=first;
while(len) {
- ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+ unsigned long chipmask;
+ int size = regions[i].erasesize;
+
+ ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
if (ret)
return ret;
- adr += regions[i].erasesize;
- len -= regions[i].erasesize;
+ adr += size;
+ len -= size;
- if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+ chipmask = (1 << cfi->chipshift) - 1;
+ if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
i++;
if (adr >> cfi->chipshift) {
}
-static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK;
+ map_word status, status_OK;
unsigned long timeo;
int retries = 3;
DECLARE_WAITQUEUE(wait, current);
ENABLE_VPP(map);
/* Clear the status register first */
- cfi_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x50), adr);
/* Now erase */
- cfi_write(map, CMD(0x20), adr);
- cfi_write(map, CMD(0xD0), adr);
+ map_write(map, CMD(0x20), adr);
+ map_write(map, CMD(0xD0), adr);
chip->state = FL_ERASING;
chip->erase_suspended = 0;
spin_unlock(chip->mutex);
+ INVALIDATE_CACHED_RANGE(map, adr, len);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((chip->erase_time*HZ)/(2*1000));
spin_lock(chip->mutex);
chip->erase_suspended = 0;
}
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
- adr, (__u64)status, (__u64)cfi_read(map, adr));
+ printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %lx, status = %lx.\n",
+ adr, status.x[0], map_read(map, adr).x[0]);
/* Clear status bits */
- cfi_write(map, CMD(0x50), adr);
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x70), adr);
DISABLE_VPP(map);
spin_unlock(chip->mutex);
return -EIO;
ret = 0;
/* We've broken this before. It doesn't hurt to be safe */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- status = cfi_read(map, adr);
+ status = map_read(map, adr);
/* check for lock bit */
- if (status & CMD(0x3a)) {
- unsigned char chipstatus = status;
- if (status != CMD(status & 0xff)) {
- int i;
- for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
- chipstatus |= status >> (cfi->device_type * 8);
+ if (map_word_bitsset(map, status, CMD(0x3a))) {
+ unsigned char chipstatus = status.x[0];
+ if (!map_word_equal(map, status, CMD(chipstatus))) {
+ int i, w;
+ for (w=0; w<map_words(map); w++) {
+ for (i = 0; i<cfi_interleave(cfi); i++) {
+ chipstatus |= status.x[w] >> (cfi->device_type * 8);
+ }
}
- printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
+ printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
+ status.x[0], chipstatus);
}
/* Reset the error bits */
- cfi_write(map, CMD(0x50), adr);
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x70), adr);
if ((chipstatus & 0x30) == 0x30) {
- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x02) {
/* Protection bit set */
ret = -EROFS;
} else if (chipstatus & 0x8) {
/* Voltage */
- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status);
+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x20) {
if (retries--) {
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ;
chip->state = FL_STATUS;
spin_unlock(chip->mutex);
goto retry;
}
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
ret = -EIO;
}
}
}
#ifdef DEBUG_LOCK_BITS
-static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
int ofs_factor = cfi->interleave * cfi->device_type;
cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
adr, cfi_read_query(map, adr+(2*ofs_factor)));
- cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-
+ chip->state = FL_JEDEC_QUERY;
return 0;
}
#endif
#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1)
#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2)
-static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, status_OK;
+ map_word status, status_OK;
unsigned long timeo = jiffies + HZ;
int ret;
}
ENABLE_VPP(map);
- cfi_write(map, CMD(0x60), adr);
+ map_write(map, CMD(0x60), adr);
if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
- cfi_write(map, CMD(0x01), adr);
+ map_write(map, CMD(0x01), adr);
chip->state = FL_LOCKING;
} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
- cfi_write(map, CMD(0xD0), adr);
+ map_write(map, CMD(0xD0), adr);
chip->state = FL_UNLOCKING;
} else
BUG();
timeo = jiffies + (HZ*20);
for (;;) {
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
+ printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n",
+ status.x[0], map_read(map, adr).x[0]);
DISABLE_VPP(map);
spin_unlock(chip->mutex);
return -EIO;
ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
#ifdef DEBUG_LOCK_BITS
- printk(KERN_DEBUG
- "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+ printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
+ __FUNCTION__, ret);
cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, 0);
#endif
ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
#ifdef DEBUG_LOCK_BITS
- printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+ printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
+ __FUNCTION__, ret);
cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
ofs, len, 0);
#endif
/* Go to known state. Chip may have been power cycled */
if (chip->state == FL_PM_SUSPENDED) {
- cfi_write(map, CMD(0xFF), 0);
+ map_write(map, CMD(0xFF), cfi->chips[i].start);
chip->state = FL_READY;
wake_up(&chip->wq);
}
struct cfi_private *cfi = map->fldrv_priv;
kfree(cfi->cmdset_priv);
kfree(cfi->cfiq);
+ kfree(cfi->chips[0].priv);
kfree(cfi);
kfree(mtd->eraseregions);
}
* AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
*
* Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
+ * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
*
* 2_by_8 routines added by Simon Munton
*
+ * 4_by_16 work by Carolyn J. Smith
+ *
+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
+ *
* This code is GPL
*
- * $Id: cfi_cmdset_0002.c,v 1.74 2003/05/28 12:51:48 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.103 2004/07/14 16:24:03 dwmw2 Exp $
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/mtd/compatmac.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/cfi.h>
-#include <linux/mtd/compatmac.h>
#define AMD_BOOTLOC_BUG
+#define FORCE_WORD_WRITE 0
+
+#define MAX_WORD_RETRIES 3
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
-static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
+static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t);
+static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t);
static void cfi_amdstd_sync (struct mtd_info *);
static int cfi_amdstd_suspend (struct mtd_info *);
static void cfi_amdstd_resume (struct mtd_info *);
};
+/* #define DEBUG_LOCK_BITS */
+/* #define DEBUG_CFI_FEATURES */
+
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_amdstd *extp)
+{
+ const char* erase_suspend[3] = {
+ "Not supported", "Read only", "Read/write"
+ };
+ const char* top_bottom[6] = {
+ "No WP", "8x8KiB sectors at top & bottom, no WP",
+ "Bottom boot", "Top boot",
+ "Uniform, Bottom WP", "Uniform, Top WP"
+ };
+
+ printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1);
+ printk(" Address sensitive unlock: %s\n",
+ (extp->SiliconRevision & 1) ? "Not required" : "Required");
+
+ if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
+ printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
+ else
+ printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
+
+ if (extp->BlkProt == 0)
+ printk(" Block protection: Not supported\n");
+ else
+ printk(" Block protection: %d sectors per group\n", extp->BlkProt);
+
+
+ printk(" Temporary block unprotect: %s\n",
+ extp->TmpBlkUnprotect ? "Supported" : "Not supported");
+ printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
+ printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps);
+ printk(" Burst mode: %s\n",
+ extp->BurstMode ? "Supported" : "Not supported");
+ if (extp->PageMode == 0)
+ printk(" Page mode: Not supported\n");
+ else
+ printk(" Page mode: %d word page\n", extp->PageMode << 2);
+
+ printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
+ extp->VppMin >> 4, extp->VppMin & 0xf);
+ printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
+ extp->VppMax >> 4, extp->VppMax & 0xf);
+
+ if (extp->TopBottom < ARRAY_SIZE(top_bottom))
+ printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
+ else
+ printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
+}
+#endif
+
+#ifdef AMD_BOOTLOC_BUG
+/* Wheee. Bring me the head of someone at AMD. */
+static void fixup_amd_bootblock(struct map_info *map, void* param)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+ __u8 major = extp->MajorVersion;
+ __u8 minor = extp->MinorVersion;
+
+ if (((major << 8) | minor) < 0x3131) {
+ /* CFI version 1.0 => don't trust bootloc */
+ if (cfi->id & 0x80) {
+ printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
+ extp->TopBottom = 3; /* top boot */
+ } else {
+ extp->TopBottom = 2; /* bottom boot */
+ }
+ }
+}
+#endif
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef AMD_BOOTLOC_BUG
+ {
+ 0x0001, /* AMD */
+ CFI_ID_ANY,
+ fixup_amd_bootblock, NULL
+ },
+#endif
+ { 0, 0, NULL, NULL }
+};
+
+
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned char bootloc;
- int ofs_factor = cfi->interleave * cfi->device_type;
int i;
- __u8 major, minor;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode==CFI_MODE_CFI){
+ /*
+ * It's a real CFI chip, not one for which the probe
+ * routine faked a CFI structure. So we read the feature
+ * table from it.
+ */
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+ struct cfi_pri_amdstd *extp;
+
+ extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
+ if (!extp)
+ return NULL;
+
+ /* Install our own private info structure */
+ cfi->cmdset_priv = extp;
+
+ cfi_fixup(map, fixup_table);
+
+#ifdef DEBUG_CFI_FEATURES
+ /* Tell the user about it in lots of lovely detail */
+ cfi_tell_features(extp);
+#endif
+
+ bootloc = extp->TopBottom;
+ if ((bootloc != 2) && (bootloc != 3)) {
+ printk(KERN_WARNING "%s: CFI does not contain boot "
+ "bank location. Assuming top.\n", map->name);
+ bootloc = 2;
+ }
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- major = cfi_read_query(map, base + (adr+3)*ofs_factor);
- minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
-
- printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
- major, minor, adr);
- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
- /* FIXME - should have a delay before continuing */
- cfi->mfr = cfi_read_query(map, base);
- cfi->id = cfi_read_query(map, base + ofs_factor);
-
- /* Wheee. Bring me the head of someone at AMD. */
-#ifdef AMD_BOOTLOC_BUG
- if (((major << 8) | minor) < 0x3131) {
- /* CFI version 1.0 => don't trust bootloc */
- if (cfi->id & 0x80) {
- printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
- bootloc = 3; /* top boot */
- } else {
- bootloc = 2; /* bottom boot */
- }
- } else
-#endif
- {
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
- bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
- }
if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
}
}
/*
- * FIXME - These might already be setup (more correctly)
- * buy jedec_probe.c.
+ * These might already be setup (more correctly) by
+ * jedec_probe.c - still need it for cfi_probe.c path.
*/
- switch (cfi->device_type) {
- case CFI_DEVICETYPE_X8:
- cfi->addr_unlock1 = 0x555;
- cfi->addr_unlock2 = 0x2aa;
- break;
- case CFI_DEVICETYPE_X16:
- cfi->addr_unlock1 = 0xaaa;
- if (map->buswidth == cfi->interleave) {
- /* X16 chip(s) in X8 mode */
- cfi->addr_unlock2 = 0x555;
- } else {
- cfi->addr_unlock2 = 0x554;
+ if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) {
+ switch (cfi->device_type) {
+ case CFI_DEVICETYPE_X8:
+ cfi->addr_unlock1 = 0x555;
+ cfi->addr_unlock2 = 0x2aa;
+ break;
+ case CFI_DEVICETYPE_X16:
+ cfi->addr_unlock1 = 0xaaa;
+ if (map_bankwidth(map) == cfi_interleave(cfi)) {
+ /* X16 chip(s) in X8 mode */
+ cfi->addr_unlock2 = 0x555;
+ } else {
+ cfi->addr_unlock2 = 0x554;
+ }
+ break;
+ case CFI_DEVICETYPE_X32:
+ cfi->addr_unlock1 = 0x1554;
+ if (map_bankwidth(map) == cfi_interleave(cfi)*2) {
+ /* X32 chip(s) in X16 mode */
+ cfi->addr_unlock1 = 0xaaa;
+ } else {
+ cfi->addr_unlock2 = 0xaa8;
+ }
+ break;
+ default:
+ printk(KERN_WARNING
+ "MTD %s(): Unsupported device type %d\n",
+ __func__, cfi->device_type);
+ return NULL;
}
- break;
- case CFI_DEVICETYPE_X32:
- cfi->addr_unlock1 = 0x1555;
- cfi->addr_unlock2 = 0xaaa;
- break;
- default:
- printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
- return NULL;
}
+
} /* CFI mode */
for (i=0; i< cfi->numchips; i++) {
map->fldrv = &cfi_amdstd_chipdrv;
- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_amdstd_setup(map);
}
+
static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
{
struct cfi_private *cfi = map->fldrv_priv;
struct mtd_info *mtd;
unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+ unsigned long offset = 0;
+ int i,j;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
printk(KERN_NOTICE "number of %s chips: %d\n",
- (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
+ (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
if (!mtd) {
- printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
- goto setup_err;
+ printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
+ goto setup_err;
}
memset(mtd, 0, sizeof(*mtd));
mtd->type = MTD_NORFLASH;
/* Also select the correct geometry setup too */
mtd->size = devsize * cfi->numchips;
-
- if (cfi->cfiq->NumEraseRegions == 1) {
- /* No need to muck about with multiple erase sizes */
- mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
- } else {
- unsigned long offset = 0;
- int i,j;
-
- mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
- if (!mtd->eraseregions) {
- printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
- goto setup_err;
- }
+
+ mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
+ * mtd->numeraseregions, GFP_KERNEL);
+ if (!mtd->eraseregions) {
+ printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
+ goto setup_err;
+ }
- for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
- unsigned long ernum, ersize;
- ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
- ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+ for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+ unsigned long ernum, ersize;
+ ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+ ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
- if (mtd->erasesize < ersize) {
- mtd->erasesize = ersize;
- }
- for (j=0; j<cfi->numchips; j++) {
- mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
- mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
- mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
- }
- offset += (ersize * ernum);
+ if (mtd->erasesize < ersize) {
+ mtd->erasesize = ersize;
}
- if (offset != devsize) {
- /* Argh */
- printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
- goto setup_err;
+ for (j=0; j<cfi->numchips; j++) {
+ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
}
+ offset += (ersize * ernum);
+ }
+ if (offset != devsize) {
+ /* Argh */
+ printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+ goto setup_err;
+ }
#if 0
- // debug
- for (i=0; i<mtd->numeraseregions;i++){
- printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
- i,mtd->eraseregions[i].offset,
- mtd->eraseregions[i].erasesize,
- mtd->eraseregions[i].numblocks);
- }
-#endif
+ // debug
+ for (i=0; i<mtd->numeraseregions;i++){
+ printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
+ i,mtd->eraseregions[i].offset,
+ mtd->eraseregions[i].erasesize,
+ mtd->eraseregions[i].numblocks);
}
-
- switch (CFIDEV_BUSWIDTH)
- {
- case 1:
- case 2:
- case 4:
-#if 1
- if (mtd->numeraseregions > 1)
- mtd->erase = cfi_amdstd_erase_varsize;
- else
#endif
- if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
- mtd->erase = cfi_amdstd_erase_chip;
- else
- mtd->erase = cfi_amdstd_erase_onesize;
- mtd->read = cfi_amdstd_read;
- mtd->write = cfi_amdstd_write;
- break;
- default:
- printk(KERN_WARNING "Unsupported buswidth\n");
- goto setup_err;
- break;
+ if (mtd->numeraseregions == 1
+ && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) {
+ mtd->erase = cfi_amdstd_erase_chip;
+ } else {
+ mtd->erase = cfi_amdstd_erase_varsize;
+ mtd->lock = cfi_amdstd_lock_varsize;
+ mtd->unlock = cfi_amdstd_unlock_varsize;
}
- if (cfi->fast_prog) {
- /* In cfi_amdstd_write() we frob the protection stuff
- without paying any attention to the state machine.
- This upsets in-progress erases. So we turn this flag
- off for now till the code gets fixed. */
- printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
- cfi->fast_prog = 0;
+
+ if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
+ DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
+ mtd->write = cfi_amdstd_write_buffers;
+ } else {
+ DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" );
+ mtd->write = cfi_amdstd_write_words;
}
+ mtd->read = cfi_amdstd_read;
- /* does this chip have a secsi area? */
+ /* FIXME: erase-suspend-program is broken. See
+ http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
+
+ /* does this chip have a secsi area? */
if(cfi->mfr==1){
switch(cfi->id){
return NULL;
}
-static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+/*
+ * Return true if the chip is ready.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and is indicated by no toggle bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ */
+static int chip_ready(struct map_info *map, unsigned long addr)
+{
+ map_word d, t;
+
+ d = map_read(map, addr);
+ t = map_read(map, addr);
+
+ return map_word_equal(map, d, t);
+}
+
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
- unsigned long timeo = jiffies + HZ;
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long timeo;
+ struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
+ resettime:
+ timeo = jiffies + HZ;
retry:
- cfi_spin_lock(chip->mutex);
+ switch (chip->state) {
- if (chip->state != FL_READY){
-#if 0
- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
-#endif
+ case FL_STATUS:
+ for (;;) {
+ if (chip_ready(map, adr))
+ break;
+
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
+ cfi_spin_unlock(chip->mutex);
+ return -EIO;
+ }
+ cfi_spin_unlock(chip->mutex);
+ cfi_udelay(1);
+ cfi_spin_lock(chip->mutex);
+ /* Someone else might have been playing with it. */
+ goto retry;
+ }
+
+ case FL_READY:
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ return 0;
+
+ case FL_ERASING:
+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
+ goto sleep;
+
+ if (!(mode == FL_READY || mode == FL_POINT
+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
+ goto sleep;
+
+ /* We could check to see if we're trying to access the sector
+ * that is currently being erased. However, no user will try
+ * anything like that so we just wait for the timeout. */
+
+ /* Erase suspend */
+ /* It's harmless to issue the Erase-Suspend and Erase-Resume
+ * commands when the erase algorithm isn't in progress. */
+ map_write(map, CMD(0xB0), chip->in_progress_block_addr);
+ chip->oldstate = FL_ERASING;
+ chip->state = FL_ERASE_SUSPENDING;
+ chip->erase_suspended = 1;
+ for (;;) {
+ if (chip_ready(map, adr))
+ break;
+
+ if (time_after(jiffies, timeo)) {
+ /* Should have suspended the erase by now.
+ * Send an Erase-Resume command as either
+ * there was an error (so leave the erase
+ * routine to recover from it) or we trying to
+ * use the erase-in-progress sector. */
+ map_write(map, CMD(0x30), chip->in_progress_block_addr);
+ chip->state = FL_ERASING;
+ chip->oldstate = FL_READY;
+ printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
+ return -EIO;
+ }
+
+ cfi_spin_unlock(chip->mutex);
+ cfi_udelay(1);
+ cfi_spin_lock(chip->mutex);
+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
+ So we can just loop here. */
+ }
+ chip->state = FL_READY;
+ return 0;
+
+ case FL_POINT:
+ /* Only if there's no operation suspended... */
+ if (mode == FL_READY && chip->oldstate == FL_READY)
+ return 0;
+
+ default:
+ sleep:
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
-
cfi_spin_unlock(chip->mutex);
-
schedule();
remove_wait_queue(&chip->wq, &wait);
-#if 0
- if(signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + HZ;
+ cfi_spin_lock(chip->mutex);
+ goto resettime;
+ }
+}
- goto retry;
- }
+
+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ switch(chip->oldstate) {
+ case FL_ERASING:
+ chip->state = chip->oldstate;
+ map_write(map, CMD(0x30), chip->in_progress_block_addr);
+ chip->oldstate = FL_READY;
+ chip->state = FL_ERASING;
+ break;
+
+ case FL_READY:
+ case FL_STATUS:
+ /* We should really make set_vpp() count, rather than doing this */
+ DISABLE_VPP(map);
+ break;
+ default:
+ printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
+ }
+ wake_up(&chip->wq);
+}
+
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+ unsigned long cmd_addr;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret;
adr += chip->start;
- chip->state = FL_READY;
+ /* Ensure cmd read/writes are aligned. */
+ cmd_addr = adr & ~(map_bankwidth(map)-1);
+
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, cmd_addr, FL_READY);
+ if (ret) {
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ if (chip->state != FL_POINT && chip->state != FL_READY) {
+ map_write(map, CMD(0xf0), cmd_addr);
+ chip->state = FL_READY;
+ }
map_copy_from(map, buf, adr, len);
- wake_up(&chip->wq);
- cfi_spin_unlock(chip->mutex);
+ put_chip(map, chip, cmd_addr);
+ cfi_spin_unlock(chip->mutex);
return 0;
}
+
static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
struct map_info *map = mtd->priv;
return ret;
}
+
static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
DECLARE_WAITQUEUE(wait, current);
if (chip->state != FL_READY){
#if 0
- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+ printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
#endif
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
-
+
cfi_spin_unlock(chip->mutex);
schedule();
adr += chip->start;
chip->state = FL_READY;
-
+
+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
map_copy_from(map, buf, adr, len);
+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
return ret;
}
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast)
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
{
- unsigned long timeo = jiffies + HZ;
- unsigned int oldstatus, status, prev_oldstatus, prev_status;
- unsigned int dq6;
struct cfi_private *cfi = map->fldrv_priv;
- /* We use a 1ms + 1 jiffies generic timeout for writes (most devices have
- a max write time of a few hundreds usec). However, we should use the
- maximum timeout value given by the chip at probe time instead.
- Unfortunately, struct flchip does have a field for maximum timeout,
- only for typical which can be far too short depending of the conditions.
- The ' + 1' is to avoid having a timeout of 0 jiffies if HZ is smaller
- than 1000. Using a static variable allows makes us save the costly
- divide operation at each word write.*/
- static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
- DECLARE_WAITQUEUE(wait, current);
+ unsigned long timeo = jiffies + HZ;
+ /*
+ * We use a 1ms + 1 jiffies generic timeout for writes (most devices
+ * have a max write time of a few hundreds usec). However, we should
+ * use the maximum timeout value given by the chip at probe time
+ * instead. Unfortunately, struct flchip does have a field for
+ * maximum timeout, only for typical which can be far too short
+ * depending of the conditions. The ' + 1' is to avoid having a
+ * timeout of 0 jiffies if HZ is smaller than 1000.
+ */
+ unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
int ret = 0;
- int ta = 0;
+ map_word oldd, curd;
+ int retry_cnt = 0;
- retry:
- cfi_spin_lock(chip->mutex);
+ adr += chip->start;
- if (chip->state != FL_READY) {
-#if 0
- printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
-#endif
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_WRITING);
+ if (ret) {
cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-#if 0
- printk(KERN_DEBUG "Wake up to write:\n");
- if(signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + HZ;
-
- goto retry;
- }
-
- chip->state = FL_WRITING;
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
+ __func__, adr, datum.x[0] );
- adr += chip->start;
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8llx)\n",
- __func__, adr, datum );
+ /*
+ * Check for a NOP for the case when the datum to write is already
+ * present - it saves time and works around buggy chips that corrupt
+ * data at other locations when 0xff is written to a location that
+ * already contains 0xff.
+ */
+ oldd = map_read(map, adr);
+ if (map_word_equal(map, oldd, datum)) {
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n",
+ __func__);
+ goto op_done;
+ }
ENABLE_VPP(map);
- if (fast) { /* Unlock bypass */
- cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
- }
- else {
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
- cfi_write(map, datum, adr);
+ retry:
+ /*
+ * The CFI_DEVICETYPE_X8 argument is needed even when
+ * cfi->device_type != CFI_DEVICETYPE_X8. The addresses for
+ * command sequences don't scale even when the device is
+ * wider. This is the case for many of the cfi_send_gen_cmd()
+ * below. I'm not sure, however, why some use
+ * cfi->device_type.
+ */
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ map_write(map, datum, adr);
+ chip->state = FL_WRITING;
cfi_spin_unlock(chip->mutex);
cfi_udelay(chip->word_write_time);
cfi_spin_lock(chip->mutex);
- /*
- * Polling toggle bits instead of reading back many times
- * This ensures that write operation is really completed,
- * or tells us why it failed.
- *
- * It appears tha the polling and decoding of error state might
- * be simplified. Don't do it unless you really know what you
- * are doing. You must remember that JESD21-C 3.5.3 states that
- * the status must be read back an _additional_ two times before
- * a failure is determined. This is because these devices have
- * internal state machines that are asynchronous to the external
- * data bus. During an erase or write the read-back status of the
- * polling bits might be transitioning internaly when the external
- * read-back occurs. This means that the bits aren't in the final
- * state and they might appear to report an error as they transition
- * and are in a weird state. This will produce infrequent errors
- * that will usually disappear the next time an erase or write
- * happens (Try tracking those errors down!). To ensure that
- * the bits are not in transition the location must be read-back
- * two more times and compared against what was written - BOTH reads
- * MUST match what was written - don't think this can be simplified
- * to only the last read matching. If the comparison fails, error
- * state can then be decoded.
- *
- * - Thayne Harbaugh
- */
- dq6 = CMD(1<<6);
/* See comment above for timeout value. */
timeo = jiffies + uWriteTimeout;
-
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- /*
- * This only checks if dq6 is still toggling and that our
- * timer hasn't expired. We purposefully ignore the chips
- * internal timer that will assert dq5 and leave dq6 toggling.
- * This is done for a variety of reasons:
- * 1) Not all chips support dq5.
- * 2) Dealing with asynchronous status bit and data updates
- * and reading a device two more times creates _messy_
- * logic when trying to deal with interleaved devices -
- * some may be changing while others are still busy.
- * 3) Checking dq5 only helps to optimize an error case that
- * should at worst be infrequent and at best non-existent.
- *
- * If our timeout occurs _then_ we will check dq5 to see
- * if the device also had an internal timeout.
- */
- while( ( ( status ^ oldstatus ) & dq6 )
- && ! ( ta = time_after(jiffies, timeo) ) ) {
+ for (;;) {
+ if (chip->state != FL_WRITING) {
+ /* Someone's suspended the write. Sleep */
+ DECLARE_WAITQUEUE(wait, current);
- if (need_resched()) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
cfi_spin_unlock(chip->mutex);
- yield();
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ timeo = jiffies + (HZ / 2); /* FIXME */
cfi_spin_lock(chip->mutex);
- } else
- udelay(1);
-
- oldstatus = cfi_read( map, adr );
- status = cfi_read( map, adr );
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- }
+ continue;
+ }
- /*
- * Something kicked us out of the read-back loop. We'll
- * check success befor checking failure.
- * Even though dq6 might be true data, it is unkown if
- * all of the other bits have changed to true data due to
- * the asynchronous nature of the internal state machine.
- * We will read two more times and use this to either
- * verify that the write completed successfully or
- * that something really went wrong. BOTH reads
- * must match what was written - this certifies that
- * bits aren't still changing and that the status
- * bits erroneously match the datum that was written.
- */
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( oldstatus == datum && status == datum ) {
- /* success - do nothing */
- goto write_done;
- }
+ /* Test to see if toggling has stopped. */
+ oldd = map_read(map, adr);
+ curd = map_read(map, adr);
+ if (map_word_equal(map, curd, oldd)) {
+ /* Do we have the correct value? */
+ if (map_word_equal(map, curd, datum)) {
+ goto op_done;
+ }
+ /* Nope something has gone wrong. */
+ break;
+ }
- if ( ta ) {
- int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x\n",
- __func__,
- status & dq5mask );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
+ break;
}
- goto write_failed;
- }
-
- /*
- * If we get to here then it means that something
- * is wrong and it's not a timeout. Something
- * is seriously wacky! Dump some debug info.
- */
- printk(KERN_WARNING
- "MTD %s(): Wacky! Unable to decode failure status\n",
- __func__ );
- printk(KERN_WARNING
- "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
- __func__, adr, datum,
- prev_oldstatus, prev_status,
- oldstatus, status);
+ /* Latency issues. Drop the lock, wait a while and retry */
+ cfi_spin_unlock(chip->mutex);
+ cfi_udelay(1);
+ cfi_spin_lock(chip->mutex);
+ }
- write_failed:
- ret = -EIO;
/* reset on all failures. */
- cfi_write( map, CMD(0xF0), chip->start );
+ map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
+ if (++retry_cnt <= MAX_WORD_RETRIES)
+ goto retry;
- write_done:
- DISABLE_VPP(map);
+ ret = -EIO;
+ op_done:
chip->state = FL_READY;
- wake_up(&chip->wq);
+ put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
return ret;
}
-static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
+
+static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
int ret = 0;
int chipnum;
unsigned long ofs, chipstart;
+ DECLARE_WAITQUEUE(wait, current);
*retlen = 0;
if (!len)
chipstart = cfi->chips[chipnum].start;
/* If it's not bus-aligned, do the first byte write */
- if (ofs & (CFIDEV_BUSWIDTH-1)) {
- unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
+ if (ofs & (map_bankwidth(map)-1)) {
+ unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
int i = ofs - bus_ofs;
int n = 0;
- u_char tmp_buf[8];
- cfi_word datum;
+ map_word tmp_buf;
- map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
- while (len && i < CFIDEV_BUSWIDTH)
- tmp_buf[i++] = buf[n++], len--;
+ retry:
+ cfi_spin_lock(cfi->chips[chipnum].mutex);
- if (cfi_buswidth_is_2()) {
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
+ if (cfi->chips[chipnum].state != FL_READY) {
+#if 0
+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
+#endif
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
+
+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+ schedule();
+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
+#if 0
+ if(signal_pending(current))
+ return -EINTR;
+#endif
+ goto retry;
}
+ /* Load 'tmp_buf' with old contents of flash */
+ tmp_buf = map_read(map, bus_ofs+chipstart);
+
+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+ /* Number of bytes to copy from buffer */
+ n = min_t(int, len, map_bankwidth(map)-i);
+
+ tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
+
ret = do_write_oneword(map, &cfi->chips[chipnum],
- bus_ofs, datum, 0);
+ bus_ofs, tmp_buf);
if (ret)
return ret;
ofs += n;
buf += n;
(*retlen) += n;
+ len -= n;
if (ofs >> cfi->chipshift) {
chipnum ++;
}
}
- if (cfi->fast_prog) {
- /* Go into unlock bypass mode */
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
-
/* We are now aligned, write as much as possible */
- while(len >= CFIDEV_BUSWIDTH) {
- cfi_word datum;
-
- if (cfi_buswidth_is_1()) {
- datum = *(__u8*)buf;
- } else if (cfi_buswidth_is_2()) {
- datum = *(__u16*)buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)buf;
- } else {
- return -EINVAL;
- }
- ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum, cfi->fast_prog);
- if (ret) {
- if (cfi->fast_prog){
- /* Get out of unlock bypass mode */
- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
- }
- return ret;
- }
+ while(len >= map_bankwidth(map)) {
+ map_word datum;
- ofs += CFIDEV_BUSWIDTH;
- buf += CFIDEV_BUSWIDTH;
- (*retlen) += CFIDEV_BUSWIDTH;
- len -= CFIDEV_BUSWIDTH;
+ datum = map_word_load(map, buf);
- if (ofs >> cfi->chipshift) {
- if (cfi->fast_prog){
- /* Get out of unlock bypass mode */
- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
- }
+ ret = do_write_oneword(map, &cfi->chips[chipnum],
+ ofs, datum);
+ if (ret)
+ return ret;
+
+ ofs += map_bankwidth(map);
+ buf += map_bankwidth(map);
+ (*retlen) += map_bankwidth(map);
+ len -= map_bankwidth(map);
+ if (ofs >> cfi->chipshift) {
chipnum ++;
ofs = 0;
if (chipnum == cfi->numchips)
return 0;
chipstart = cfi->chips[chipnum].start;
- if (cfi->fast_prog){
- /* Go into unlock bypass mode for next set of chips */
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
- }
}
}
- if (cfi->fast_prog){
- /* Get out of unlock bypass mode */
- cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
- cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
- }
-
/* Write the trailing bytes if any */
- if (len & (CFIDEV_BUSWIDTH-1)) {
- int i = 0, n = 0;
- u_char tmp_buf[8];
- cfi_word datum;
-
- map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
- while (len--)
- tmp_buf[i++] = buf[n++];
-
- if (cfi_buswidth_is_2()) {
- datum = *(__u16*)tmp_buf;
- } else if (cfi_buswidth_is_4()) {
- datum = *(__u32*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
+ if (len & (map_bankwidth(map)-1)) {
+ map_word tmp_buf;
+
+ retry1:
+ cfi_spin_lock(cfi->chips[chipnum].mutex);
+
+ if (cfi->chips[chipnum].state != FL_READY) {
+#if 0
+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
+#endif
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&cfi->chips[chipnum].wq, &wait);
+
+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+ schedule();
+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
+#if 0
+ if(signal_pending(current))
+ return -EINTR;
+#endif
+ goto retry1;
}
+ tmp_buf = map_read(map, ofs + chipstart);
+
+ cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+ tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
+
ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum, 0);
+ ofs, tmp_buf);
if (ret)
return ret;
- (*retlen) += n;
+ (*retlen) += len;
}
return 0;
}
-static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+
+/*
+ * FIXME: interleaved mode not tested, and probably not supported!
+ */
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
+ unsigned long adr, const u_char *buf, int len)
{
- unsigned int oldstatus, status, prev_oldstatus, prev_status;
- unsigned int dq6;
- unsigned long timeo = jiffies + HZ;
- unsigned long int adr;
struct cfi_private *cfi = map->fldrv_priv;
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
- int ta = 0;
- cfi_word ones = 0;
+ unsigned long timeo = jiffies + HZ;
+ /* see comments in do_write_oneword() regarding uWriteTimeo. */
+ static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+ int ret = -EIO;
+ unsigned long cmd_adr;
+ int z, words;
+ map_word datum;
- retry:
- cfi_spin_lock(chip->mutex);
+ adr += chip->start;
+ cmd_adr = adr;
- if (chip->state != FL_READY){
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_WRITING);
+ if (ret) {
cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-#if 0
- if(signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + HZ;
+ datum = map_word_load(map, buf);
- goto retry;
- }
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
+ __func__, adr, datum.x[0] );
- chip->state = FL_ERASING;
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
- __func__, chip->start );
-
- /* Handle devices with one erase region, that only implement
- * the chip erase command.
- */
ENABLE_VPP(map);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- timeo = jiffies + (HZ*20);
- adr = cfi->addr_unlock1;
+ //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- /* Wait for the end of programing/erasure by using the toggle method.
- * As long as there is a programming procedure going on, bit 6
- * is toggling it's state with each consecutive read.
- * The toggling stops as soon as the procedure is completed.
- *
- * If the process has gone on for too long on the chip bit 5 gets.
- * After bit5 is set you can kill the operation by sending a reset
- * command to the chip.
- */
- /* see comments in do_write_oneword */
- dq6 = CMD(1<<6);
+ /* Write Buffer Load */
+ map_write(map, CMD(0x25), cmd_adr);
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
+ chip->state = FL_WRITING_TO_BUFFER;
- while( ( ( status ^ oldstatus ) & dq6 )
- && ! ( ta = time_after(jiffies, timeo) ) ) {
- int wait_reps;
+ /* Write length of data to come */
+ words = len / map_bankwidth(map);
+ map_write(map, CMD(words - 1), cmd_adr);
+ /* Write data */
+ z = 0;
+ while(z < words * map_bankwidth(map)) {
+ datum = map_word_load(map, buf);
+ map_write(map, datum, adr + z);
- /* an initial short sleep */
- cfi_spin_unlock(chip->mutex);
- schedule_timeout(HZ/100);
- cfi_spin_lock(chip->mutex);
+ z += map_bankwidth(map);
+ buf += map_bankwidth(map);
+ }
+ z -= map_bankwidth(map);
+
+ adr += z;
+
+ /* Write Buffer Program Confirm: GO GO GO */
+ map_write(map, CMD(0x29), cmd_adr);
+ chip->state = FL_WRITING;
+
+ cfi_spin_unlock(chip->mutex);
+ cfi_udelay(chip->buffer_write_time);
+ cfi_spin_lock(chip->mutex);
+
+ timeo = jiffies + uWriteTimeout;
- if (chip->state != FL_ERASING) {
- /* Someone's suspended the erase. Sleep */
+ for (;;) {
+ if (chip->state != FL_WRITING) {
+ /* Someone's suspended the write. Sleep */
+ DECLARE_WAITQUEUE(wait, current);
+
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
-
cfi_spin_unlock(chip->mutex);
- printk("erase suspended. Sleeping\n");
-
schedule();
remove_wait_queue(&chip->wq, &wait);
-#if 0
- if (signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + (HZ*2); /* FIXME */
+ timeo = jiffies + (HZ / 2); /* FIXME */
cfi_spin_lock(chip->mutex);
continue;
}
- /* Busy wait for 1/10 of a milisecond */
- for(wait_reps = 0;
- (wait_reps < 100)
- && ( ( status ^ oldstatus ) & dq6 );
- wait_reps++) {
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
-
- cfi_udelay(1);
-
- cfi_spin_lock(chip->mutex);
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- }
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- }
-
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( cfi_buswidth_is_1() ) {
- ones = (__u8)~0;
- } else if ( cfi_buswidth_is_2() ) {
- ones = (__u16)~0;
- } else if ( cfi_buswidth_is_4() ) {
- ones = (__u32)~0;
- } else {
- printk(KERN_WARNING "Unsupported buswidth\n");
- goto erase_failed;
- }
-
- if ( oldstatus == ones && status == ones ) {
- /* success - do nothing */
- goto erase_done;
- }
+ if (chip_ready(map, adr))
+ goto op_done;
+
+ if( time_after(jiffies, timeo))
+ break;
- if ( ta ) {
- int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x\n",
- __func__,
- status & dq5mask );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto erase_failed;
+ /* Latency issues. Drop the lock, wait a while and retry */
+ cfi_spin_unlock(chip->mutex);
+ cfi_udelay(1);
+ cfi_spin_lock(chip->mutex);
}
- printk(KERN_WARNING
- "MTD %s(): Wacky! Unable to decode failure status\n",
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
- printk(KERN_WARNING
- "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
- __func__, adr, ones,
- prev_oldstatus, prev_status,
- oldstatus, status);
-
- erase_failed:
- ret = -EIO;
/* reset on all failures. */
- cfi_write( map, CMD(0xF0), chip->start );
+ map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- erase_done:
- DISABLE_VPP(map);
+ ret = -EIO;
+ op_done:
chip->state = FL_READY;
- wake_up(&chip->wq);
+ put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
+
return ret;
}
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
{
- unsigned int oldstatus, status, prev_oldstatus, prev_status;
- unsigned int dq6;
- unsigned long timeo = jiffies + HZ;
+ struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- DECLARE_WAITQUEUE(wait, current);
+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
int ret = 0;
- int ta = 0;
- cfi_word ones = 0;
+ int chipnum;
+ unsigned long ofs;
- retry:
- cfi_spin_lock(chip->mutex);
+ *retlen = 0;
+ if (!len)
+ return 0;
- if (chip->state != FL_READY){
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- cfi_spin_unlock(chip->mutex);
+ chipnum = to >> cfi->chipshift;
+ ofs = to - (chipnum << cfi->chipshift);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-#if 0
- if(signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + HZ;
+ /* If it's not bus-aligned, do the first word write */
+ if (ofs & (map_bankwidth(map)-1)) {
+ size_t local_len = (-ofs)&(map_bankwidth(map)-1);
+ if (local_len > len)
+ local_len = len;
+ ret = cfi_amdstd_write_words(mtd, to, local_len,
+ retlen, buf);
+ if (ret)
+ return ret;
+ ofs += local_len;
+ buf += local_len;
+ len -= local_len;
- goto retry;
- }
+ if (ofs >> cfi->chipshift) {
+ chipnum ++;
+ ofs = 0;
+ if (chipnum == cfi->numchips)
+ return 0;
+ }
+ }
- chip->state = FL_ERASING;
+ /* Write buffer is worth it only if more than one word to write... */
+ while (len >= map_bankwidth(map) * 2) {
+ /* We must not cross write block boundaries */
+ int size = wbufsize - (ofs & (wbufsize-1));
+
+ if (size > len)
+ size = len;
+ if (size % map_bankwidth(map))
+ size -= size % map_bankwidth(map);
+
+ ret = do_write_buffer(map, &cfi->chips[chipnum],
+ ofs, buf, size);
+ if (ret)
+ return ret;
+
+ ofs += size;
+ buf += size;
+ (*retlen) += size;
+ len -= size;
+
+ if (ofs >> cfi->chipshift) {
+ chipnum ++;
+ ofs = 0;
+ if (chipnum == cfi->numchips)
+ return 0;
+ }
+ }
+
+ if (len) {
+ size_t retlen_dregs = 0;
+
+ ret = cfi_amdstd_write_words(mtd, to, len, &retlen_dregs, buf);
+
+ *retlen += retlen_dregs;
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Handle devices with one erase region, that only implement
+ * the chip erase command.
+ */
+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long timeo = jiffies + HZ;
+ unsigned long int adr;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret = 0;
+
+ adr = cfi->addr_unlock1;
+
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_WRITING);
+ if (ret) {
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
- adr += chip->start;
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
- __func__, adr );
+ __func__, chip->start );
ENABLE_VPP(map);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
- cfi_write(map, CMD(0x30), adr);
-
- timeo = jiffies + (HZ*20);
-
- /* Wait for the end of programing/erasure by using the toggle method.
- * As long as there is a programming procedure going on, bit 6
- * is toggling it's state with each consecutive read.
- * The toggling stops as soon as the procedure is completed.
- *
- * If the process has gone on for too long on the chip bit 5 gets.
- * After bit5 is set you can kill the operation by sending a reset
- * command to the chip.
- */
- /* see comments in do_write_oneword */
- dq6 = CMD(1<<6);
+ chip->state = FL_ERASING;
+ chip->erase_suspended = 0;
+ chip->in_progress_block_addr = adr;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
+ cfi_spin_unlock(chip->mutex);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((chip->erase_time*HZ)/(2*1000));
+ cfi_spin_lock(chip->mutex);
- while( ( ( status ^ oldstatus ) & dq6 )
- && ! ( ta = time_after(jiffies, timeo) ) ) {
- int wait_reps;
+ timeo = jiffies + (HZ*20);
- /* an initial short sleep */
- cfi_spin_unlock(chip->mutex);
- schedule_timeout(HZ/100);
- cfi_spin_lock(chip->mutex);
-
+ for (;;) {
if (chip->state != FL_ERASING) {
/* Someone's suspended the erase. Sleep */
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
-
cfi_spin_unlock(chip->mutex);
- printk(KERN_DEBUG "erase suspended. Sleeping\n");
-
schedule();
remove_wait_queue(&chip->wq, &wait);
-#if 0
- if (signal_pending(current))
- return -EINTR;
-#endif
- timeo = jiffies + (HZ*2); /* FIXME */
cfi_spin_lock(chip->mutex);
continue;
}
-
- /* Busy wait for 1/10 of a milisecond */
- for(wait_reps = 0;
- (wait_reps < 100)
- && ( ( status ^ oldstatus ) & dq6 );
- wait_reps++) {
-
- /* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
-
- cfi_udelay(1);
-
- cfi_spin_lock(chip->mutex);
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
+ if (chip->erase_suspended) {
+ /* This erase was suspended and resumed.
+ Adjust the timeout */
+ timeo = jiffies + (HZ*20); /* FIXME */
+ chip->erase_suspended = 0;
}
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- }
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( cfi_buswidth_is_1() ) {
- ones = (__u8)~0;
- } else if ( cfi_buswidth_is_2() ) {
- ones = (__u16)~0;
- } else if ( cfi_buswidth_is_4() ) {
- ones = (__u32)~0;
- } else {
- printk(KERN_WARNING "Unsupported buswidth\n");
- goto erase_failed;
- }
+ if (chip_ready(map, adr))
+ goto op_done;
- if ( oldstatus == ones && status == ones ) {
- /* success - do nothing */
- goto erase_done;
- }
+ if (time_after(jiffies, timeo))
+ break;
- if ( ta ) {
- int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x\n",
- __func__,
- status & dq5mask );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto erase_failed;
+ /* Latency issues. Drop the lock, wait a while and retry */
+ cfi_spin_unlock(chip->mutex);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ cfi_spin_lock(chip->mutex);
}
- printk(KERN_WARNING
- "MTD %s(): Wacky! Unable to decode failure status\n",
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
- printk(KERN_WARNING
- "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
- __func__, adr, ones,
- prev_oldstatus, prev_status,
- oldstatus, status);
-
- erase_failed:
- ret = -EIO;
/* reset on all failures. */
- cfi_write( map, CMD(0xF0), chip->start );
+ map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- erase_done:
- DISABLE_VPP(map);
+ ret = -EIO;
+ op_done:
chip->state = FL_READY;
- wake_up(&chip->wq);
+ put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
+
return ret;
}
-static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+
+typedef int (*frob_t)(struct map_info *map, struct flchip *chip,
+ unsigned long adr, void *thunk);
+
+
+static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob,
+ loff_t ofs, size_t len, void *thunk)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- unsigned long adr, len;
+ unsigned long adr;
int chipnum, ret = 0;
int i, first;
struct mtd_erase_region_info *regions = mtd->eraseregions;
- if (instr->addr > mtd->size)
+ if (ofs > mtd->size)
return -EINVAL;
- if ((instr->len + instr->addr) > mtd->size)
+ if ((len + ofs) > mtd->size)
return -EINVAL;
/* Check that both start and end of the requested erase are
start of the requested erase, and then go back one.
*/
- while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
+ while (i < mtd->numeraseregions && ofs >= regions[i].offset)
i++;
i--;
effect here.
*/
- if (instr->addr & (regions[i].erasesize-1))
+ if (ofs & (regions[i].erasesize-1))
return -EINVAL;
/* Remember the erase region we start on */
* with the erase region at that address.
*/
- while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+ while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
i++;
/* As before, drop back one to point at the region in which
*/
i--;
- if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+ if ((ofs + len) & (regions[i].erasesize-1))
return -EINVAL;
-
- chipnum = instr->addr >> cfi->chipshift;
- adr = instr->addr - (chipnum << cfi->chipshift);
- len = instr->len;
- i=first;
+ chipnum = ofs >> cfi->chipshift;
+ adr = ofs - (chipnum << cfi->chipshift);
- while(len) {
- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+ i=first;
+ while (len) {
+ ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+
if (ret)
return ret;
}
}
- instr->state = MTD_ERASE_DONE;
- if (instr->callback)
- instr->callback(instr);
-
return 0;
}
-static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
{
- struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- unsigned long adr, len;
- int chipnum, ret = 0;
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret = 0;
- if (instr->addr & (mtd->erasesize - 1))
- return -EINVAL;
+ adr += chip->start;
- if (instr->len & (mtd->erasesize -1))
- return -EINVAL;
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_ERASING);
+ if (ret) {
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
- if ((instr->len + instr->addr) > mtd->size)
- return -EINVAL;
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
+ __func__, adr );
- chipnum = instr->addr >> cfi->chipshift;
- adr = instr->addr - (chipnum << cfi->chipshift);
- len = instr->len;
+ ENABLE_VPP(map);
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ map_write(map, CMD(0x30), adr);
+
+ chip->state = FL_ERASING;
+ chip->erase_suspended = 0;
+ chip->in_progress_block_addr = adr;
+
+ cfi_spin_unlock(chip->mutex);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((chip->erase_time*HZ)/(2*1000));
+ cfi_spin_lock(chip->mutex);
- while(len) {
- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+ timeo = jiffies + (HZ*20);
- if (ret)
- return ret;
+ for (;;) {
+ if (chip->state != FL_ERASING) {
+ /* Someone's suspended the erase. Sleep */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ cfi_spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ cfi_spin_lock(chip->mutex);
+ continue;
+ }
+ if (chip->erase_suspended) {
+ /* This erase was suspended and resumed.
+ Adjust the timeout */
+ timeo = jiffies + (HZ*20); /* FIXME */
+ chip->erase_suspended = 0;
+ }
- adr += mtd->erasesize;
- len -= mtd->erasesize;
+ if (chip_ready(map, adr))
+ goto op_done;
- if (adr >> cfi->chipshift) {
- adr = 0;
- chipnum++;
-
- if (chipnum >= cfi->numchips)
+ if (time_after(jiffies, timeo))
break;
- }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ cfi_spin_unlock(chip->mutex);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ cfi_spin_lock(chip->mutex);
}
-
+
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
+
+ ret = -EIO;
+ op_done:
+ chip->state = FL_READY;
+ put_chip(map, chip, adr);
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+}
+
+
+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+{
+ unsigned long ofs, len;
+ int ret;
+
+ ofs = instr->addr;
+ len = instr->len;
+
+ ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
+ if (ret)
+ return ret;
+
instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
return 0;
}
+
static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
{
struct map_info *map = mtd->priv;
return 0;
}
+
static void cfi_amdstd_sync (struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
schedule();
- remove_wait_queue(&chip->wq, &wait);
+ remove_wait_queue(&chip->wq, &wait);
goto retry;
}
/* Unlock the chips again */
if (ret) {
- for (i--; i >=0; i--) {
+ for (i--; i >=0; i--) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
return ret;
}
+
static void cfi_amdstd_resume(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
if (chip->state == FL_PM_SUSPENDED) {
chip->state = FL_READY;
- cfi_write(map, CMD(0xF0), chip->start);
+ map_write(map, CMD(0xF0), chip->start);
wake_up(&chip->wq);
}
else
}
}
+
+#ifdef DEBUG_LOCK_BITS
+
+static int do_printlockstatus_oneblock(struct map_info *map,
+ struct flchip *chip,
+ unsigned long adr,
+ void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ofs_factor = cfi->interleave * cfi->device_type;
+
+ cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+ adr, cfi_read_query(map, adr+(2*ofs_factor)));
+ cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+
+ return 0;
+}
+
+
+#define debug_dump_locks(mtd, frob, ofs, len, thunk) \
+ cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk))
+
+#else
+
+#define debug_dump_locks(...)
+
+#endif /* DEBUG_LOCK_BITS */
+
+
+struct xxlock_thunk {
+ uint8_t val;
+ flstate_t state;
+};
+
+
+#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING})
+#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING})
+
+
+/*
+ * FIXME - this is *very* specific to a particular chip. It likely won't
+ * work for all chips that require unlock. It also hasn't been tested
+ * with interleaved chips.
+ */
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk;
+ int ret;
+
+ /*
+ * This is easy because these are writes to registers and not writes
+ * to flash memory - that means that we don't have to check status
+ * and timeout.
+ */
+
+ adr += chip->start;
+ /*
+ * lock block registers:
+ * - on 64k boundariesand
+ * - bit 1 set high
+ * - block lock registers are 4MiB lower - overflow subtract (danger)
+ */
+ adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff;
+
+ cfi_spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr, FL_LOCKING);
+ if (ret) {
+ cfi_spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ chip->state = xxlt->state;
+ map_write(map, CMD(xxlt->val), adr);
+
+ /* Done and happy. */
+ chip->state = FL_READY;
+ put_chip(map, chip, adr);
+ cfi_spin_unlock(chip->mutex);
+ return 0;
+}
+
+
+static int cfi_amdstd_lock_varsize(struct mtd_info *mtd,
+ loff_t ofs,
+ size_t len)
+{
+ int ret;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+ __func__, ofs, len);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+ (void *)&DO_XXLOCK_ONEBLOCK_LOCK);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status after, ret=%d\n",
+ __func__, ret);
+
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ return ret;
+}
+
+
+static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd,
+ loff_t ofs,
+ size_t len)
+{
+ int ret;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+ __func__, ofs, len);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+ (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "%s: lock status after, ret=%d\n",
+ __func__, ret);
+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+ return ret;
+}
+
+
static void cfi_amdstd_destroy(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
static char im_name[]="cfi_cmdset_0002";
+
int __init cfi_amdstd_init(void)
{
inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
return 0;
}
+
static void __exit cfi_amdstd_exit(void)
{
inter_module_unregister(im_name);
}
+
module_init(cfi_amdstd_init);
module_exit(cfi_amdstd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
-
*
* (C) 2000 Red Hat. GPL'd
*
+ * $Id: cfi_cmdset_0020.c,v 1.13 2004/07/12 21:52:50 dwmw2 Exp $
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
* - completely revamped method functions so they are aware and
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
- __u32 base = cfi->chips[0].start;
if (cfi->cfi_mode) {
/*
*/
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
struct cfi_pri_intelext *extp;
- int ofs_factor = cfi->interleave * cfi->device_type;
- printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
- if (!adr)
+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics");
+ if (!extp)
return NULL;
- /* Switch it into Query Mode */
- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
- extp = kmalloc(sizeof(*extp), GFP_KERNEL);
- if (!extp) {
- printk(KERN_ERR "Failed to allocate memory\n");
- return NULL;
- }
-
- /* Read in the Extended Query Table */
- for (i=0; i<sizeof(*extp); i++) {
- ((unsigned char *)extp)[i] =
- cfi_read_query(map, (base+((adr+i)*ofs_factor)));
- }
-
- if (extp->MajorVersion != '1' ||
- (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
- printk(KERN_WARNING " Unknown staa Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
- return NULL;
- }
-
/* Do some byteswapping if necessary */
extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
cfi->chips[i].erase_time = 1024;
}
- /* Make sure it's in read mode */
- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
return cfi_staa_setup(map);
}
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
- __u32 status, status_OK;
+ map_word status, status_OK;
unsigned long timeo;
DECLARE_WAITQUEUE(wait, current);
int suspended = 0;
adr += chip->start;
/* Ensure cmd read/writes are aligned. */
- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1);
+ cmd_addr = adr & ~(map_bankwidth(map)-1);
/* Let's determine this according to the interleave only once */
status_OK = CMD(0x80);
*/
switch (chip->state) {
case FL_ERASING:
- if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+ if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
goto sleep; /* We don't support erase suspend */
- cfi_write (map, CMD(0xb0), cmd_addr);
+ map_write (map, CMD(0xb0), cmd_addr);
/* If the flash has finished erasing, then 'erase suspend'
* appears to make some (28F320) flash devices switch to
* 'read' mode. Make sure that we switch to 'read status'
* mode so we get the right data. --rmk
*/
- cfi_write(map, CMD(0x70), cmd_addr);
+ map_write(map, CMD(0x70), cmd_addr);
chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING;
// printk("Erase suspending at 0x%lx\n", cmd_addr);
for (;;) {
- status = cfi_read(map, cmd_addr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_addr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
if (time_after(jiffies, timeo)) {
/* Urgh */
- cfi_write(map, CMD(0xd0), cmd_addr);
+ map_write(map, CMD(0xd0), cmd_addr);
/* make sure we're in 'read status' mode */
- cfi_write(map, CMD(0x70), cmd_addr);
+ map_write(map, CMD(0x70), cmd_addr);
chip->state = FL_ERASING;
spin_unlock_bh(chip->mutex);
printk(KERN_ERR "Chip not ready after erase "
- "suspended: status = 0x%x\n", status);
+ "suspended: status = 0x%lx\n", status.x[0]);
return -EIO;
}
}
suspended = 1;
- cfi_write(map, CMD(0xff), cmd_addr);
+ map_write(map, CMD(0xff), cmd_addr);
chip->state = FL_READY;
break;
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
- cfi_write(map, CMD(0x70), cmd_addr);
+ map_write(map, CMD(0x70), cmd_addr);
chip->state = FL_STATUS;
case FL_STATUS:
- status = cfi_read(map, cmd_addr);
- if ((status & status_OK) == status_OK) {
- cfi_write(map, CMD(0xff), cmd_addr);
+ status = map_read(map, cmd_addr);
+ if (map_word_andequal(map, status, status_OK, status_OK)) {
+ map_write(map, CMD(0xff), cmd_addr);
chip->state = FL_READY;
break;
}
/* Urgh. Chip not yet ready to talk to us. */
if (time_after(jiffies, timeo)) {
spin_unlock_bh(chip->mutex);
- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+ printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %lx\n", status.x[0]);
return -EIO;
}
sending the 0x70 (Read Status) command to an erasing
chip and expecting it to be ignored, that's what we
do. */
- cfi_write(map, CMD(0xd0), cmd_addr);
- cfi_write(map, CMD(0x70), cmd_addr);
+ map_write(map, CMD(0xd0), cmd_addr);
+ map_write(map, CMD(0x70), cmd_addr);
}
wake_up(&chip->wq);
unsigned long adr, const u_char *buf, int len)
{
struct cfi_private *cfi = map->fldrv_priv;
- __u32 status, status_OK;
+ map_word status, status_OK;
unsigned long cmd_adr, timeo;
DECLARE_WAITQUEUE(wait, current);
int wbufsize, z;
/* M58LW064A requires bus alignment for buffer wriets -- saw */
- if (adr & (CFIDEV_BUSWIDTH-1))
+ if (adr & (map_bankwidth(map)-1))
return -EINVAL;
- wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+ wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
adr += chip->start;
cmd_adr = adr & ~(wbufsize-1);
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
- cfi_write(map, CMD(0x70), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
#ifdef DEBUG_CFI_FEATURES
- printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
+ printk("%s: 1 status[%x]\n", __FUNCTION__, map_read(map, cmd_adr));
#endif
case FL_STATUS:
- status = cfi_read(map, cmd_adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* Urgh. Chip not yet ready to talk to us. */
if (time_after(jiffies, timeo)) {
spin_unlock_bh(chip->mutex);
- printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %llx\n",
- status, cfi_read(map, cmd_adr));
+ printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %lx, status = %lx\n",
+ status.x[0], map_read(map, cmd_adr).x[0]);
return -EIO;
}
}
ENABLE_VPP(map);
- cfi_write(map, CMD(0xe8), cmd_adr);
+ map_write(map, CMD(0xe8), cmd_adr);
chip->state = FL_WRITING_TO_BUFFER;
z = 0;
for (;;) {
- status = cfi_read(map, cmd_adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
spin_unlock_bh(chip->mutex);
if (++z > 100) {
/* Argh. Not ready for write to buffer */
DISABLE_VPP(map);
- cfi_write(map, CMD(0x70), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
spin_unlock_bh(chip->mutex);
- printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
+ printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx\n", status.x[0]);
return -EIO;
}
}
/* Write length of data to come */
- cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
+ map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr );
/* Write data */
- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
- if (cfi_buswidth_is_1()) {
- u8 *b = (u8 *)buf;
-
- map_write8 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else if (cfi_buswidth_is_2()) {
- u16 *b = (u16 *)buf;
-
- map_write16 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else if (cfi_buswidth_is_4()) {
- u32 *b = (u32 *)buf;
-
- map_write32 (map, *b++, adr+z);
- buf = (const u_char *)b;
- } else {
- DISABLE_VPP(map);
- return -EINVAL;
- }
+ for (z = 0; z < len;
+ z += map_bankwidth(map), buf += map_bankwidth(map)) {
+ map_word d;
+ d = map_word_load(map, buf);
+ map_write(map, d, adr+z);
}
/* GO GO GO */
- cfi_write(map, CMD(0xd0), cmd_adr);
+ map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
spin_unlock_bh(chip->mutex);
continue;
}
- status = cfi_read(map, cmd_adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
/* clear status */
- cfi_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x50), cmd_adr);
/* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
DISABLE_VPP(map);
spin_unlock_bh(chip->mutex);
chip->state = FL_STATUS;
/* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
- if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
- (status & CMD(0x10)) || (status & CMD(0x20))) {
+ if (map_word_bitsset(map, status, CMD(0x3a))) {
#ifdef DEBUG_CFI_FEATURES
- printk("%s: 2 status[%x]\n", __FUNCTION__, status);
+ printk("%s: 2 status[%lx]\n", __FUNCTION__, status.x[0]);
#endif
- /* clear status */
- cfi_write(map, CMD(0x50), cmd_adr);
- /* put back into read status register mode */
- cfi_write(map, CMD(0x70), adr);
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
- return (status & CMD(0x02)) ? -EROFS : -EIO;
- }
+ /* clear status */
+ map_write(map, CMD(0x50), cmd_adr);
+ /* put back into read status register mode */
+ map_write(map, CMD(0x70), adr);
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+ return map_word_bitsset(map, status, CMD(0x02)) ? -EROFS : -EIO;
+ }
wake_up(&chip->wq);
spin_unlock_bh(chip->mutex);
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+ int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
int ret = 0;
int chipnum;
unsigned long ofs;
ofs = to - (chipnum << cfi->chipshift);
#ifdef DEBUG_CFI_FEATURES
- printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
+ printk("%s: map_bankwidth(map)[%x]\n", __FUNCTION__, map_bankwidth(map));
printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
#endif
static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
{
struct cfi_private *cfi = map->fldrv_priv;
- __u32 status, status_OK;
+ map_word status, status_OK;
unsigned long timeo;
int retries = 3;
DECLARE_WAITQUEUE(wait, current);
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
case FL_READY:
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
case FL_STATUS:
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* Urgh. Chip not yet ready to talk to us. */
ENABLE_VPP(map);
/* Clear the status register first */
- cfi_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x50), adr);
/* Now erase */
- cfi_write(map, CMD(0x20), adr);
- cfi_write(map, CMD(0xD0), adr);
+ map_write(map, CMD(0x20), adr);
+ map_write(map, CMD(0xD0), adr);
chip->state = FL_ERASING;
spin_unlock_bh(chip->mutex);
continue;
}
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+ printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
DISABLE_VPP(map);
spin_unlock_bh(chip->mutex);
return -EIO;
ret = 0;
/* We've broken this before. It doesn't hurt to be safe */
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- status = cfi_read(map, adr);
+ status = map_read(map, adr);
/* check for lock bit */
- if (status & CMD(0x3a)) {
- unsigned char chipstatus = status;
- if (status != CMD(status & 0xff)) {
- int i;
- for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
- chipstatus |= status >> (cfi->device_type * 8);
+ if (map_word_bitsset(map, status, CMD(0x3a))) {
+ unsigned char chipstatus = status.x[0];
+ if (!map_word_equal(map, status, CMD(chipstatus))) {
+ int i, w;
+ for (w=0; w<map_words(map); w++) {
+ for (i = 0; i<cfi_interleave(cfi); i++) {
+ chipstatus |= status.x[w] >> (cfi->device_type * 8);
+ }
}
- printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+ printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
+ status.x[0], chipstatus);
}
/* Reset the error bits */
- cfi_write(map, CMD(0x50), adr);
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x50), adr);
+ map_write(map, CMD(0x70), adr);
if ((chipstatus & 0x30) == 0x30) {
- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x02) {
/* Protection bit set */
ret = -EROFS;
} else if (chipstatus & 0x8) {
/* Voltage */
- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x20) {
if (retries--) {
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ;
chip->state = FL_STATUS;
spin_unlock_bh(chip->mutex);
goto retry;
}
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
ret = -EIO;
}
}
static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
{
struct cfi_private *cfi = map->fldrv_priv;
- __u32 status, status_OK;
+ map_word status, status_OK;
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
case FL_READY:
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
case FL_STATUS:
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* Urgh. Chip not yet ready to talk to us. */
}
ENABLE_VPP(map);
- cfi_write(map, CMD(0x60), adr);
- cfi_write(map, CMD(0x01), adr);
+ map_write(map, CMD(0x60), adr);
+ map_write(map, CMD(0x01), adr);
chip->state = FL_LOCKING;
spin_unlock_bh(chip->mutex);
timeo = jiffies + (HZ*2);
for (;;) {
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+ printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
DISABLE_VPP(map);
spin_unlock_bh(chip->mutex);
return -EIO;
static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
{
struct cfi_private *cfi = map->fldrv_priv;
- __u32 status, status_OK;
+ map_word status, status_OK;
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
case FL_READY:
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
case FL_STATUS:
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* Urgh. Chip not yet ready to talk to us. */
}
ENABLE_VPP(map);
- cfi_write(map, CMD(0x60), adr);
- cfi_write(map, CMD(0xD0), adr);
+ map_write(map, CMD(0x60), adr);
+ map_write(map, CMD(0xD0), adr);
chip->state = FL_UNLOCKING;
spin_unlock_bh(chip->mutex);
timeo = jiffies + (HZ*2);
for (;;) {
- status = cfi_read(map, adr);
- if ((status & status_OK) == status_OK)
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
break;
/* OK Still waiting */
if (time_after(jiffies, timeo)) {
- cfi_write(map, CMD(0x70), adr);
+ map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
- printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+ printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
DISABLE_VPP(map);
spin_unlock_bh(chip->mutex);
return -EIO;
/* Go to known state. Chip may have been power cycled */
if (chip->state == FL_PM_SUSPENDED) {
- cfi_write(map, CMD(0xFF), 0);
+ map_write(map, CMD(0xFF), 0);
chip->state = FL_READY;
wake_up(&chip->wq);
}
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: cfi_probe.c,v 1.71 2003/05/28 12:51:48 dwmw2 Exp $
+ $Id: cfi_probe.c,v 1.77 2004/07/14 08:38:44 dwmw2 Exp $
*/
#include <linux/config.h>
#endif
static int cfi_probe_chip(struct map_info *map, __u32 base,
- struct flchip *chips, struct cfi_private *cfi);
+ unsigned long *chip_map, struct cfi_private *cfi);
static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
struct mtd_info *cfi_probe(struct map_info *map);
in: interleave,type,mode
ret: table index, <0 for error
*/
-static inline int qry_present(struct map_info *map, __u32 base,
+static int qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
int osf = cfi->interleave * cfi->device_type; // scale factor
+ map_word val;
+ map_word qry;
- if (cfi_read(map,base+osf*0x10)==cfi_build_cmd('Q',map,cfi) &&
- cfi_read(map,base+osf*0x11)==cfi_build_cmd('R',map,cfi) &&
- cfi_read(map,base+osf*0x12)==cfi_build_cmd('Y',map,cfi))
- return 1; // ok !
+ qry = cfi_build_cmd('Q', map, cfi);
+ val = map_read(map, base + osf*0x10);
- return 0; // nothing found
+ if (!map_word_equal(map, qry, val))
+ return 0;
+
+ qry = cfi_build_cmd('R', map, cfi);
+ val = map_read(map, base + osf*0x11);
+
+ if (!map_word_equal(map, qry, val))
+ return 0;
+
+ qry = cfi_build_cmd('Y', map, cfi);
+ val = map_read(map, base + osf*0x12);
+
+ if (!map_word_equal(map, qry, val))
+ return 0;
+
+ return 1; // nothing found
}
static int cfi_probe_chip(struct map_info *map, __u32 base,
- struct flchip *chips, struct cfi_private *cfi)
+ unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
return 0;
}
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
if (!qry_present(map,base,cfi))
}
/* Check each previous chip to see if it's an alias */
- for (i=0; i<cfi->numchips; i++) {
+ for (i=0; i < (base >> cfi->chipshift); i++) {
+ unsigned long start;
+ if(!test_bit(i, chip_map)) {
+ /* Skip location; no valid chip at this address */
+ continue;
+ }
+ start = i << cfi->chipshift;
/* This chip should be in read mode if it's one
we've already touched. */
- if (qry_present(map,chips[i].start,cfi)) {
+ if (qry_present(map, start, cfi)) {
/* Eep. This chip also had the QRY marker.
* Is it an alias for the new one? */
- cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
/* If the QRY marker goes away, it's an alias */
- if (!qry_present(map, chips[i].start, cfi)) {
+ if (!qry_present(map, start, cfi)) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
- map->name, base, chips[i].start);
+ map->name, base, start);
return 0;
}
/* Yes, it's actually got QRY for data. Most
* too and if it's the same, assume it's an alias. */
/* FIXME: Use other modes to do a proper check */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
if (qry_present(map, base, cfi)) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
- map->name, base, chips[i].start);
+ map->name, base, start);
return 0;
}
}
/* OK, if we got to here, then none of the previous chips appear to
be aliases for the current one. */
- if (cfi->numchips == MAX_CFI_CHIPS) {
- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
- return -1;
- }
- chips[cfi->numchips].start = base;
- chips[cfi->numchips].state = FL_READY;
+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
cfi->numchips++;
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
- printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
- map->buswidth*8);
+ map->bankwidth*8);
return 1;
}
memset(cfi->cfiq,0,sizeof(struct cfi_ident));
cfi->cfi_mode = CFI_MODE_CFI;
- cfi->fast_prog=1; /* CFI supports fast programming */
/* Read the CFI info structure */
for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
(cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
#endif
}
+
+ /* Note we put the device back into Read Mode BEFORE going into Auto
+ * Select Mode, as some devices support nesting of modes, others
+ * don't. This way should always work.
+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
+ * so should be treated as nops or illegal (and so put the device
+ * back into Read Mode, which is a nop in this case).
+ */
+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
+ cfi->mfr = cfi_read_query(map, base);
+ cfi->id = cfi_read_query(map, base + ofs_factor);
+
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ /* ... even if it's an Intel chip */
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+
+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
+ map->name, cfi->interleave, cfi->device_type*8, base,
+ map->bankwidth*8);
return 1;
}
printk("No Alternate Algorithm Table\n");
- printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
- printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
+ printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
+ printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
if (cfip->VppMin) {
- printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
- printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
+ printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
+ printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
}
else
printk("No Vpp line\n");
/*
- * $Id: chipreg.c,v 1.15 2003/05/21 15:15:05 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.16 2003/05/29 09:36:15 dwmw2 Exp $
*
* Registration for chip drivers
*
* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.c,v 1.13 2003/06/25 11:50:37 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.19 2004/07/13 22:33:32 dwmw2 Exp $
*/
#include <linux/kernel.h>
EXPORT_SYMBOL(mtd_do_chip_probe);
-struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
+static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
{
- unsigned long base=0;
struct cfi_private cfi;
struct cfi_private *retcfi;
- struct flchip chip[MAX_CFI_CHIPS];
- int i;
+ unsigned long *chip_map;
+ int i, j, mapsize;
+ int max_chips;
memset(&cfi, 0, sizeof(cfi));
- memset(&chip[0], 0, sizeof(chip));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
return NULL;
}
#endif
- chip[0].start = 0;
- chip[0].state = FL_READY;
cfi.chipshift = cfi.cfiq->DevSize;
- switch(cfi.interleave) {
-#ifdef CFIDEV_INTERLEAVE_1
- case 1:
- break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_2
- case 2:
+ if (cfi_interleave_is_1(&cfi)) {
+ ;
+ } else if (cfi_interleave_is_2(&cfi)) {
cfi.chipshift++;
- break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_4
- case 4:
- cfi.chipshift+=2;
- break;
-#endif
- default:
+ } else if (cfi_interleave_is_4((&cfi))) {
+ cfi.chipshift += 2;
+ } else if (cfi_interleave_is_8(&cfi)) {
+ cfi.chipshift += 3;
+ } else {
BUG();
}
cfi.numchips = 1;
+ /*
+ * Allocate memory for bitmap of valid chips.
+ * Align bitmap storage size to full byte.
+ */
+ max_chips = map->size >> cfi.chipshift;
+ mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
+ chip_map = kmalloc(mapsize, GFP_KERNEL);
+ if (!chip_map) {
+ printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
+ kfree(cfi.cfiq);
+ return NULL;
+ }
+ memset (chip_map, 0, mapsize);
+
+ set_bit(0, chip_map); /* Mark first chip valid */
+
/*
* Now probe for other chips, checking sensibly for aliases while
* we're at it. The new_chip probe above should have let the first
* chip in read mode.
- *
- * NOTE: Here, we're checking if there is room for another chip
- * the same size within the mapping. Therefore,
- * base + chipsize <= map->size is the correct thing to do,
- * because, base + chipsize would be the _first_ byte of the
- * next chip, not the one we're currently pondering.
*/
- for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
- base += (1<<cfi.chipshift))
- cp->probe_chip(map, base, &chip[0], &cfi);
+ for (i = 1; i < max_chips; i++) {
+ cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
+ }
/*
* Now allocate the space for the structures we need to return to
if (!retcfi) {
printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
kfree(cfi.cfiq);
+ kfree(chip_map);
return NULL;
}
memcpy(retcfi, &cfi, sizeof(cfi));
- memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-
- /* Fix up the stuff that breaks when you move it */
- for (i=0; i< retcfi->numchips; i++) {
- init_waitqueue_head(&retcfi->chips[i].wq);
- spin_lock_init(&retcfi->chips[i]._spinlock);
- retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
+ memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
+
+ for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
+ if(test_bit(i, chip_map)) {
+ struct flchip *pchip = &retcfi->chips[j++];
+
+ pchip->start = (i << cfi.chipshift);
+ pchip->state = FL_READY;
+ init_waitqueue_head(&pchip->wq);
+ spin_lock_init(&pchip->_spinlock);
+ pchip->mutex = &pchip->_spinlock;
+ }
}
+ kfree(chip_map);
return retcfi;
}
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi)
{
- switch (map->buswidth) {
-#ifdef CFIDEV_BUSWIDTH_1
- case CFIDEV_BUSWIDTH_1:
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
- break;
-#endif /* CFIDEV_BUSWITDH_1 */
-
-#ifdef CFIDEV_BUSWIDTH_2
- case CFIDEV_BUSWIDTH_2:
-#ifdef CFIDEV_INTERLEAVE_1
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
- break;
-#endif /* CFIDEV_BUSWIDTH_2 */
-
-#ifdef CFIDEV_BUSWIDTH_4
- case CFIDEV_BUSWIDTH_4:
-#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
- cfi->interleave = CFIDEV_INTERLEAVE_1;
-
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
- cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
- break;
-#endif /* CFIDEV_BUSWIDTH_4 */
-
-#ifdef CFIDEV_BUSWIDTH_8
- case CFIDEV_BUSWIDTH_8:
-#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
- cfi->interleave = CFIDEV_INTERLEAVE_2;
-
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
- cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
- cfi->device_type = CFI_DEVICETYPE_X32;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
-#ifdef CFIDEV_INTERLEAVE_8
- cfi->interleave = CFIDEV_INTERLEAVE_8;
-
- cfi->device_type = CFI_DEVICETYPE_X16;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-
- cfi->device_type = CFI_DEVICETYPE_X8;
- if (cp->probe_chip(map, 0, NULL, cfi))
- return 1;
-#endif /* CFIDEV_INTERLEAVE_8 */
- break;
-#endif /* CFIDEV_BUSWIDTH_8 */
-
- default:
- printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
- return 0;
+ int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
+ int max_chips = map_bankwidth(map); /* And minimum 1 */
+ int nr_chips, type;
+
+ for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+
+ if (!cfi_interleave_supported(nr_chips))
+ continue;
+
+ cfi->interleave = nr_chips;
+
+ for (type = 0; type < 3; type++) {
+ cfi->device_type = 1<<type;
+
+ if (cp->probe_chip(map, 0, NULL, cfi))
+ return 1;
+ }
}
return 0;
}
-
typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
extern cfi_cmdset_fn_t cfi_cmdset_0001;
* not going to guess how to send commands to them, plus I expect they will
* all speak CFI..
*
- * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $
+ * $Id: jedec.c,v 1.20 2004/07/12 14:03:01 dwmw2 Exp $
*/
#include <linux/init.h>
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: jedec_probe.c,v 1.29 2003/05/28 13:57:46 dwmw2 Exp $
+ $Id: jedec_probe.c,v 1.51 2004/07/14 14:44:30 thayne Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
+
+ Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
/* AMD */
+#define AM29DL800BB 0x22C8
+#define AM29DL800BT 0x224A
+
#define AM29F800BB 0x2258
#define AM29F800BT 0x22D6
+#define AM29LV400BB 0x22BA
+#define AM29LV400BT 0x22B9
#define AM29LV800BB 0x225B
#define AM29LV800BT 0x22DA
#define AM29LV160DT 0x22C4
#define AT49BV32XT 0x00C9
/* Fujitsu */
+#define MBM29F040C 0x00A4
#define MBM29LV650UE 0x22D7
#define MBM29LV320TE 0x22F6
#define MBM29LV320BE 0x22F9
#define MBM29LV160BE 0x2249
#define MBM29LV800BA 0x225B
#define MBM29LV800TA 0x22DA
+#define MBM29LV400TC 0x22B9
+#define MBM29LV400BC 0x22BA
+
/* Intel */
#define I28F004B3T 0x00d4
#define M50FW016 0x002E
/* SST */
+#define SST29EE020 0x0010
+#define SST29LE020 0x0012
#define SST29EE512 0x005d
#define SST29LE512 0x003d
#define SST39LF800 0x2781
#define SST39LF040 0x00D7
#define SST39SF010A 0x00B5
#define SST39SF020A 0x00B6
+#define SST49LF004B 0x0060
+#define SST49LF008A 0x005a
#define SST49LF030A 0x001C
#define SST49LF040A 0x0051
#define SST49LF080A 0x005B
const __u16 dev_id;
const char *name;
const int DevSize;
- const int InterfaceDesc;
const int NumEraseRegions;
const int CmdSet;
- const __u8 uaddr[3]; /* unlock addrs for 8, 16, 32 modes */
- const ulong regions[4];
+ const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */
+ const ulong regions[6];
};
#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
ERASEINFO(0x08000,1),
ERASEINFO(0x10000,31)
}
+ }, {
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29LV400BB,
+ .name = "AMD AM29LV400BB",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,7)
+ }
+ }, {
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29LV400BT,
+ .name = "AMD AM29LV400BT",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,7),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1)
+ }
}, {
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29LV800BB,
ERASEINFO(0x10000,15),
}
}, {
+/* add DL */
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29DL800BB,
+ .name = "AMD AM29DL800BB",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 6,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,4),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x10000,14)
+ }
+ }, {
+ .mfr_id = MANUFACTURER_AMD,
+ .dev_id = AM29DL800BT,
+ .name = "AMD AM29DL800BT",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 6,
+ .regions = {
+ ERASEINFO(0x10000,14),
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,4),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x04000,1)
+ }
+ }, {
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29F800BB,
.name = "AMD AM29F800BB",
ERASEINFO(0x10000,63),
ERASEINFO(0x02000,8)
}
+ }, {
+ .mfr_id = MANUFACTURER_FUJITSU,
+ .dev_id = MBM29F040C,
+ .name = "Fujitsu MBM29F040C",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,8)
+ }
}, {
.mfr_id = MANUFACTURER_FUJITSU,
.dev_id = MBM29LV650UE,
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1)
}
+ }, {
+ .mfr_id = MANUFACTURER_FUJITSU,
+ .dev_id = MBM29LV400BC,
+ .name = "Fujitsu MBM29LV400BC",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,7)
+ }
+ }, {
+ .mfr_id = MANUFACTURER_FUJITSU,
+ .dev_id = MBM29LV400TC,
+ .name = "Fujitsu MBM29LV400TC",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x10000,7),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x04000,1)
+ }
}, {
.mfr_id = MANUFACTURER_INTEL,
.dev_id = I28F004B3B,
ERASEINFO(0x01000,32),
}
}, {
+ .mfr_id = MANUFACTURER_SST,
+ .dev_id = SST29EE020,
+ .name = "SST 29EE020",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_SST_PAGE,
+ .NumEraseRegions= 1,
+ regions: {ERASEINFO(0x01000,64),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_SST,
+ .dev_id = SST29LE020,
+ .name = "SST 29LE020",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+ },
+ .DevSize = SIZE_256KiB,
+ .CmdSet = P_ID_SST_PAGE,
+ .NumEraseRegions= 1,
+ regions: {ERASEINFO(0x01000,64),
+ }
+ }, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST39LF020,
.name = "SST 39LF020",
.regions = {
ERASEINFO(0x01000,64),
}
+ }, {
+ .mfr_id = MANUFACTURER_SST,
+ .dev_id = SST49LF004B,
+ .name = "SST 49LF004B",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x01000,128),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_SST,
+ .dev_id = SST49LF008A,
+ .name = "SST 49LF008A",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x01000,256),
+ }
}, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST49LF030A,
static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
static int jedec_probe_chip(struct map_info *map, __u32 base,
- struct flchip *chips, struct cfi_private *cfi);
+ unsigned long *chip_map, struct cfi_private *cfi);
struct mtd_info *jedec_probe(struct map_info *map);
static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
- u32 result, mask;
+ map_word result;
+ unsigned long mask;
mask = (1 << (cfi->device_type * 8)) -1;
- result = cfi_read(map, base);
- result &= mask;
- return result;
+ result = map_read(map, base);
+ return result.x[0] & mask;
}
static inline u32 jedec_read_id(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
int osf;
- u32 result, mask;
+ map_word result;
+ unsigned long mask;
osf = cfi->interleave *cfi->device_type;
mask = (1 << (cfi->device_type * 8)) -1;
- result = cfi_read(map, base + osf);
- result &= mask;
- return result;
+ result = map_read(map, base + osf);
+ return result.x[0] & mask;
}
static inline void jedec_reset(u32 base, struct map_info *map,
struct cfi_private *cfi)
{
/* Reset */
- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+
+ /* after checking the datasheets for SST, MACRONIX and ATMEL
+ * (oh and incidentaly the jedec spec - 3.5.3.3) the reset
+ * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at
+ * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
+ * as they will ignore the writes and dont care what address
+ * the F0 is written to */
+ if(cfi->addr_unlock1) {
+ /*printk("reset unlock called %x %x \n",cfi->addr_unlock1,cfi->addr_unlock2);*/
+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+ }
+
+ cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
/* Some misdesigned intel chips do not respond for 0xF0 for a reset,
* so ensure we're in read mode. Send both the Intel and the AMD command
* for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so
uaddr = finfo->uaddr[uaddr_idx];
+ if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
+ /* ASSERT("The unlock addresses for non-8-bit mode
+ are bollocks. We don't really need an array."); */
+ uaddr = finfo->uaddr[0];
+ }
+
uaddr_done:
return uaddr;
}
static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
{
int i,num_erase_regions;
+ unsigned long mask;
__u8 uaddr;
printk("Found: %s\n",jedec_table[index].name);
p_cfi->id = jedec_table[index].dev_id;
uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
- if ( MTD_UADDR_NOT_SUPPORTED ) {
+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
kfree( p_cfi->cfiq );
return 0;
}
- p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
- p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+
+ /* Mask out address bits which are smaller than the device type */
+ mask = ~(p_cfi->device_type-1);
+ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask;
+ p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask;
return 1; /* ok */
}
int rc = 0; /* failure until all tests pass */
u32 mfr, id;
__u8 uaddr;
+ unsigned long mask;
- /* The ID's must match */
- if ( cfi->mfr != finfo->mfr_id || cfi->id != finfo->dev_id ) {
+ /*
+ * The IDs must match. For X16 and X32 devices operating in
+ * a lower width ( X8 or X16 ), the device ID's are usually just
+ * the lower byte(s) of the larger device ID for wider mode. If
+ * a part is found that doesn't fit this assumption (device id for
+ * smaller width mode is completely unrealated to full-width mode)
+ * then the jedec_table[] will have to be augmented with the IDs
+ * for different widths.
+ */
+ switch (cfi->device_type) {
+ case CFI_DEVICETYPE_X8:
+ mfr = (__u8)finfo->mfr_id;
+ id = (__u8)finfo->dev_id;
+ break;
+ case CFI_DEVICETYPE_X16:
+ mfr = (__u16)finfo->mfr_id;
+ id = (__u16)finfo->dev_id;
+ break;
+ case CFI_DEVICETYPE_X32:
+ mfr = (__u16)finfo->mfr_id;
+ id = (__u32)finfo->dev_id;
+ break;
+ default:
+ printk(KERN_WARNING
+ "MTD %s(): Unsupported device type %d\n",
+ __func__, cfi->device_type);
+ goto match_done;
+ }
+ if ( cfi->mfr != mfr || cfi->id != id ) {
goto match_done;
}
DEBUG( MTD_DEBUG_LEVEL3,
"MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
__func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
- if ( base + ( 1 << finfo->DevSize ) > map->size ) {
+ if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) {
DEBUG( MTD_DEBUG_LEVEL3,
"MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
__func__, finfo->mfr_id, finfo->dev_id,
}
uaddr = finfo_uaddr(finfo, cfi->device_type);
- if ( MTD_UADDR_NOT_SUPPORTED ) {
+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
goto match_done;
}
+ mask = ~(cfi->device_type-1);
+
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
__func__, cfi->addr_unlock1, cfi->addr_unlock2 );
if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
- && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1
- || unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+ && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 ||
+ (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) {
DEBUG( MTD_DEBUG_LEVEL3,
- "MTD %s(): 0x%.4x 0x%.4x did not match\n",
+ "MTD %s(): 0x%.4lx 0x%.4lx did not match\n",
__func__,
- unlock_addrs[uaddr].addr1,
- unlock_addrs[uaddr].addr2 );
+ unlock_addrs[uaddr].addr1 & mask,
+ unlock_addrs[uaddr].addr2 & mask);
goto match_done;
}
static int jedec_probe_chip(struct map_info *map, __u32 base,
- struct flchip *chips, struct cfi_private *cfi)
+ unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
- int unlockpass = 0;
+ enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
- /*
- * FIXME - eventually replace these unlock address seeds with
- * information from unlock_addrs[].
- */
+ retry:
if (!cfi->numchips) {
- switch (cfi->device_type) {
- case CFI_DEVICETYPE_X8:
- cfi->addr_unlock1 = 0x555;
- cfi->addr_unlock2 = 0x2aa;
- break;
- case CFI_DEVICETYPE_X16:
- cfi->addr_unlock1 = 0xaaa;
- if (map->buswidth == cfi->interleave) {
- /* X16 chip(s) in X8 mode */
- cfi->addr_unlock2 = 0x555;
- } else {
- cfi->addr_unlock2 = 0x554;
- }
- break;
- case CFI_DEVICETYPE_X32:
- cfi->addr_unlock1 = 0x1555;
- cfi->addr_unlock2 = 0xaaa;
- break;
- default:
- printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
- return 0;
- }
+ unsigned long mask = ~(cfi->device_type-1);
+
+ uaddr_idx++;
+
+ if (MTD_UADDR_UNNECESSARY == uaddr_idx)
+ return 0;
+
+ /* Mask out address bits which are smaller than the device type */
+ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask;
+ cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask;
}
- retry:
/* Make certain we aren't probing past the end of map */
if (base >= map->size) {
printk(KERN_NOTICE
cfi->mfr = jedec_read_mfr(map, base, cfi);
cfi->id = jedec_read_id(map, base, cfi);
- printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
goto ok_out;
}
}
- switch(unlockpass++) {
- case 0:
- cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
- cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
- goto retry;
- case 1:
- cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
- goto retry;
- }
- return 0;
+ goto retry;
} else {
__u16 mfr;
__u16 id;
}
}
- /* Check each previous chip to see if it's an alias */
- for (i=0; i<cfi->numchips; i++) {
- /* This chip should be in read mode if it's one
- we've already touched. */
- if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
- jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
+ /* Check each previous chip locations to see if it's an alias */
+ for (i=0; i < (base >> cfi->chipshift); i++) {
+ unsigned long start;
+ if(!test_bit(i, chip_map)) {
+ continue; /* Skip location; no valid chip at this address */
+ }
+ start = i << cfi->chipshift;
+ if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
+ jedec_read_id(map, start, cfi) == cfi->id) {
/* Eep. This chip also looks like it's in autoselect mode.
Is it an alias for the new one? */
- jedec_reset(chips[i].start, map, cfi);
+ jedec_reset(start, map, cfi);
/* If the device IDs go away, it's an alias */
if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
jedec_read_id(map, base, cfi) != cfi->id) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
- map->name, base, chips[i].start);
+ map->name, base, start);
return 0;
}
if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
jedec_read_id(map, base, cfi) == cfi->id) {
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
- map->name, base, chips[i].start);
+ map->name, base, start);
return 0;
}
}
/* OK, if we got to here, then none of the previous chips appear to
be aliases for the current one. */
- if (cfi->numchips == MAX_CFI_CHIPS) {
- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
- return -1;
- }
- chips[cfi->numchips].start = base;
- chips[cfi->numchips].state = FL_READY;
+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
cfi->numchips++;
ok_out:
/* Put it back into Read Mode */
jedec_reset(base, map, cfi);
- printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
- map->buswidth*8);
+ map->bankwidth*8);
return 1;
}
/*
* Common code to handle map devices which are simple RAM
* (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $
+ * $Id: map_ram.c,v 1.19 2004/07/12 21:58:44 dwmw2 Exp $
*/
#include <linux/module.h>
/* Yeah, it's inefficient. Who cares? It's faster than a _real_
flash erase. */
struct map_info *map = (struct map_info *)mtd->priv;
+ map_word allff;
unsigned long i;
- for (i=0; i<instr->len; i++)
- map_write8(map, 0xFF, instr->addr + i);
+ allff = map_word_ff(map);
+
+ for (i=0; i<instr->len; i += map_bankwidth(map))
+ map_write(map, allff, instr->addr + i);
+
+ instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
/*
* Common code to handle map devices which are simple ROM
* (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $
+ * $Id: map_rom.c,v 1.21 2004/07/12 14:06:01 dwmw2 Exp $
*/
#include <linux/module.h>
* Copyright 2000,2001 David A. Schleef <ds@schleef.org>
* 2000,2001 Lineo, Inc.
*
- * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $
+ * $Id: sharp.c,v 1.13 2004/07/12 14:06:34 dwmw2 Exp $
*
* Devices supported:
* LH28F016SCT Symmetrical block flash memory, 2Mx8
/*
- * $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $
+ * $Id: cmdlinepart.c,v 1.14 2004/07/12 12:34:23 dwmw2 Exp $
*
* Read flash partition table from command line
*
* mtdparts=<mtddef>[;<mtddef]
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
* <partdef> := <size>[@offset][<name>][ro]
- * <mtd-id> := unique id used in mapping driver/device
+ * <mtd-id> := unique name used in mapping driver/device (mtd->name)
* <size> := standard linux memsize OR "-" to denote all remaining space
* <name> := '(' NAME ')'
*
return register_mtd_parser(&cmdline_parser);
}
-static void __exit cmdline_parser_exit(void)
-{
- deregister_mtd_parser(&cmdline_parser);
-}
-
module_init(cmdline_parser_init);
-module_exit(cmdline_parser_exit);
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $
+# $Id: Kconfig,v 1.10 2004/07/15 00:34:49 dwmw2 Exp $
menu "Self-contained MTD device drivers"
depends on MTD!=n
depends on MTD && PCI
---help---
This provides a MTD device driver for the Ramix PMC551 RAM PCI card
- from Ramix Inc. <http://www.ramix.com/products/>. These devices come
- in memory configurations from 32M - 1G. If you have one, you
- probably want to enable this.
+ from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
+ These devices come in memory configurations from 32M - 1G. If you
+ have one, you probably want to enable this.
If this driver is compiled as a module you get the ability to select
the size of the aperture window pointing into the devices memory.
config MTD_MS02NV
tristate "DEC MS02-NV NVRAM module support"
- depends on CONFIG_MACH_DECSTATION
+ depends on MTD && MACH_DECSTATION
help
- Support for NVRAM module on DECstation.
+ This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
+ backed-up NVRAM module. The module was originally meant as an NFS
+ accelerator. Say Y here if you have a DECstation 5000/2x0 or a
+ DECsystem 5900 equipped with such a module.
config MTD_SLRAM
tristate "Uncached system RAM"
you can still use it for storage or swap by using this driver to
present it to the system as a Memory Technology Device.
+config MTD_PHRAM
+ tristate "Physical system RAM"
+ depends on MTD
+ help
+ This is a re-implementation of the slram driver above.
+
+ Use this driver to access physical memory that the kernel proper
+ doesn't have access to, memory beyond the mem=xxx limit, nvram,
+ memory on the video card, etc...
+
config MTD_LART
tristate "28F160xx flash driver for LART"
depends on SA1100_LART && MTD
config MTD_DOCPROBE
tristate
- default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m)
+ default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
help
This isn't a real config option, it's derived.
+config MTD_DOCECC
+ tristate
+ default m if MTD_DOCPROBE!=y && MTD_NAND_DISKONCHIP!=y && (MTD_DOCPROBE=m || MTD_NAND_DISKONCHIP=m)
+ default y if MTD_DOCPROBE=y || MTD_NAND_DISKONCHIP=y
+ help
+ This isn't a real config option, it's derived.
+
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
depends on MTD_DOCPROBE
#
# linux/drivers/devices/Makefile
#
-# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $
+# $Id: Makefile.common,v 1.6 2004/07/12 16:07:30 dwmw2 Exp $
# *** BIG UGLY NOTE ***
#
obj-$(CONFIG_MTD_DOC2000) += doc2000.o
obj-$(CONFIG_MTD_DOC2001) += doc2001.o
obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o
-obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o
+obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o
+obj-$(CONFIG_MTD_DOCECC) += docecc.o
obj-$(CONFIG_MTD_SLRAM) += slram.o
+obj-$(CONFIG_MTD_PHRAM) += phram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
/*
- * $Id: blkmtd-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
+ * $Id: blkmtd-25.c,v 1.6 2004/07/15 15:09:15 dwmw2 Exp $
*
* blkmtd.c - use a block device as a fake MTD
*
/* Default erase size in K, always make it a multiple of PAGE_SIZE */
#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
-#define VERSION "$Revision: 1.5 $"
+#define VERSION "$Revision: 1.6 $"
/* Info for the block device */
struct blkmtd_dev {
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
- * $Id: doc2000.c,v 1.53 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.60 2004/04/07 08:30:04 gleixner Exp $
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/doc2000.h>
#define DOC_SUPPORT_2000
+#define DOC_SUPPORT_2000TSOP
#define DOC_SUPPORT_MILLENNIUM
#ifdef DOC_SUPPORT_2000
#define DoC_is_2000(doc) (0)
#endif
-#ifdef DOC_SUPPORT_MILLENNIUM
+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
#define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
#else
#define DoC_is_Millennium(doc) (0)
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused);
+ size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused);
+ size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs,
+ unsigned long count, loff_t to, size_t *retlen,
+ u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
/* Out-of-line routine to wait for chip response */
while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+ /* issue 2 read from NOP register after reading from CDSNControl register
+ see Software Requirement 11.4 item 2. */
+ DoC_Delay(doc, 2);
+
if (time_after(jiffies, timeo)) {
DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
return -EIO;
/* Send the command */
WriteDOC_(command, docptr, doc->ioreg);
+ if (DoC_is_Millennium(doc))
+ WriteDOC(command, docptr, WritePipeTerm);
/* Lower the CLE line */
WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
}
}
+ if (DoC_is_Millennium(doc))
+ WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
+
DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */
/* FIXME: The SlowIO's for millennium could be replaced by
/* Read the manufacturer and device id codes from the device */
- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+ if (DoC_is_Millennium(doc)) {
+ DoC_Delay(doc, 2);
+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+ mfr = ReadDOC(doc->virtadr, LastDataRead);
- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
- dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
- DoC_Delay(doc, 2);
- id = ReadDOC_(doc->virtadr, doc->ioreg);
+ DoC_Delay(doc, 2);
+ dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+ id = ReadDOC(doc->virtadr, LastDataRead);
+ } else {
+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
+ dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+ DoC_Delay(doc, 2);
+ mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+ /* CDSN Slow IO register see Software Req 11.4 item 5. */
+ dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+ DoC_Delay(doc, 2);
+ id = ReadDOC_(doc->virtadr, doc->ioreg);
+ }
/* No response - return failure */
if (mfr == 0xff || mfr == 0)
if (!doc->mfr) {
doc->mfr = mfr;
doc->id = id;
- doc->chipshift =
- nand_flash_ids[i].chipshift;
- doc->page256 = nand_flash_ids[i].page256;
- doc->pageadrlen =
- nand_flash_ids[i].chipshift > 25 ? 3 : 2;
+ doc->chipshift =
+ ffs((nand_flash_ids[i].chipsize << 20)) - 1;
+ doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
+ doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
doc->erasesize =
nand_flash_ids[i].erasesize;
return 1;
/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
-static void DoC_ScanChips(struct DiskOnChip *this)
+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
{
int floor, chip;
int numchips[MAX_FLOORS];
- int maxchips = MAX_CHIPS;
int ret = 1;
this->numchips = 0;
this->mfr = 0;
this->id = 0;
- if (DoC_is_Millennium(this))
- maxchips = MAX_CHIPS_MIL;
-
/* For each floor, find the number of valid chips it contains */
for (floor = 0; floor < MAX_FLOORS; floor++) {
ret = 1;
{
struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
struct DiskOnChip *old = NULL;
+ int maxchips;
/* We must avoid being called twice for the same device. */
switch (this->ChipID) {
+ case DOC_ChipID_Doc2kTSOP:
+ mtd->name = "DiskOnChip 2000 TSOP";
+ this->ioreg = DoC_Mil_CDSN_IO;
+ /* Pretend it's a Millennium */
+ this->ChipID = DOC_ChipID_DocMil;
+ maxchips = MAX_CHIPS;
+ break;
case DOC_ChipID_Doc2k:
mtd->name = "DiskOnChip 2000";
this->ioreg = DoC_2k_CDSN_IO;
+ maxchips = MAX_CHIPS;
break;
case DOC_ChipID_DocMil:
mtd->name = "DiskOnChip Millennium";
this->ioreg = DoC_Mil_CDSN_IO;
+ maxchips = MAX_CHIPS_MIL;
break;
+ default:
+ printk("Unknown ChipID 0x%02x\n", this->ChipID);
+ kfree(mtd);
+ iounmap((void *) this->virtadr);
+ return;
}
printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
+ mtd->writev_ecc = doc_writev_ecc;
mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob;
mtd->sync = NULL;
init_MUTEX(&this->lock);
/* Ident all the chips present. */
- DoC_ScanChips(this);
+ DoC_ScanChips(this, maxchips);
if (!this->totlen) {
kfree(mtd);
size_t * retlen, u_char * buf)
{
/* Just a special case of doc_read_ecc */
- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
}
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf, u_char * eccbuf,
- struct nand_oobinfo *unused)
+ size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
{
struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
unsigned long docptr;
unsigned char syndrome[6];
volatile char dummy;
int i, len256 = 0, ret=0;
+ size_t left = len;
docptr = this->virtadr;
down(&this->lock);
- /* Don't allow a single read to cross a 512-byte block boundary */
- if (from + len > ((from | 0x1ff) + 1))
- len = ((from | 0x1ff) + 1) - from;
-
- /* The ECC will not be calculated correctly if less than 512 is read */
- if (len != 0x200 && eccbuf)
- printk(KERN_WARNING
- "ECC needs a full sector read (adr: %lx size %lx)\n",
- (long) from, (long) len);
-
- /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+ *retlen = 0;
+ while (left) {
+ len = left;
+ /* Don't allow a single read to cross a 512-byte block boundary */
+ if (from + len > ((from | 0x1ff) + 1))
+ len = ((from | 0x1ff) + 1) - from;
- /* Find the chip which is to be used and select it */
- mychip = &this->chips[from >> (this->chipshift)];
+ /* The ECC will not be calculated correctly if less than 512 is read */
+ if (len != 0x200 && eccbuf)
+ printk(KERN_WARNING
+ "ECC needs a full sector read (adr: %lx size %lx)\n",
+ (long) from, (long) len);
- if (this->curfloor != mychip->floor) {
- DoC_SelectFloor(this, mychip->floor);
- DoC_SelectChip(this, mychip->chip);
- } else if (this->curchip != mychip->chip) {
- DoC_SelectChip(this, mychip->chip);
- }
+ /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
- this->curfloor = mychip->floor;
- this->curchip = mychip->chip;
- DoC_Command(this,
- (!this->page256
- && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
- CDSN_CTRL_WP);
- DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
- CDSN_CTRL_ECC_IO);
-
- if (eccbuf) {
- /* Prime the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_EN, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- }
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[from >> (this->chipshift)];
- /* treat crossing 256-byte sector for 2M x 8bits devices */
- if (this->page256 && from + len > (from | 0xff) + 1) {
- len256 = (from | 0xff) + 1 - from;
- DoC_ReadBuf(this, buf, len256);
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
- DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
- DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
- CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
- }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
- DoC_ReadBuf(this, &buf[len256], len - len256);
+ DoC_Command(this,
+ (!this->page256
+ && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+ CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+ CDSN_CTRL_ECC_IO);
- /* Let the caller know we completed it */
- *retlen = len;
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+ } else {
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ }
- if (eccbuf) {
- /* Read the ECC data through the DiskOnChip ECC logic */
- /* Note: this will work even with 2M x 8bit devices as */
- /* they have 8 bytes of OOB per 256 page. mf. */
- DoC_ReadBuf(this, eccbuf, 6);
+ /* treat crossing 256-byte sector for 2M x 8bits devices */
+ if (this->page256 && from + len > (from | 0xff) + 1) {
+ len256 = (from | 0xff) + 1 - from;
+ DoC_ReadBuf(this, buf, len256);
- /* Flush the pipeline */
- if (DoC_is_Millennium(this)) {
- dummy = ReadDOC(docptr, ECCConf);
- dummy = ReadDOC(docptr, ECCConf);
- i = ReadDOC(docptr, ECCConf);
- } else {
- dummy = ReadDOC(docptr, 2k_ECCStatus);
- dummy = ReadDOC(docptr, 2k_ECCStatus);
- i = ReadDOC(docptr, 2k_ECCStatus);
+ DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+ DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+ CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
}
- /* Check the ECC Status */
- if (i & 0x80) {
- int nb_errors;
- /* There was an ECC error */
+ DoC_ReadBuf(this, &buf[len256], len - len256);
+
+ /* Let the caller know we completed it */
+ *retlen += len;
+
+ if (eccbuf) {
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ /* Note: this will work even with 2M x 8bit devices as */
+ /* they have 8 bytes of OOB per 256 page. mf. */
+ DoC_ReadBuf(this, eccbuf, 6);
+
+ /* Flush the pipeline */
+ if (DoC_is_Millennium(this)) {
+ dummy = ReadDOC(docptr, ECCConf);
+ dummy = ReadDOC(docptr, ECCConf);
+ i = ReadDOC(docptr, ECCConf);
+ } else {
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ i = ReadDOC(docptr, 2k_ECCStatus);
+ }
+
+ /* Check the ECC Status */
+ if (i & 0x80) {
+ int nb_errors;
+ /* There was an ECC error */
#ifdef ECC_DEBUG
- printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
+ printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif
- /* Read the ECC syndrom through the DiskOnChip ECC logic.
- These syndrome will be all ZERO when there is no error */
- for (i = 0; i < 6; i++) {
- syndrome[i] =
- ReadDOC(docptr, ECCSyndrome0 + i);
- }
- nb_errors = doc_decode_ecc(buf, syndrome);
+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
+ These syndrome will be all ZERO when there is no error */
+ for (i = 0; i < 6; i++) {
+ syndrome[i] =
+ ReadDOC(docptr, ECCSyndrome0 + i);
+ }
+ nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
- printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
+ printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
#endif
- if (nb_errors < 0) {
- /* We return error, but have actually done the read. Not that
- this can be told to user-space, via sys_read(), but at least
- MTD-aware stuff can know about it by checking *retlen */
- ret = -EIO;
- }
- }
+ if (nb_errors < 0) {
+ /* We return error, but have actually done the read. Not that
+ this can be told to user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by checking *retlen */
+ ret = -EIO;
+ }
+ }
#ifdef PSYCHO_DEBUG
- printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
- eccbuf[3], eccbuf[4], eccbuf[5]);
+ printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+ eccbuf[3], eccbuf[4], eccbuf[5]);
#endif
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
- }
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+ }
- /* according to 11.4.1, we need to wait for the busy line
- * drop if we read to the end of the page. */
- if(0 == ((from + *retlen) & 0x1ff))
- {
- DoC_WaitReady(this);
+ /* according to 11.4.1, we need to wait for the busy line
+ * drop if we read to the end of the page. */
+ if(0 == ((from + len) & 0x1ff))
+ {
+ DoC_WaitReady(this);
+ }
+
+ from += len;
+ left -= len;
+ buf += len;
}
up(&this->lock);
size_t * retlen, const u_char * buf)
{
char eccbuf[6];
- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
}
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf,
- u_char * eccbuf,
- struct nand_oobinfo *unused)
+ u_char * eccbuf, struct nand_oobinfo *oobsel)
{
struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
volatile char dummy;
int len256 = 0;
struct Nand *mychip;
+ size_t left = len;
+ int status;
docptr = this->virtadr;
down(&this->lock);
- /* Don't allow a single write to cross a 512-byte block boundary */
- if (to + len > ((to | 0x1ff) + 1))
- len = ((to | 0x1ff) + 1) - to;
+ *retlen = 0;
+ while (left) {
+ len = left;
- /* The ECC will not be calculated correctly if less than 512 is written */
- if (len != 0x200 && eccbuf)
- printk(KERN_WARNING
- "ECC needs a full sector write (adr: %lx size %lx)\n",
- (long) to, (long) len);
+ /* Don't allow a single write to cross a 512-byte block boundary */
+ if (to + len > ((to | 0x1ff) + 1))
+ len = ((to | 0x1ff) + 1) - to;
- /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+ /* The ECC will not be calculated correctly if less than 512 is written */
+/* DBB-
+ if (len != 0x200 && eccbuf)
+ printk(KERN_WARNING
+ "ECC needs a full sector write (adr: %lx size %lx)\n",
+ (long) to, (long) len);
+ -DBB */
- /* Find the chip which is to be used and select it */
- mychip = &this->chips[to >> (this->chipshift)];
+ /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
- if (this->curfloor != mychip->floor) {
- DoC_SelectFloor(this, mychip->floor);
- DoC_SelectChip(this, mychip->chip);
- } else if (this->curchip != mychip->chip) {
- DoC_SelectChip(this, mychip->chip);
- }
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[to >> (this->chipshift)];
- this->curfloor = mychip->floor;
- this->curchip = mychip->chip;
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(this, mychip->floor);
+ DoC_SelectChip(this, mychip->chip);
+ } else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(this, mychip->chip);
+ }
- /* Set device to main plane of flash */
- DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
- DoC_Command(this,
- (!this->page256
- && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
- CDSN_CTRL_WP);
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
- DoC_Command(this, NAND_CMD_SEQIN, 0);
- DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+ /* Set device to main plane of flash */
+ DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(this,
+ (!this->page256
+ && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+ CDSN_CTRL_WP);
- if (eccbuf) {
- /* Prime the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- }
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
- /* treat crossing 256-byte sector for 2M x 8bits devices */
- if (this->page256 && to + len > (to | 0xff) + 1) {
- len256 = (to | 0xff) + 1 - to;
- DoC_WriteBuf(this, buf, len256);
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+ } else {
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ }
+
+ /* treat crossing 256-byte sector for 2M x 8bits devices */
+ if (this->page256 && to + len > (to | 0xff) + 1) {
+ len256 = (to | 0xff) + 1 - to;
+ DoC_WriteBuf(this, buf, len256);
+
+ DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+ DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+ /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+
+ if (ReadDOC_(docptr, this->ioreg) & 1) {
+ printk(KERN_ERR "Error programming flash\n");
+ /* Error in programming */
+ *retlen = 0;
+ up(&this->lock);
+ return -EIO;
+ }
+
+ DoC_Command(this, NAND_CMD_SEQIN, 0);
+ DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+ CDSN_CTRL_ECC_IO);
+ }
+
+ DoC_WriteBuf(this, &buf[len256], len - len256);
+
+ if (eccbuf) {
+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+ CDSNControl);
+
+ if (DoC_is_Millennium(this)) {
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ } else {
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ }
+
+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
+ CDSNControl);
+
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di = 0; di < 6; di++) {
+ eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+ }
+
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+ printk
+ ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
+#endif
+ }
DoC_Command(this, NAND_CMD_PAGEPROG, 0);
DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
/* There's an implicit DoC_WaitReady() in DoC_Command */
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
+ if (DoC_is_Millennium(this)) {
+ ReadDOC(docptr, ReadPipeInit);
+ status = ReadDOC(docptr, LastDataRead);
+ } else {
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+ status = ReadDOC_(docptr, this->ioreg);
+ }
- if (ReadDOC_(docptr, this->ioreg) & 1) {
+ if (status & 1) {
printk(KERN_ERR "Error programming flash\n");
/* Error in programming */
*retlen = 0;
return -EIO;
}
- DoC_Command(this, NAND_CMD_SEQIN, 0);
- DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
- CDSN_CTRL_ECC_IO);
+ /* Let the caller know we completed it */
+ *retlen += len;
+
+ if (eccbuf) {
+ unsigned char x[8];
+ size_t dummy;
+ int ret;
+
+ /* Write the ECC data to flash */
+ for (di=0; di<6; di++)
+ x[di] = eccbuf[di];
+
+ x[6]=0x55;
+ x[7]=0x55;
+
+ ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
+ if (ret) {
+ up(&this->lock);
+ return ret;
+ }
+ }
+
+ to += len;
+ left -= len;
+ buf += len;
}
- DoC_WriteBuf(this, &buf[len256], len - len256);
+ up(&this->lock);
+ return 0;
+}
- if (eccbuf) {
- WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
- CDSNControl);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs,
+ unsigned long count, loff_t to, size_t *retlen,
+ u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+ static char static_buf[512];
+ static DECLARE_MUTEX(writev_buf_sem);
- if (DoC_is_Millennium(this)) {
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
- } else {
- WriteDOC_(0, docptr, this->ioreg);
- WriteDOC_(0, docptr, this->ioreg);
- WriteDOC_(0, docptr, this->ioreg);
- }
+ size_t totretlen = 0;
+ size_t thisvecofs = 0;
+ int ret= 0;
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (di = 0; di < 6; di++) {
- eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
- }
+ down(&writev_buf_sem);
- /* Reset the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ while(count) {
+ size_t thislen, thisretlen;
+ unsigned char *buf;
-#ifdef PSYCHO_DEBUG
- printk
- ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
-#endif
- }
+ buf = vecs->iov_base + thisvecofs;
+ thislen = vecs->iov_len - thisvecofs;
- DoC_Command(this, NAND_CMD_PAGEPROG, 0);
- DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
- /* There's an implicit DoC_WaitReady() in DoC_Command */
+ if (thislen >= 512) {
+ thislen = thislen & ~(512-1);
+ thisvecofs += thislen;
+ } else {
+ /* Not enough to fill a page. Copy into buf */
+ memcpy(static_buf, buf, thislen);
+ buf = &static_buf[thislen];
+
+ while(count && thislen < 512) {
+ vecs++;
+ count--;
+ thisvecofs = min((512-thislen), vecs->iov_len);
+ memcpy(buf, vecs->iov_base, thisvecofs);
+ thislen += thisvecofs;
+ buf += thisvecofs;
+ }
+ buf = static_buf;
+ }
+ if (count && thisvecofs == vecs->iov_len) {
+ thisvecofs = 0;
+ vecs++;
+ count--;
+ }
+ ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
+ totretlen += thisretlen;
- if (ReadDOC_(docptr, this->ioreg) & 1) {
- printk(KERN_ERR "Error programming flash\n");
- /* Error in programming */
- *retlen = 0;
- up(&this->lock);
- return -EIO;
- }
+ if (ret || thisretlen != thislen)
+ break;
- /* Let the caller know we completed it */
- *retlen = len;
-
- if (eccbuf) {
- unsigned char x[8];
- size_t dummy;
- int ret;
-
- /* Write the ECC data to flash */
- for (di=0; di<6; di++)
- x[di] = eccbuf[di];
-
- x[6]=0x55;
- x[7]=0x55;
-
- ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
- up(&this->lock);
- return ret;
- }
- up(&this->lock);
- return 0;
+ to += thislen;
+ }
+
+ up(&writev_buf_sem);
+ *retlen = totretlen;
+ return ret;
}
+
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, u_char * buf)
{
unsigned long docptr = this->virtadr;
struct Nand *mychip = &this->chips[ofs >> this->chipshift];
volatile int dummy;
+ int status;
// printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
// buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
DoC_Command(this, NAND_CMD_STATUS, 0);
/* DoC_WaitReady() is implicit in DoC_Command */
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
+ if (DoC_is_Millennium(this)) {
+ ReadDOC(docptr, ReadPipeInit);
+ status = ReadDOC(docptr, LastDataRead);
+ } else {
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+ status = ReadDOC_(docptr, this->ioreg);
+ }
- if (ReadDOC_(docptr, this->ioreg) & 1) {
+ if (status & 1) {
printk(KERN_ERR "Error programming oob data\n");
/* There was an error */
*retlen = 0;
DoC_Command(this, NAND_CMD_STATUS, 0);
/* DoC_WaitReady() is implicit in DoC_Command */
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
+ if (DoC_is_Millennium(this)) {
+ ReadDOC(docptr, ReadPipeInit);
+ status = ReadDOC(docptr, LastDataRead);
+ } else {
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+ status = ReadDOC_(docptr, this->ioreg);
+ }
- if (ReadDOC_(docptr, this->ioreg) & 1) {
+ if (status & 1) {
printk(KERN_ERR "Error programming oob data\n");
/* There was an error */
*retlen = 0;
volatile int dummy;
unsigned long docptr;
struct Nand *mychip;
+ int status;
down(&this->lock);
DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
- dummy = ReadDOC(docptr, CDSNSlowIO);
- DoC_Delay(this, 2);
-
- if (ReadDOC_(docptr, this->ioreg) & 1) {
+ if (DoC_is_Millennium(this)) {
+ ReadDOC(docptr, ReadPipeInit);
+ status = ReadDOC(docptr, LastDataRead);
+ } else {
+ dummy = ReadDOC(docptr, CDSNSlowIO);
+ DoC_Delay(this, 2);
+ status = ReadDOC_(docptr, this->ioreg);
+ }
+
+ if (status & 1) {
printk(KERN_ERR "Error erasing at 0x%x\n", ofs);
/* There was an error */
instr->state = MTD_ERASE_FAILED;
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
- * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.42 2004/04/04 12:36:45 gleixner Exp $
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused);
+ size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused);
-
+ size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
doc->mfr = mfr;
doc->id = id;
- doc->chipshift = nand_flash_ids[i].chipshift;
+ doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
break;
}
}
size_t *retlen, u_char *buf)
{
/* Just a special case of doc_read_ecc */
- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
}
static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused)
+ size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
{
int i, ret;
volatile char dummy;
size_t *retlen, const u_char *buf)
{
char eccbuf[6];
- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
}
static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *unused)
+ size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
{
int i,ret = 0;
volatile char dummy;
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
- * $Id: doc2001plus.c,v 1.5 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.8 2004/04/04 12:36:45 gleixner Exp $
+ *
+ * Released under GPL
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
* | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 |
* +-----------+-------+-------+-------+--------------+---------+-----------+
*/
+/* FIXME: This lives in INFTL not here. Other users of flash devices
+ may not want it */
static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
{
- unsigned int ofs = *from & 0x3ff;
- unsigned int cmd;
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
- if (ofs < 512) {
- cmd = NAND_CMD_READ0;
- ofs &= 0x1ff;
- } else if (ofs < 1014) {
- cmd = NAND_CMD_READ1;
- ofs = (ofs & 0x1ff) + 10;
+ if (this->interleave) {
+ unsigned int ofs = *from & 0x3ff;
+ unsigned int cmd;
+
+ if (ofs < 512) {
+ cmd = NAND_CMD_READ0;
+ ofs &= 0x1ff;
+ } else if (ofs < 1014) {
+ cmd = NAND_CMD_READ1;
+ ofs = (ofs & 0x1ff) + 10;
+ } else {
+ cmd = NAND_CMD_READOOB;
+ ofs = ofs - 1014;
+ }
+
+ *from = (*from & ~0x3ff) | ofs;
+ return cmd;
} else {
- cmd = NAND_CMD_READOOB;
- ofs = ofs - 1014;
+ /* No interleave */
+ if ((*from) & 0x100)
+ return NAND_CMD_READ1;
+ return NAND_CMD_READ0;
}
-
- *from = (*from & ~0x3ff) | ofs;
- return cmd;
}
static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
mfr = ReadDOC(docptr, Mil_CDSN_IO);
- dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+ if (doc->interleave)
+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
id = ReadDOC(docptr, Mil_CDSN_IO);
- dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+ if (doc->interleave)
+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
dummy = ReadDOC(docptr, Mplus_LastDataRead);
dummy = ReadDOC(docptr, Mplus_LastDataRead);
nand_manuf_ids[j].name, nand_flash_ids[i].name);
doc->mfr = mfr;
doc->id = id;
- doc->interleave = 0;
- if (doc->ChipID == DOC_ChipID_DocMilPlus32)
- doc->interleave = 1;
- doc->chipshift = nand_flash_ids[i].chipshift;
+ doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
break;
}
this->mfr = 0;
this->id = 0;
+ /* Work out the intended interleave setting */
+ this->interleave = 0;
+ if (this->ChipID == DOC_ChipID_DocMilPlus32)
+ this->interleave = 1;
+
+ /* Check the ASIC agrees */
+ if ( (this->interleave << 2) !=
+ (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
+ u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
+ printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
+ this->interleave?"on (16-bit)":"off (8-bit)");
+ conf ^= 4;
+ WriteDOC(this->virtadr, conf, Mplus_Configuration);
+ }
+
/* For each floor, find the number of valid chips it contains */
for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
numchips[floor] = 0;
return -EINVAL;
/* Determine position of OOB flags, before or after data */
- before = to & 0x200;
+ before = (this->interleave && (to & 0x200));
DoC_CheckASIC(docptr);
/* Figure out which region we are accessing... */
fofs = ofs;
base = ofs & 0xf;
- if (base < 6) {
+ if (!this->interleave) {
+ DoC_Command(docptr, NAND_CMD_READOOB, 0);
+ size = 16 - base;
+ } else if (base < 6) {
DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
size = 6 - base;
} else if (base < 8) {
/* Figure out which region we are accessing... */
fofs = ofs;
base = ofs & 0x0f;
- if (base < 6) {
+ if (!this->interleave) {
+ WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
+ size = 16 - base;
+ } else if (base < 6) {
WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
size = 6 - base;
} else if (base < 8) {
/* (C) 1999 Machine Vision Holdings, Inc. */
/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */
-/* $Id: docprobe.c,v 1.36 2003/05/23 11:29:34 dwmw2 Exp $ */
+/* $Id: docprobe.c,v 1.41 2003/12/03 10:19:57 dwmw2 Exp $ */
window, DOCControl);
#endif /* !DOC_PASSIVE_PROBE */
+ /* We need to read the ChipID register four times. For some
+ newer DiskOnChip 2000 units, the first three reads will
+ return the DiskOnChip Millennium ident. Don't ask. */
ChipID = ReadDOC(window, ChipID);
switch (ChipID) {
break;
case DOC_ChipID_DocMil:
+ /* Check for the new 2000 with Millennium ASIC */
+ ReadDOC(window, ChipID);
+ ReadDOC(window, ChipID);
+ if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
+ ChipID = DOC_ChipID_Doc2kTSOP;
+
/* Check the TOGGLE bit in the ECC register */
tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
if (tmp != tmpb && tmp == tmpc)
return ChipID;
- break;
default:
break;
}
default:
-#ifndef CONFIG_MTD_DOCPROBE_55AA
- printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+#ifdef CONFIG_MTD_DOCPROBE_55AA
+ printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
ChipID, physadr);
#endif
#ifndef DOC_PASSIVE_PROBE
return;
if ((ChipID = doccheck(docptr, physadr))) {
+ if (ChipID == DOC_ChipID_Doc2kTSOP) {
+ /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
+ printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
+ iounmap((void *)docptr);
+ return;
+ }
docfound = 1;
mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
sprintf(namebuf, "with ChipID %2.2X", ChipID);
switch(ChipID) {
+ case DOC_ChipID_Doc2kTSOP:
+ name="2000 TSOP";
+ im_funcname = "DoC2k_init";
+ im_modname = "doc2000";
+ break;
+
case DOC_ChipID_Doc2k:
name="2000";
im_funcname = "DoC2k_init";
/*
* MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
*
- * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
+ * $Id: lart.c,v 1.6 2004/07/14 17:21:38 dwmw2 Exp $
*
* Author: Abraham vd Merwe <abraham@2d3d.co.za>
*
/*
- * Copyright (c) 2001 Maciej W. Rozycki
+ * Copyright (c) 2001 Maciej W. Rozycki
*
- * 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.
+ * 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.
*
- * $Id: ms02-nv.c,v 1.4 2003/05/20 21:03:07 dwmw2 Exp $
+ * $Id: ms02-nv.c,v 1.6 2003/08/19 09:25:36 dwmw2 Exp $
*/
#include <linux/init.h>
static char version[] __initdata =
- "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
+ "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
/*
* Addresses we probe for an MS02-NV at. Modules may be located
- * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
- * boundary within a 0MB up to 448MB range. We don't support a module
- * at 0MB, though.
+ * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
+ * boundary within a 0MiB up to 448MiB range. We don't support a module
+ * at 0MiB, though.
*/
static ulong ms02nv_addrs[] __initdata = {
0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
int ret = -ENODEV;
- /* The module decodes 8MB of address space. */
+ /* The module decodes 8MiB of address space. */
mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
if (!mod_res)
return -ENOMEM;
goto err_out_csr_res;
}
- printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
+ printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
mtd->index, ms02nv_name, addr, size >> 20);
mp->next = root_ms02nv_mtd;
switch (mips_machtype) {
case MACH_DS5000_200:
- csr = (volatile u32 *)KN02_CSR_ADDR;
+ csr = (volatile u32 *)KN02_CSR_BASE;
if (*csr & KN02_CSR_BNK32M)
stride = 2;
break;
case MACH_DS5000_2X0:
- case MACH_DS5000:
+ case MACH_DS5900:
csr = (volatile u32 *)KN03_MCR_BASE;
if (*csr & KN03_MCR_BNK32M)
stride = 2;
/*
- * Copyright (c) 2001 Maciej W. Rozycki
+ * Copyright (c) 2001, 2003 Maciej W. Rozycki
*
- * 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.
+ * DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for
+ * DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260
+ * systems.
*
- * $Id: ms02-nv.h,v 1.1 2002/09/13 13:46:55 dwmw2 Exp $
+ * 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.
+ *
+ * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $
*/
#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
+/*
+ * Addresses are decoded as follows:
+ *
+ * 0x000000 - 0x3fffff SRAM
+ * 0x400000 - 0x7fffff CSR
+ *
+ * Within the SRAM area the following ranges are forced by the system
+ * firmware:
+ *
+ * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot
+ * 0x000400 - ENDofRAM storage area, available to operating systems
+ *
+ * but we can't really use the available area right from 0x000400 as
+ * the first word is used by the firmware as a status flag passed
+ * from an operating system. If anything but the valid data magic
+ * ID value is found, the firmware considers the SRAM clean, i.e.
+ * containing no valid data, and disables the battery resulting in
+ * data being erased as soon as power is switched off. So the choice
+ * for the start address of the user-available is 0x001000 which is
+ * nicely page aligned. The area between 0x000404 and 0x000fff may
+ * be used by the driver for own needs.
+ *
+ * The diagnostic area defines two status words to be read by an
+ * operating system, a magic ID to distinguish a MS02-NV board from
+ * anything else and a status information providing results of tests
+ * as well as the size of SRAM available, which can be 1MiB or 2MiB
+ * (that's what the firmware handles; no idea if 2MiB modules ever
+ * existed).
+ *
+ * The firmware only handles the MS02-NV board if installed in the
+ * last (15th) slot, so for any other location the status information
+ * stored in the SRAM cannot be relied upon. But from the hardware
+ * point of view there is no problem using up to 14 such boards in a
+ * system -- only the 1st slot needs to be filled with a DRAM module.
+ * The MS02-NV board is ECC-protected, like other MS02 memory boards.
+ *
+ * The state of the battery as provided by the CSR is reflected on
+ * the two onboard LEDs. When facing the battery side of the board,
+ * with the LEDs at the top left and the battery at the bottom right
+ * (i.e. looking from the back side of the system box), their meaning
+ * is as follows (the system has to be powered on):
+ *
+ * left LED battery disable status: lit = enabled
+ * right LED battery condition status: lit = OK
+ */
+
/* MS02-NV iomem register offsets. */
#define MS02NV_CSR 0x400000 /* control & status register */
+/* MS02-NV CSR status bits. */
+#define MS02NV_CSR_BATT_OK 0x01 /* battery OK */
+#define MS02NV_CSR_BATT_OFF 0x02 /* battery disabled */
+
+
/* MS02-NV memory offsets. */
#define MS02NV_DIAG 0x0003f8 /* diagnostic status */
#define MS02NV_MAGIC 0x0003fc /* MS02-NV magic ID */
-#define MS02NV_RAM 0x000400 /* general-purpose RAM start */
+#define MS02NV_VALID 0x000400 /* valid data magic ID */
+#define MS02NV_RAM 0x001000 /* user-exposed RAM start */
-/* MS02-NV diagnostic status constants. */
-#define MS02NV_DIAG_SIZE_MASK 0xf0 /* RAM size mask */
-#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* RAM size shift (left) */
+/* MS02-NV diagnostic status bits. */
+#define MS02NV_DIAG_TEST 0x01 /* SRAM test done (?) */
+#define MS02NV_DIAG_RO 0x02 /* SRAM r/o test done */
+#define MS02NV_DIAG_RW 0x04 /* SRAM r/w test done */
+#define MS02NV_DIAG_FAIL 0x08 /* SRAM test failed */
+#define MS02NV_DIAG_SIZE_MASK 0xf0 /* SRAM size mask */
+#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* SRAM size shift (left) */
/* MS02-NV general constants. */
#define MS02NV_ID 0x03021966 /* MS02-NV magic ID value */
+#define MS02NV_VALID_ID 0xbd100248 /* valid data magic ID value */
#define MS02NV_SLOT_SIZE 0x800000 /* size of the address space
decoded by the module */
+
typedef volatile u32 ms02nv_uint;
struct ms02nv_private {
/*
- * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.26 2004/07/14 17:25:07 dwmw2 Exp $
*
* PMC551 PCI Mezzanine Ram Device
*
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $
*
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
int init_ftl(void)
{
- DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
+ DEBUG(0, "$Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n");
return register_mtd_blktrans(&ftl_tr);
}
* (c) 1999 Machine Vision Holdings, Inc.
* Author: David Woodhouse <dwmw2@infradead.org>
*
- * $Id: inftlcore.c,v 1.14 2003/06/26 08:28:26 dwmw2 Exp $
+ * $Id: inftlcore.c,v 1.16 2004/07/12 12:34:58 dwmw2 Exp $
*
* 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
struct INFTLrecord *inftl;
unsigned long temp;
- if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+ if (mtd->type != MTD_NANDFLASH)
+ return;
+ /* OK, this is moderately ugly. But probably safe. Alternatives? */
+ if (memcmp(mtd->name, "DiskOnChip", 10))
return;
+ if (!mtd->block_isbad) {
+ printk(KERN_ERR
+"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
+ return;
+ }
+
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512;
inftl->mbd.tr = tr;
+ memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+ inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (INFTL_mount(inftl) < 0) {
printk(KERN_WARNING "INFTL: could not mount device\n");
if (BlockMap[block] == BLOCK_NIL)
continue;
- ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
- &retlen, movebuf, (char *)&oob, NULL);
+ &retlen, movebuf);
if (ret < 0) {
- ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+ ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE),
- SECTORSIZE, &retlen, movebuf, (char *)&oob,
- NULL);
+ SECTORSIZE, &retlen, movebuf);
if (ret != -EIO)
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
"away on retry?\n");
}
+ memset(&oob, 0xff, sizeof(struct inftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
(block * SECTORSIZE), SECTORSIZE, &retlen,
- movebuf, (char *)&oob, NULL);
+ movebuf, (char *)&oob, &inftl->oobinfo);
}
/*
if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
- * FixMe: Update Bad Unit Table on disk.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else {
if (INFTL_formatblock(inftl, thisEUN) < 0) {
/*
* Could not erase : mark block as reserved.
- * FixMe: Update Bad Unit Table on medium.
*/
inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else {
unsigned int writeEUN;
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
size_t retlen;
- u8 eccbuf[6];
+ struct inftl_oob oob;
char *p, *pend;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%ld,"
return 1;
}
+ memset(&oob, 0xff, sizeof(struct inftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
blockofs, SECTORSIZE, &retlen, (char *)buffer,
- (char *)eccbuf, NULL);
+ (char *)&oob, &inftl->oobinfo);
/*
- * No need to write SECTOR_USED flags since they are written
+ * need to write SECTOR_USED flags since they are not written
* in mtd_writeecc
*/
} else {
} else {
size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
- u_char eccbuf[6];
- if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
- buffer, eccbuf, NULL))
+ if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
+ buffer))
return -EIO;
}
return 0;
int __init init_inftl(void)
{
- printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.14 $, "
+ printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.16 $, "
"inftlmount.c %s\n", inftlmountrev);
return register_mtd_blktrans(&inftl_tr);
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
- * $Id: inftlmount.c,v 1.11 2003/06/23 07:39:21 dwmw2 Exp $
+ * $Id: inftlmount.c,v 1.13 2004/06/28 16:06:36 dbrown Exp $
*
* 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
#include <linux/mtd/inftl.h>
#include <linux/mtd/compatmac.h>
-char inftlmountrev[]="$Revision: 1.11 $";
+char inftlmountrev[]="$Revision: 1.13 $";
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
{
struct inftl_unittail h1;
//struct inftl_oob oob;
- unsigned int i, block, boot_record_count = 0;
+ unsigned int i, block;
u8 buf[SECTORSIZE];
struct INFTLMediaHeader *mh = &inftl->MediaHdr;
struct INFTLPartition *ip;
inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
inftl->MediaUnit = BLOCK_NIL;
- inftl->SpareMediaUnit = BLOCK_NIL;
/* Search for a valid boot record */
for (block = 0; block < inftl->nb_blocks; block++) {
* Check for BNAND header first. Then whinge if it's found
* but later checks fail.
*/
- if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
- SECTORSIZE, &retlen, buf))) {
+ ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
+ SECTORSIZE, &retlen, buf);
+ /* We ignore ret in case the ECC of the MediaHeader is invalid
+ (which is apparently acceptable) */
+ if (retlen != SECTORSIZE) {
static int warncount = 5;
if (warncount) {
continue;
}
- if (boot_record_count) {
- /*
- * We've already processed one. So we just check if
- * this one is the same as the first one we found.
- */
- if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
- printk(KERN_WARNING "INFTL: Media Headers at "
- "0x%x and 0x%x disagree.\n",
- inftl->MediaUnit * inftl->EraseSize,
- block * inftl->EraseSize);
- return -1;
- }
- if (boot_record_count == 1)
- inftl->SpareMediaUnit = block;
-
- /*
- * Mark this boot record (INFTL MediaHeader) block as
- * reserved.
- */
- inftl->PUtable[block] = BLOCK_RESERVED;
-
- boot_record_count++;
- continue;
- }
/*
* This is the first we've seen.
* Copy the media header structure into place.
*/
memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
+
+ /* Read the spare media header at offset 4096 */
+ MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
+ SECTORSIZE, &retlen, buf);
+ if (retlen != SECTORSIZE) {
+ printk(KERN_WARNING "INFTL: Unable to read spare "
+ "Media Header\n");
+ return -1;
+ }
+ /* Check if this one is the same as the first one we found. */
+ if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
+ printk(KERN_WARNING "INFTL: Primary and spare Media "
+ "Headers disagree.\n");
+ return -1;
+ }
+
mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
"UnitSizeFactor 0x%02x is experimental\n",
mh->BlockMultiplierBits);
inftl->EraseSize = inftl->mbd.mtd->erasesize <<
- (0xff - mh->BlockMultiplierBits);
+ mh->BlockMultiplierBits;
inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+ block >>= mh->BlockMultiplierBits;
}
/* Scan the partitions */
/* Mark this boot record (NFTL MediaHeader) block as reserved */
inftl->PUtable[block] = BLOCK_RESERVED;
-#if 0
/* Read Bad Erase Unit Table and modify PUtable[] accordingly */
for (i = 0; i < inftl->nb_blocks; i++) {
- if ((i & (SECTORSIZE - 1)) == 0) {
- /* read one sector for every SECTORSIZE of blocks */
- if ((ret = MTD_READECC(inftl->mbd.mtd,
- block * inftl->EraseSize + i + SECTORSIZE,
- SECTORSIZE, &retlen, buf,
- (char *)&oob, NULL)) < 0) {
- printk(KERN_WARNING "INFTL: read of "
- "bad sector table failed "
- "(err %d)\n", ret);
- kfree(inftl->VUtable);
- kfree(inftl->PUtable);
- return -1;
- }
+ int physblock;
+ /* If any of the physical eraseblocks are bad, don't
+ use the unit. */
+ for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
+ if (inftl->mbd.mtd->block_isbad(inftl->mbd.mtd, i * inftl->EraseSize + physblock))
+ inftl->PUtable[i] = BLOCK_RESERVED;
}
- /* Mark the Bad Erase Unit as RESERVED in PUtable */
- if (buf[i & (SECTORSIZE - 1)] != 0xff)
- inftl->PUtable[i] = BLOCK_RESERVED;
}
-#endif
inftl->MediaUnit = block;
- boot_record_count++;
+ return 0;
}
-
- return boot_record_count ? 0 : -1;
+
+ /* Not found. */
+ return -1;
}
static int memcmpb(void *a, int c, int n)
int len, int check_oob)
{
int i, retlen;
- u8 buf[SECTORSIZE];
+ u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
"address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
address, len, check_oob);
for (i = 0; i < len; i += SECTORSIZE) {
- /*
- * We want to read the sector without ECC check here since a
- * free sector does not have ECC syndrome on it yet.
- */
- if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+ if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
- if (MTD_READOOB(inftl->mbd.mtd, address,
- inftl->mbd.mtd->oobsize, &retlen, buf) < 0)
- return -1;
- if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)
+ if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
* Return: 0 when succeed, -1 on error.
*
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
- * 2. UnitSizeFactor != 0xFF
*/
int INFTL_formatblock(struct INFTLrecord *inftl, int block)
{
int retlen;
struct inftl_unittail uci;
struct erase_info *instr = &inftl->instr;
+ int physblock;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
"block=%d)\n", (int)inftl, block);
memset(instr, 0, sizeof(struct erase_info));
+ /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
+ _first_? */
+
/* Use async erase interface, test return code */
instr->addr = block * inftl->EraseSize;
- instr->len = inftl->EraseSize;
- MTD_ERASE(inftl->mbd.mtd, instr);
+ instr->len = inftl->mbd.mtd->erasesize;
+ /* Erase one physical eraseblock at a time, even though the NAND api
+ allows us to group them. This way we if we have a failure, we can
+ mark only the failed block in the bbt. */
+ for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
+ MTD_ERASE(inftl->mbd.mtd, instr);
+
+ if (instr->state == MTD_ERASE_FAILED) {
+ printk(KERN_WARNING "INFTL: error while formatting block %d\n",
+ block);
+ goto fail;
+ }
- if (instr->state == MTD_ERASE_FAILED) {
/*
- * Could not format, FixMe: We should update the BadUnitTable
- * both in memory and on disk.
- */
- printk(KERN_WARNING "INFTL: error while formatting block %d\n",
- block);
- return -1;
+ * Check the "freeness" of Erase Unit before updating metadata.
+ * FixMe: is this check really necessary? Since we have check the
+ * return code after the erase operation.
+ */
+ if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
+ goto fail;
}
- /*
- * Check the "freeness" of Erase Unit before updating metadata.
- * FixMe: is this check really necessary? Since we have check the
- * return code after the erase operation.
- */
- if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0)
- return -1;
-
uci.EraseMark = cpu_to_le16(ERASE_MARK);
uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
uci.Reserved[0] = 0;
uci.Reserved[1] = 0;
uci.Reserved[2] = 0;
uci.Reserved[3] = 0;
- if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
+ instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
+ if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
8, 8, &retlen, (char *)&uci) < 0)
- return -1;
+ goto fail;
return 0;
+fail:
+ /* could not format, update the bad block table (caller is responsible
+ for setting the PUtable to BLOCK_RESERVED on failure) */
+ inftl->mbd.mtd->block_markbad(inftl->mbd.mtd, instr->addr);
+ return -1;
}
/*
if (INFTL_formatblock(inftl, block) < 0) {
/*
* Cannot format !!!! Mark it as Bad Unit,
- * FixMe: update the BadUnitTable on disk.
*/
inftl->PUtable[block] = BLOCK_RESERVED;
} else {
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.12 2003/06/23 07:38:11 dwmw2 Exp $
+# $Id: Kconfig,v 1.29 2004/07/15 15:29:17 dwmw2 Exp $
menu "Mapping drivers for chip access"
depends on MTD!=n
BE VERY CAREFUL.
-config MTD_ICH2ROM
- tristate "BIOS flash chip on Intel Hub Controller 2"
+config MTD_ICHXROM
+ tristate "BIOS flash chip on Intel Controller Hub 2/3/4/5"
depends on X86 && MTD_JEDECPROBE && MTD_COMPLEX_MAPPINGS
help
- Support for treating the BIOS flash chip on ICH2 motherboards
+ Support for treating the BIOS flash chip on ICHX motherboards
as an MTD device - with this you can reprogram your BIOS.
BE VERY CAREFUL.
config MTD_LASAT
tristate "Flash chips on LASAT board"
- depends on LASAT && MTD_CFI
+ depends on LASAT
help
Support for the flash chips on the Lasat 100 and 200 boards.
You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
both banks.
+config MTD_PB1550
+ tristate "Flash devices on Alchemy PB1550 board"
+ depends on MIPS && MIPS_PB1550
+ help
+ Flash memory access on Alchemy Pb1550 board
+
+config MTD_PB1550_BOOT
+ bool "PB1550 boot flash device"
+ depends on MTD_PB1550
+ help
+ Use the first of the two 64MiB flash banks on Pb1550 board.
+ You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use
+ both banks.
+
+config MTD_PB1550_USER
+ bool "PB1550 user flash device"
+ depends on MTD_PB1550
+ default y if MTD_PB1550_BOOT = n
+ help
+ Use the second of the two 64MiB flash banks on Pb1550 board.
+ You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use
+ both banks.
+
+config MTD_DB1550
+ tristate "Flash devices on Alchemy DB1550 board"
+ depends on MIPS && MIPS_DB1550
+ help
+ Flash memory access on Alchemy Db1550 board
+
+config MTD_DB1550_BOOT
+ bool "DB1550 boot flash device"
+ depends on MTD_DB1550
+ help
+ Use the first of the two 64MiB flash banks on Db1550 board.
+ You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use
+ both banks.
+
+config MTD_DB1550_USER
+ bool "DB1550 user flash device"
+ depends on MTD_DB1550
+ default y if MTD_DB1550_BOOT = n
+ help
+ Use the second of the two 64MiB flash banks on Db1550 board.
+ You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use
+ both banks.
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
BE VERY CAREFUL.
+config MTD_SBC8240
+ tristate "Flash device on SBC8240"
+ depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260
+ help
+ Flash access on the SBC8240 board from Wind River. See
+ <http://www.windriver.com/products/sbc8240/>
+
config MTD_TQM8XXL
tristate "CFI Flash device mapped on TQM8XXL"
depends on MTD_CFI && PPC32 && 8xx && TQM8xxL
config MTD_DBOX2
tristate "CFI Flash device mapped on D-Box2"
- depends on PPC32 && 8xx && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
+ depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
help
This enables access routines for the flash chips on the Nokia/Sagem
D-Box 2 board. If you have one of these boards and would like to use
PhotoMax Digital Picture Frame.
If you have such a device, say 'Y'.
+config MTD_NOR_TOTO
+ tristate "NOR Flash device on TOTO board"
+ depends on ARM && ARCH_OMAP && OMAP_TOTO
+ help
+ This enables access to the NOR flash on the Texas Instruments
+ TOTO board.
+
config MTD_H720X
tristate "Hynix evaluation board mappings"
depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
This enables access to the flash chips on the Hynix evaluation boards.
If you have such a board, say 'Y'.
+config MTD_MPC1211
+ tristate "CFI Flash device mapped on Interface MPC-1211"
+ depends on SUPERH && SH_MPC1211 && MTD_CFI
+ help
+ This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
+ If you have such a board, say 'Y'.
+
# This needs CFI or JEDEC, depending on the cards found.
config MTD_PCI
tristate "PCI MTD driver"
config MTD_WRSBC8260
tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
- depends on MTD_PARTITIONS && SBC82xx
+ depends on (SBC82xx || SBC8560)
+ select MTD_PARTITIONS
+ select MTD_MAP_BANK_WIDTH_4
+ select MTD_MAP_BANK_WIDTH_1
+ select MTD_CFI_I1
+ select MTD_CFI_I4
help
Map driver for WindRiver PowerQUICC II MPC82xx board. Drives
all three flash regions on CS0, CS1 and CS6 if they are configured
correctly by the boot loader.
+config MTD_DMV182
+ tristate "Map driver for Dy-4 SVME/DMV-182 board."
+ depends on DMV182
+ select MTD_PARTITIONS
+ select MTD_MAP_BANK_WIDTH_32
+ select MTD_CFI_I8
+ select MTD_CFI_AMDSTD
+ help
+ Map driver for Dy-4 SVME/DMV-182 board.
+
endmenu
#
# linux/drivers/maps/Makefile
#
-# $Id: Makefile.common,v 1.2 2003/05/28 10:48:41 dwmw2 Exp $
+# $Id: Makefile.common,v 1.14 2004/07/12 16:07:31 dwmw2 Exp $
ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
obj-$(CONFIG_MTD) += map_funcs.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
-obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o
+obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o
+obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
+obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o
+obj-$(CONFIG_MTD_DB1550) += db1550-flash.o
obj-$(CONFIG_MTD_LASAT) += lasat.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
+obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
+obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
+obj-$(CONFIG_MTD_MPC1211) += mpc1211.o
obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
+obj-$(CONFIG_MTD_DMV182) += dmv182.o
* amd76xrom.c
*
* Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.8 2003/05/28 15:44:28 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.12 2004/07/14 14:44:31 thayne Exp $
*/
#include <linux/module.h>
#include <linux/pci_ids.h>
+#define xstr(s) str(s)
+#define str(s) #s
+#define MOD_NAME xstr(KBUILD_BASENAME)
+
+#define MTD_DEV_NAME_LENGTH 16
+
struct amd76xrom_map_info {
struct map_info map;
struct mtd_info *mtd;
unsigned long window_addr;
u32 window_start, window_size;
struct pci_dev *pdev;
+ struct resource window_rsrc;
+ struct resource rom_rsrc;
+ char mtd_name[MTD_DEV_NAME_LENGTH];
};
static struct amd76xrom_map_info amd76xrom_map = {
.map = {
- .name = "AMD76X rom",
+ .name = MOD_NAME,
.size = 0,
- .buswidth = 1,
- },
- .mtd = NULL,
- .window_addr = 0,
+ .bankwidth = 1,
+ }
+ /* remaining fields of structure are initialized to 0 */
};
+
+static void amd76xrom_cleanup(struct amd76xrom_map_info *info)
+{
+ u8 byte;
+
+ /* Disable writes through the rom window */
+ pci_read_config_byte(info->pdev, 0x40, &byte);
+ pci_write_config_byte(info->pdev, 0x40, byte & ~1);
+
+ if (info->mtd) {
+ del_mtd_device(info->mtd);
+ map_destroy(info->mtd);
+ info->mtd = NULL;
+ info->map.virt = 0;
+ }
+ if (info->rom_rsrc.parent)
+ release_resource(&info->rom_rsrc);
+ if (info->window_rsrc.parent)
+ release_resource(&info->window_rsrc);
+
+ if (info->window_addr) {
+ iounmap((void *)(info->window_addr));
+ info->window_addr = 0;
+ }
+}
+
+
static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
u8 segen_bits;
};
static struct rom_window rom_window[] = {
+ /*
+ * Need the 5MiB window for chips that have block lock/unlock
+ * registers located below 4MiB window.
+ */
{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
{ 0xffc00000, 4*1024*1024, (1<<7), },
{ 0xffff0000, 64*1024, 0 },
int i;
u32 rom_size;
+ info->pdev = pdev;
window = &rom_window[0];
- /* disabled because it fights with BIOS reserved regions */
-#define REQUEST_MEM_REGION 0
-#if REQUEST_MEM_REGION
- while(window->size) {
- if (request_mem_region(window->start, window->size, "amd76xrom")) {
- break;
+ while (window->size) {
+ /*
+ * Try to reserve the window mem region. If this fails then
+ * it is likely due to a fragment of the window being
+ * "reseved" by the BIOS. In the case that the
+ * request_mem_region() fails then once the rom size is
+ * discovered we will try to reserve the unreserved fragment.
+ */
+ info->window_rsrc.name = MOD_NAME;
+ info->window_rsrc.start = window->start;
+ info->window_rsrc.end = window->start + window->size - 1;
+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&iomem_resource, &info->window_rsrc)) {
+ info->window_rsrc.parent = NULL;
+ printk(KERN_ERR MOD_NAME
+ " %s(): Unable to register resource"
+ " 0x%.08lx-0x%.08lx - kernel bug?\n",
+ __func__,
+ info->window_rsrc.start, info->window_rsrc.end);
}
- window++;
- }
- if (!window->size) {
- printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
- goto err_out_none;
- }
-#endif /* REQUEST_MEM_REGION */
- /* Enable the selected rom window */
- pci_read_config_byte(pdev, 0x43, &byte);
- pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+ /* Enable the selected rom window */
+ pci_read_config_byte(pdev, 0x43, &byte);
+ pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
- /* Enable writes through the rom window */
- pci_read_config_byte(pdev, 0x40, &byte);
- pci_write_config_byte(pdev, 0x40, byte | 1);
+ /* Enable writes through the rom window */
+ pci_read_config_byte(pdev, 0x40, &byte);
+ pci_write_config_byte(pdev, 0x40, byte | 1);
- /* FIXME handle registers 0x80 - 0x8C the bios region locks */
+ /* FIXME handle registers 0x80 - 0x8C the bios region locks */
- printk(KERN_NOTICE "amd76xrom window : %x at %x\n",
- window->size, window->start);
- /* For write accesses caches are useless */
- info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+ printk(KERN_NOTICE MOD_NAME " window : %x at %x\n",
+ window->size, window->start);
+ /* For write accesses caches are useless */
+ info->window_addr =
+ (unsigned long)ioremap_nocache(window->start,
+ window->size);
- if (!info->window_addr) {
- printk(KERN_ERR "Failed to ioremap\n");
- goto err_out_free_mmio_region;
- }
- info->mtd = NULL;
- for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
- char **chip_type;
- if (rom_size > window->size) {
+ if (!info->window_addr) {
+ printk(KERN_ERR "Failed to ioremap\n");
continue;
}
- info->map.phys = window->start + window->size - rom_size;
- info->map.virt =
- info->window_addr + window->size - rom_size;
- info->map.size = rom_size;
- simple_map_init(&info->map);
- chip_type = rom_probe_types;
- for(; !info->mtd && *chip_type; chip_type++) {
- info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
- }
- if (info->mtd) {
- break;
+
+ info->mtd = NULL;
+
+ for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+ char **chip_type;
+ if (rom_size > window->size) {
+ continue;
+ }
+ info->map.phys = window->start + window->size - rom_size;
+ info->map.virt =
+ info->window_addr + window->size - rom_size;
+ info->map.size = rom_size;
+ simple_map_init(&info->map);
+ chip_type = rom_probe_types;
+ for(; !info->mtd && *chip_type; chip_type++) {
+ info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
+ }
+ if (info->mtd) goto found_mtd;
}
+ iounmap((void *)(info->window_addr));
+ info->window_addr = 0;
+
+ /* Disable writes through the rom window */
+ pci_read_config_byte(pdev, 0x40, &byte);
+ pci_write_config_byte(pdev, 0x40, byte & ~1);
+
+ window++;
}
- if (!info->mtd) {
- goto err_out_iounmap;
- }
- printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n",
+ goto failed;
+
+ found_mtd:
+ printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n",
window->size - rom_size);
-
+
info->mtd->owner = THIS_MODULE;
+
+ if (!info->window_rsrc.parent) {
+ /* failed to reserve entire window - try fragments */
+ info->window_rsrc.name = MOD_NAME;
+ info->window_rsrc.start = window->start;
+ info->window_rsrc.end = window->start + window->size - rom_size - 1;
+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&iomem_resource, &info->window_rsrc)) {
+ printk(KERN_ERR MOD_NAME
+ ": cannot reserve window resource fragment\n");
+#if 0
+ /*
+ * The BIOS e820 usually reserves this so it isn't
+ * usually an error.
+ */
+ goto failed;
+#endif
+ }
+ }
+
add_mtd_device(info->mtd);
info->window_start = window->start;
info->window_size = window->size;
+
+ if (info->window_rsrc.parent) {
+ /*
+ * Registering the MTD device in iomem may not be possible
+ * if there is a BIOS "reserved" and BUSY range. If this
+ * fails then continue anyway.
+ */
+ snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
+ "mtd%d", info->mtd->index);
+
+ info->rom_rsrc.name = info->mtd_name;
+ info->rom_rsrc.start = window->start + window->size - rom_size;
+ info->rom_rsrc.end = window->start + window->size - 1;
+ info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
+ printk(KERN_ERR MOD_NAME
+ ": cannot reserve MTD resource\n");
+ info->rom_rsrc.parent = NULL;
+ }
+ }
+
return 0;
-err_out_iounmap:
- iounmap((void *)(info->window_addr));
-err_out_free_mmio_region:
-#if REQUEST_MEM_REGION
- release_mem_region(window->start, window->size);
-err_out_none:
-#endif /* REQUEST_MEM_REGION */
+ failed:
+ amd76xrom_cleanup(info);
return -ENODEV;
}
static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
{
struct amd76xrom_map_info *info = &amd76xrom_map;
- u8 byte;
-
- del_mtd_device(info->mtd);
- map_destroy(info->mtd);
- info->mtd = NULL;
- info->map.virt = 0;
-
- iounmap((void *)(info->window_addr));
- info->window_addr = 0;
-
- /* Disable writes through the rom window */
- pci_read_config_byte(pdev, 0x40, &byte);
- pci_write_config_byte(pdev, 0x40, byte & ~1);
-#if REQUEST_MEM_REGION
- release_mem_region(info->window_start, info->window_size);
-#endif /* REQUEST_MEM_REGION */
+ amd76xrom_cleanup(info);
}
static struct pci_device_id amd76xrom_pci_tbl[] = {
#if 0
static struct pci_driver amd76xrom_driver = {
- .name = "amd76xrom",
+ .name = MOD_NAME,
.id_table = amd76xrom_pci_tbl,
.probe = amd76xrom_init_one,
.remove = amd76xrom_remove_one,
/*
- * $Id: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $
+ * $Id: arctic-mtd.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $
*
* drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
* IBM 405LP Arctic boards.
static struct map_info arctic_mtd_map = {
.name = NAME,
.size = SIZE,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
.phys = PADDR,
};
* NV-RAM memory access on autcpu12
* (C) 2002 Thomas Gleixner (gleixner@autronix.de)
*
- * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: autcpu12-nvram.c,v 1.6 2004/07/12 21:59:43 dwmw2 Exp $
*
* 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
struct map_info autcpu12_sram_map = {
.name = "SRAM",
.size = 32768,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = 0x12000000,
};
/*
- * $Id: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: beech-mtd.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $
*
* drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
* IBM 405LP Beech boards.
static struct map_info beech_mtd_map = {
.name = NAME,
.size = SIZE,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
.phys = PADDR
};
/*
* Flash on Cirrus CDB89712
*
- * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: cdb89712.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $
*/
#include <linux/module.h>
struct map_info cdb89712_flash_map = {
.name = "flash",
.size = FLASH_SIZE,
- .buswidth = FLASH_WIDTH,
+ .bankwidth = FLASH_WIDTH,
.phys = FLASH_START,
};
struct map_info cdb89712_sram_map = {
.name = "SRAM",
.size = SRAM_SIZE,
- .buswidth = SRAM_WIDTH,
+ .bankwidth = SRAM_WIDTH,
.phys = SRAM_START,
};
struct map_info cdb89712_bootrom_map = {
.name = "BootROM",
.size = BOOTROM_SIZE,
- .buswidth = BOOTROM_WIDTH,
+ .bankwidth = BOOTROM_WIDTH,
.phys = BOOTROM_START,
};
*
* (C) 2000 Nicolas Pitre <nico@cam.org>
*
- * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: ceiva.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $
*/
#include <linux/config.h>
}
clps[i].map->virt = (unsigned long)clps[i].vbase;
- clps[i].map->buswidth = clps[i].width;
+ clps[i].map->bankwidth = clps[i].width;
clps[i].map->size = clps[i].size;
simple_map_init(&clps[i].map);
/*
* Copyright © 2001 Flaga hf. Medical Devices, Kári DavÃðsson <kd@flaga.is>
*
- * $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: cfi_flagadm.c,v 1.12 2004/07/12 21:59:43 dwmw2 Exp $
*
* 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
struct map_info flagadm_map = {
.name = "FlagaDM flash device",
.size = FLASH_SIZE,
- .buswidth = 2,
+ .bankwidth = 2,
};
struct mtd_partition flagadm_parts[] = {
/*
- * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: cstm_mips_ixx.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $
*
* Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
* Config with both CFI and JEDEC device support.
char *name;
unsigned long window_addr;
unsigned long window_size;
- int buswidth;
+ int bankwidth;
int num_partitions;
};
"big flash", // name
0x08000000, // window_addr
0x02000000, // window_size
- 4, // buswidth
+ 4, // bankwidth
1, // num_partitions
}
"MTD flash", // name
CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr
CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size
- CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // buswidth
+ CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // bankwidth
1, // num_partitions
},
}
cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
- cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
+ cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
#endif
/*
- * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dbox2-flash.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $
*
* D-Box 2 flash driver
*/
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
+#include <linux/errno.h>
/* partition_info gives details on the logical partitions that the split the
* single flash device into. If the size if zero we use up to the end of the
.mask_flags = MTD_WRITEABLE
},
{
- .name = "flfs (ppcboot)",
+ .name = "FLFS (U-Boot)",
.size = 128 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
- .name = "root (cramfs)",
+ .name = "Root (SquashFS)",
.size = 7040 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
- .name = "var (jffs2)",
+ .name = "var (JFFS2)",
.size = 896 * 1024,
.offset = MTDPART_OFS_APPEND,
.mask_flags = 0
},
{
- .name = "flash without bootloader",
+ .name = "Flash without bootloader",
.size = MTDPART_SIZ_FULL,
.offset = 128 * 1024,
.mask_flags = 0
},
{
- .name = "complete flash",
+ .name = "Complete Flash",
.size = MTDPART_SIZ_FULL,
.offset = 0,
.mask_flags = MTD_WRITEABLE
struct map_info dbox2_flash_map = {
.name = "D-Box 2 flash memory",
.size = WINDOW_SIZE,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = WINDOW_ADDR,
};
mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
if (!mymtd) {
// Probe for single Intel 28F640
- dbox2_flash_map.buswidth = 2;
+ dbox2_flash_map.bankwidth = 2;
mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
}
*
* This code is GPL
*
- * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.20 2004/07/12 22:38:29 dwmw2 Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <asm/io.h>
#include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
-static struct mtd_info *mymtd;
+static struct mtd_info *dc21285_mtd;
-__u8 dc21285_read8(struct map_info *map, unsigned long ofs)
+#ifdef CONFIG_ARCH_NETWINDER
+/*
+ * This is really ugly, but it seams to be the only
+ * realiable way to do it, as the cpld state machine
+ * is unpredictible. So we have a 25us penalty per
+ * write access.
+ */
+static void nw_en_write(void) {
+ extern spinlock_t gpio_lock;
+ unsigned long flags;
+
+ /*
+ * we want to write a bit pattern XXX1 to Xilinx to enable
+ * the write gate, which will be open for about the next 2ms.
+ */
+ spin_lock_irqsave(&gpio_lock, flags);
+ cpld_modify(1, 1);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ /*
+ * let the ISA bus to catch on...
+ */
+ udelay(25);
+}
+#else
+#define nw_en_write() do { } while (0)
+#endif
+
+static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
{
- return *(__u8*)(map->map_priv_1 + ofs);
+ return *(uint8_t*)(map->map_priv_1 + ofs);
}
-__u16 dc21285_read16(struct map_info *map, unsigned long ofs)
+static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
{
- return *(__u16*)(map->map_priv_1 + ofs);
+ return *(uint16_t*)(map->map_priv_1 + ofs);
}
-__u32 dc21285_read32(struct map_info *map, unsigned long ofs)
+static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
{
- return *(__u32*)(map->map_priv_1 + ofs);
+ return *(uint32_t*)(map->map_priv_1 + ofs);
}
-void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
memcpy(to, (void*)(map->map_priv_1 + from), len);
}
-void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
+static void dc21285_write(struct map_info *map, map_word d, unsigned long adr)
{
+ if (machine_is_netwinder())
+ nw_en_write();
*CSR_ROMWRITEREG = adr & 3;
adr &= ~3;
- *(__u8*)(map->map_priv_1 + adr) = d;
+ *(uint8_t*)(map->map_priv_1 + adr) = d.x[0];
}
-void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
+static void dc21285_write16(struct map_info *map, map_word d, unsigned long adr)
{
+ if (machine_is_netwinder())
+ nw_en_write();
*CSR_ROMWRITEREG = adr & 3;
adr &= ~3;
- *(__u16*)(map->map_priv_1 + adr) = d;
+ *(uint16_t*)(map->map_priv_1 + adr) = d.x[0];
}
-void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void dc21285_write32(struct map_info *map, map_word d, unsigned long adr)
{
- *(__u32*)(map->map_priv_1 + adr) = d;
+ if (machine_is_netwinder())
+ nw_en_write();
+ *(uint32_t*)(map->map_priv_1 + adr) = d.x[0];
}
-void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
- switch (map->buswidth) {
- case 4:
- while (len > 0) {
- __u32 d = *((__u32*)from)++;
- dc21285_write32(map, d, to);
- to += 4;
- len -= 4;
- }
- break;
- case 2:
- while (len > 0) {
- __u16 d = *((__u16*)from)++;
- dc21285_write16(map, d, to);
- to += 2;
- len -= 2;
- }
- break;
- case 1:
- while (len > 0) {
- __u8 d = *((__u8*)from)++;
- dc21285_write8(map, d, to);
- to++;
- len--;
- }
- break;
+ while (len > 0) {
+ uint32_t d = *((uint32_t*)from)++;
+ dc21285_write32(map, d, to);
+ to += 4;
+ len -= 4;
+ }
+}
+
+static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ while (len > 0) {
+ uint16_t d = *((uint16_t*)from)++;
+ dc21285_write16(map, d, to);
+ to += 2;
+ len -= 2;
}
}
-struct map_info dc21285_map = {
+static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ uint8_t d = *((uint8_t*)from)++;
+ dc21285_write8(map, d, to);
+ to++;
+ len--;
+}
+
+static struct map_info dc21285_map = {
.name = "DC21285 flash",
.phys = NO_XIP,
.size = 16*1024*1024,
- .read8 = dc21285_read8,
- .read16 = dc21285_read16,
- .read32 = dc21285_read32,
.copy_from = dc21285_copy_from,
- .write8 = dc21285_write8,
- .write16 = dc21285_write16,
- .write32 = dc21285_write32,
- .copy_to = dc21285_copy_to
};
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
#endif
-int __init init_dc21285(void)
+static int __init init_dc21285(void)
{
- /*
- * Flash timing is determined with bits 19-16 of the
- * CSR_SA110_CNTL. The value is the number of wait cycles, or
- * 0 for 16 cycles (the default). Cycles are 20 ns.
- * Here we use 7 for 140 ns flash chips.
- */
- /* access time */
- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
- /* burst time */
- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
- /* tristate time */
- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
-
- /* Determine buswidth */
+#ifdef CONFIG_MTD_PARTITIONS
+ int nrparts;
+#endif
+
+ /* Determine bankwidth */
switch (*CSR_SA110_CNTL & (3<<14)) {
case SA110_CNTL_ROMWIDTH_8:
- dc21285_map.buswidth = 1;
+ dc21285_map.bankwidth = 1;
+ dc21285_map.read = dc21285_read8;
+ dc21285_map.write = dc21285_write8;
+ dc21285_map.copy_to = dc21285_copy_to_8;
break;
case SA110_CNTL_ROMWIDTH_16:
- dc21285_map.buswidth = 2;
+ dc21285_map.bankwidth = 2;
+ dc21285_map.read = dc21285_read16;
+ dc21285_map.write = dc21285_write16;
+ dc21285_map.copy_to = dc21285_copy_to_16;
break;
case SA110_CNTL_ROMWIDTH_32:
- dc21285_map.buswidth = 4;
+ dc21285_map.bankwidth = 4;
break;
+ dc21285_map.read = dc21285_read32;
+ dc21285_map.write = dc21285_write32;
+ dc21285_map.copy_to = dc21285_copy_to_32;
default:
- printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
+ printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
return -ENXIO;
}
- printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
- dc21285_map.buswidth*8);
+ printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
+ dc21285_map.bankwidth*8);
/* Let's map the flash area */
dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
return -EIO;
}
- mymtd = do_map_probe("cfi_probe", &dc21285_map);
- if (mymtd) {
- int nrparts = 0;
+ if (machine_is_ebsa285()) {
+ dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
+ } else {
+ dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
+ }
- mymtd->owner = THIS_MODULE;
-
- /* partition fixup */
+ if (!dc21285_mtd) {
+ iounmap((void *)dc21285_map.map_priv_1);
+ return -ENXIO;
+ }
+
+ dc21285_mtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
- nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0);
- if (nrparts > 0) {
- add_mtd_partitions(mymtd, dc21285_parts, nrparts);
- return 0;
- }
-#endif
- add_mtd_device(mymtd);
- return 0;
+ nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, (void *)0);
+ if (nrparts > 0)
+ add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
+ else
+#endif
+ add_mtd_device(dc21285_mtd);
+
+ if(machine_is_ebsa285()) {
+ /*
+ * Flash timing is determined with bits 19-16 of the
+ * CSR_SA110_CNTL. The value is the number of wait cycles, or
+ * 0 for 16 cycles (the default). Cycles are 20 ns.
+ * Here we use 7 for 140 ns flash chips.
+ */
+ /* access time */
+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
+ /* burst time */
+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
+ /* tristate time */
+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
}
-
- iounmap((void *)dc21285_map.map_priv_1);
- return -ENXIO;
+
+ return 0;
}
static void __exit cleanup_dc21285(void)
{
#ifdef CONFIG_MTD_PARTITIONS
if (dc21285_parts) {
- del_mtd_partitions(mymtd);
+ del_mtd_partitions(dc21285_mtd);
kfree(dc21285_parts);
} else
#endif
- del_mtd_device(mymtd);
+ del_mtd_device(dc21285_mtd);
- map_destroy(mymtd);
+ map_destroy(dc21285_mtd);
iounmap((void *)dc21285_map.map_priv_1);
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dilnetpc.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
*
* The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
* featuring the AMD Elan SC410 processor. There are two variants of this
static struct map_info dnpc_map = {
.name = "ADNP Flash Bank",
.size = ADNP_WINDOW_SIZE,
- .buswidth = 1,
+ .bankwidth = 1,
.set_vpp = adnp_set_vpp,
.phys = WINDOW_ADDR
};
/*
- * $Id: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: ebony.c,v 1.10 2004/07/12 21:59:44 dwmw2 Exp $
*
* Mapping for Ebony user flash
*
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <asm/io.h>
-#include <asm/ibm440.h>
+#include <asm/ibm44x.h>
#include <platforms/ebony.h>
static struct mtd_info *flash;
static struct map_info ebony_small_map = {
.name = "Ebony small flash",
.size = EBONY_SMALL_FLASH_SIZE,
- .buswidth = 1,
+ .bankwidth = 1,
};
static struct map_info ebony_large_map = {
.name = "Ebony large flash",
.size = EBONY_LARGE_FLASH_SIZE,
- .buswidth = 1,
+ .bankwidth = 1,
};
static struct mtd_partition ebony_small_partitions[] = {
return -ENOMEM;
fpga0_reg = readb(fpga0_adr);
- iounmap64(fpga0_adr);
+ iounmap(fpga0_adr);
if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
!EBONY_FLASH_SEL(fpga0_reg))
/*
- * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: edb7312.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $
*
* Handle mapping of the NOR flash on Cogent EDB7312 boards
*
#define BUSWIDTH 2
#define FLASH_BLOCKSIZE_MAIN 0x20000
#define FLASH_NUMBLOCKS_MAIN 128
-/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
-#define PROBETYPES { "cfi_probe", 0 }
+/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
+#define PROBETYPES { "cfi_probe", NULL }
#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */
#define MTDID "edb7312-nor" /* for mtdparts= partitioning */
struct map_info edb7312nor_map = {
.name = "NOR flash on EDB7312",
.size = WINDOW_SIZE,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
};
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- $Id: elan-104nc.c,v 1.18 2003/06/23 07:37:02 dwmw2 Exp $
+ $Id: elan-104nc.c,v 1.21 2004/07/12 22:38:29 dwmw2 Exp $
The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
}
-static __u8 elan_104nc_read8(struct map_info *map, unsigned long ofs)
+static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
{
- __u8 ret;
+ map_word ret;
spin_lock(&elan_104nc_spin);
elan_104nc_page(map, ofs);
- ret = readb(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
- return ret;
-}
-
-static __u16 elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
- __u16 ret;
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, ofs);
- ret = readw(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
- return ret;
-}
-
-static __u32 elan_104nc_read32(struct map_info *map, unsigned long ofs)
-{
- __u32 ret;
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, ofs);
- ret = readl(iomapadr + (ofs & WINDOW_MASK));
+ ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK));
spin_unlock(&elan_104nc_spin);
return ret;
}
static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
- while(len) {
+ while (len) {
unsigned long thislen = len;
if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
}
}
-static void elan_104nc_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, adr);
- writeb(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, adr);
- writew(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&elan_104nc_spin);
elan_104nc_page(map, adr);
- writel(d, iomapadr + (adr & WINDOW_MASK));
+ writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
spin_unlock(&elan_104nc_spin);
}
.size = 8*1024*1024, /* this must be set to a maximum possible amount
of flash so the cfi probe routines find all
the chips */
- .buswidth = 2,
- .read8 = elan_104nc_read8,
- .read16 = elan_104nc_read16,
- .read32 = elan_104nc_read32,
+ .bankwidth = 2,
+ .read = elan_104nc_read16,
.copy_from = elan_104nc_copy_from,
- .write8 = elan_104nc_write8,
- .write16 = elan_104nc_write16,
- .write32 = elan_104nc_write32,
+ .write = elan_104nc_write16,
.copy_to = elan_104nc_copy_to
};
* Copyright (C) 2001 Altera Corporation
* Copyright (C) 2001 Red Hat, Inc.
*
- * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: epxa10db-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $
*
* 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
static struct map_info epxa_map = {
.name = "EPXA flash",
.size = FLASH_SIZE,
- .buswidth = 2,
+ .bankwidth = 2,
.phys = FLASH_START,
};
/* fortunet.c memory map
*
- * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: fortunet.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $
*/
#include <linux/module.h>
struct map_region
{
int window_addr_physical;
- int altbuswidth;
+ int altbankwidth;
struct map_info map_info;
struct mtd_info *mymtd;
struct mtd_partition parts[MAX_NUM_PARTITIONS];
struct map_info default_map = {
.size = DEF_WINDOW_SIZE,
- .buswidth = 4,
+ .bankwidth = 4,
};
static char * __init get_string_option(char *dest,int dest_size,char *sor)
if(params[0]<1)
{
printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
- " name,region-number[,base,size,buswidth,altbuswidth]\n");
+ " name,region-number[,base,size,bankwidth,altbankwidth]\n");
return 1;
}
if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
&default_map,sizeof(map_regions[params[1]].map_info));
map_regions_set[params[1]] = 1;
map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
- map_regions[params[1]].altbuswidth = 2;
+ map_regions[params[1]].altbankwidth = 2;
map_regions[params[1]].mymtd = NULL;
map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
strcpy(map_regions[params[1]].map_info.name,string);
}
if(params[0]>3)
{
- map_regions[params[1]].map_info.buswidth = params[4];
+ map_regions[params[1]].map_info.bankwidth = params[4];
}
if(params[0]>4)
{
- map_regions[params[1]].altbuswidth = params[5];
+ map_regions[params[1]].altbankwidth = params[5];
}
return 1;
}
sizeof(map_regions[ix].map_info));
map_regions_set[ix] = 1;
map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
- map_regions[ix].altbuswidth = 2;
+ map_regions[ix].altbankwidth = 2;
map_regions[ix].mymtd = NULL;
map_regions[ix].map_info.name = map_regions[ix].map_name;
strcpy(map_regions[ix].map_info.name,"FORTUNET");
map_regions[ix].mymtd = do_map_probe("cfi_probe",
&map_regions[ix].map_info);
if((!map_regions[ix].mymtd)&&(
- map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+ map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
{
- printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth "
+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
"for %s flash.\n",
map_regions[ix].map_info.name);
- map_regions[ix].map_info.buswidth =
- map_regions[ix].altbuswidth;
+ map_regions[ix].map_info.bankwidth =
+ map_regions[ix].altbankwidth;
map_regions[ix].mymtd = do_map_probe("cfi_probe",
&map_regions[ix].map_info);
}
* Flash memory access on Hynix GMS30C7201/HMS30C7202 based
* evaluation boards
*
+ * $Id: h720x-flash.c,v 1.9 2004/07/14 17:45:40 dwmw2 Exp $
+ *
* (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
* 2003 Thomas Gleixner <tglx@linutronix.de>
-*/
+ */
#include <linux/config.h>
#include <linux/module.h>
static struct map_info h720x_map = {
.name = "H720X",
- .buswidth = 4,
+ .bankwidth = 4,
.size = FLASH_SIZE,
.phys = FLASH_PHYS,
};
simple_map_init(&h720x_map);
- // Probe for flash buswidth 4
+ // Probe for flash bankwidth 4
printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
mymtd = do_map_probe("cfi_probe", &h720x_map);
if (!mymtd) {
printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
- // Probe for buswidth 2
- h720x_map.buswidth = 2;
+ // Probe for bankwidth 2
+ h720x_map.bankwidth = 2;
mymtd = do_map_probe("cfi_probe", &h720x_map);
}
/*
- * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $
+ * $Id: impa7.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $
*
* Handle mapping of the NOR flash on implementa A7 boards
*
#define NUM_FLASHBANKS 2
#define BUSWIDTH 4
-/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
-#define PROBETYPES { "jedec_probe", 0 }
+/* can be { "cfi_probe", "jedec_probe", "map_rom", NULL } */
+#define PROBETYPES { "jedec_probe", NULL }
#define MSG_PREFIX "impA7:" /* prefix for our printk()'s */
#define MTDID "impa7-%d" /* for mtdparts= partitioning */
-static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS];
static struct map_info impa7_map[NUM_FLASHBANKS] = {
{
.name = "impA7 NOR Flash Bank #0",
.size = WINDOW_SIZE0,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
},
{
.name = "impA7 NOR Flash Bank #1",
.size = WINDOW_SIZE1,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
},
};
This is access code for flashes using ARM's flash partitioning
standards.
- $Id: integrator-flash.c,v 1.15 2004/02/27 22:37:39 rmk Exp $
+ $Id: integrator-flash.c,v 1.16 2004/07/12 21:59:44 dwmw2 Exp $
======================================================================*/
* look for CFI based flash parts fitted to this board
*/
info->map.size = size;
- info->map.buswidth = plat->width;
+ info->map.bankwidth = plat->width;
info->map.phys = res->start;
info->map.virt = (unsigned long) base;
info->map.name = dev->dev.bus_id;
/*
- * $Id: iq80310.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.18 2004/07/12 21:59:44 dwmw2 Exp $
*
* Mapping for the Intel XScale IQ80310 evaluation board
*
static struct map_info iq80310_map = {
.name = "IQ80310 flash",
.size = WINDOW_SIZE,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR
};
/*
- * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
*
* BIOS Flash chip on Intel 440GX board.
*
struct map_info l440gx_map = {
.name = "L440GX BIOS",
.size = WINDOW_SIZE,
- .buswidth = BUSWIDTH,
+ .bankwidth = BUSWIDTH,
.phys = WINDOW_ADDR,
#if 0
/* FIXME verify that this is the
/*
- * Flash device on lasat 100 and 200 boards
+ * Flash device on Lasat 100 and 200 boards
*
- * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
- * works for.
+ * (C) 2002 Brian Murphy <brian@murphy.dk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
- * $Id: lasat.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: lasat.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $
*
*/
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <asm/lasat/lasat.h>
-#include <asm/lasat/lasat_mtd.h>
-static struct mtd_info *mymtd;
-
-static struct map_info sp_map = {
- .name = "SP flash",
- .buswidth = 4,
-};
+static struct mtd_info *lasat_mtd;
static struct mtd_partition partition_info[LASAT_MTD_LAST];
static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
-static int __init init_sp(void)
+static void lasat_set_vpp(struct map_info *map, int vpp)
{
- int i;
- /* this does not play well with the old flash code which
- * protects and uprotects the flash when necessary */
- /* FIXME: Implement set_vpp() */
- printk(KERN_NOTICE "Unprotecting flash\n");
- *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+ if (vpp)
+ *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+ else
+ *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit);
+}
+
+static struct map_info lasat_map = {
+ .name = "LASAT flash",
+ .bankwidth = 4,
+ .set_vpp = lasat_set_vpp
+};
- sp_map.virt = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
- sp_map.phys = virt_to_phys(sp_map.virt);
- sp_map.size = lasat_board_info.li_flash_size;
+static int __init init_lasat(void)
+{
+ int i;
+ /* since we use AMD chips and set_vpp is not implimented
+ * for these (yet) we still have to permanently enable flash write */
+ printk(KERN_NOTICE "Unprotecting flash\n");
+ ENABLE_VPP((&lasat_map));
- simple_map_init(&sp_map);
+ lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+ lasat_map.virt = (unsigned long)ioremap_nocache(
+ lasat_map.phys, lasat_board_info.li_flash_size);
+ lasat_map.size = lasat_board_info.li_flash_size;
- printk(KERN_NOTICE "sp flash device: %lx at %lx\n",
- sp_map.size, sp_map.phys);
+ simple_map_init(&lasat_map);
for (i=0; i < LASAT_MTD_LAST; i++)
partition_info[i].name = lasat_mtd_partnames[i];
- mymtd = do_map_probe("cfi_probe", &sp_map);
- if (mymtd) {
+ lasat_mtd = do_map_probe("cfi_probe", &lasat_map);
+
+ if (!lasat_mtd)
+ lasat_mtd = do_map_probe("jedec_probe", &lasat_map);
+
+ if (lasat_mtd) {
u32 size, offset = 0;
- mymtd->owner = THIS_MODULE;
+ lasat_mtd->owner = THIS_MODULE;
for (i=0; i < LASAT_MTD_LAST; i++) {
size = lasat_flash_partition_size(i);
offset += size;
}
- add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
+ add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST );
return 0;
}
return -ENXIO;
}
-static void __exit cleanup_sp(void)
+static void __exit cleanup_lasat(void)
{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
+ if (lasat_mtd) {
+ del_mtd_partitions(lasat_mtd);
+ map_destroy(lasat_mtd);
}
- if (sp_map.virt) {
- sp_map.virt = 0;
+ if (lasat_map.virt) {
+ lasat_map.virt = 0;
}
}
-module_init(init_sp);
-module_exit(cleanup_sp);
+module_init(init_lasat);
+module_exit(cleanup_lasat);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
/*
- * $Id: lubbock-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: lubbock-flash.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $
*
* Map driver for the Lubbock developer platform.
*
#define WINDOW_SIZE 64*1024*1024
+static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
+{
+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+}
+
static struct map_info lubbock_maps[2] = { {
.size = WINDOW_SIZE,
.phys = 0x00000000,
+ .inval_cache = lubbock_map_inval_cache,
}, {
.size = WINDOW_SIZE,
.phys = 0x04000000,
+ .inval_cache = lubbock_map_inval_cache,
} };
static struct mtd_partition lubbock_partitions[] = {
int flashboot = (LUB_CONF_SWITCHES & 1);
int ret = 0, i;
- lubbock_maps[0].buswidth = lubbock_maps[1].buswidth =
+ lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
(BOOT_DEF & 1) ? 2 : 4;
/* Compensate for the nROMBT switch which swaps the flash banks */
ret = -ENOMEM;
continue;
}
+ lubbock_maps[i].cached = __ioremap(lubbock_maps[i].phys,
+ WINDOW_SIZE,
+ L_PTE_CACHEABLE, 1);
+ if (!lubbock_maps[i].cached)
+ printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
simple_map_init(&lubbock_maps[i]);
- printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n",
+ printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
lubbock_maps[i].name, lubbock_maps[i].phys,
- lubbock_maps[i].buswidth * 8);
+ lubbock_maps[i].bankwidth * 8);
mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
if (!mymtds[i]) {
iounmap((void *)lubbock_maps[i].virt);
+ if (lubbock_maps[i].cached)
+ iounmap(lubbock_maps[i].cached);
if (!ret)
ret = -EIO;
continue;
map_destroy(mymtds[i]);
iounmap((void *)lubbock_maps[i].virt);
+ if (lubbock_maps[i].cached)
+ iounmap(lubbock_maps[i].cached);
if (parsed_parts[i])
kfree(parsed_parts[i]);
/*
- * $Id: map_funcs.c,v 1.2 2003/05/21 15:15:07 dwmw2 Exp $
+ * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $
*
* Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
* is enabled.
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <asm/io.h>
#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
+static map_word simple_map_read(struct map_info *map, unsigned long ofs)
{
- return __raw_readb(map->virt + ofs);
+ return inline_map_read(map, ofs);
}
-static u16 simple_map_read16(struct map_info *map, unsigned long ofs)
+static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
{
- return __raw_readw(map->virt + ofs);
-}
-
-static u32 simple_map_read32(struct map_info *map, unsigned long ofs)
-{
- return __raw_readl(map->virt + ofs);
-}
-
-static u64 simple_map_read64(struct map_info *map, unsigned long ofs)
-{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
- BUG();
- return 0;
-#else
- return __raw_readll(map->virt + ofs);
-#endif
-}
-
-static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs)
-{
- __raw_writeb(datum, map->virt + ofs);
- mb();
-}
-
-static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs)
-{
- __raw_writew(datum, map->virt + ofs);
- mb();
-}
-
-static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs)
-{
- __raw_writel(datum, map->virt + ofs);
- mb();
-}
-
-static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs)
-{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
- BUG();
-#else
- __raw_writell(datum, map->virt + ofs);
- mb();
-#endif /* CFI_B8 */
+ inline_map_write(map, datum, ofs);
}
static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
- memcpy_fromio(to, map->virt + from, len);
+ inline_map_copy_from(map, to, from, len);
}
static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
- memcpy_toio(map->virt + to, from, len);
+ inline_map_copy_to(map, to, from, len);
}
void simple_map_init(struct map_info *map)
{
- map->read8 = simple_map_read8;
- map->read16 = simple_map_read16;
- map->read32 = simple_map_read32;
- map->read64 = simple_map_read64;
- map->write8 = simple_map_write8;
- map->write16 = simple_map_write16;
- map->write32 = simple_map_write32;
- map->write64 = simple_map_write64;
+ BUG_ON(!map_bankwidth_supported(map->bankwidth));
+
+ map->read = simple_map_read;
+ map->write = simple_map_write;
map->copy_from = simple_map_copy_from;
map->copy_to = simple_map_copy_to;
}
/*
- * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: mbx860.c,v 1.6 2004/07/12 21:59:44 dwmw2 Exp $
*
* Handle mapping of the flash on MBX860 boards
*
.name = "MBX flash",
.size = WINDOW_SIZE,
.phys = WINDOW_ADDR,
- .buswidth = 4,
+ .bankwidth = 4,
};
int __init init_mbx(void)
* Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
* based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
*
- * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: netsc520.c,v 1.10 2004/07/12 21:59:44 dwmw2 Exp $
*
* 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
static struct map_info netsc520_map = {
.name = "netsc520 Flash Bank",
.size = WINDOW_SIZE,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = WINDOW_ADDR,
};
* (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
* (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
*
- * $Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $
+ * $Id: nettel.c,v 1.5 2004/07/12 21:59:44 dwmw2 Exp $
*/
/****************************************************************************/
static struct map_info nettel_intel_map = {
.name = "SnapGear Intel",
.size = 0,
- .buswidth = INTEL_BUSWIDTH,
+ .bankwidth = INTEL_BUSWIDTH,
};
static struct mtd_partition nettel_intel_partitions[] = {
static struct map_info nettel_amd_map = {
.name = "SnapGear AMD",
.size = AMD_WINDOW_MAXSIZE,
- .buswidth = AMD_BUSWIDTH,
+ .bankwidth = AMD_BUSWIDTH,
};
static struct mtd_partition nettel_amd_partitions[] = {
/*
- * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: ocelot.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
*
* Flash on Momenco Ocelot
*/
struct map_info ocelot_flash_map = {
.name = "Ocelot boot flash",
.size = FLASH_WINDOW_SIZE,
- .buswidth = FLASH_BUSWIDTH,
+ .bankwidth = FLASH_BUSWIDTH,
.phys = FLASH_WINDOW_ADDR,
};
struct map_info ocelot_nvram_map = {
.name = "Ocelot NVRAM",
.size = NVRAM_WINDOW_SIZE,
- .buswidth = NVRAM_BUSWIDTH,
+ .bankwidth = NVRAM_BUSWIDTH,
.phys = NVRAM_WINDOW_ADDR,
};
-// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $
/* ######################################################################
Octagon 5066 MTD Driver.
}
-static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
+static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
{
- __u8 ret;
+ map_word ret;
spin_lock(&oct5066_spin);
oct5066_page(map, ofs);
- ret = readb(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
- return ret;
-}
-
-static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
-{
- __u16 ret;
- spin_lock(&oct5066_spin);
- oct5066_page(map, ofs);
- ret = readw(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
- return ret;
-}
-
-static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
-{
- __u32 ret;
- spin_lock(&oct5066_spin);
- oct5066_page(map, ofs);
- ret = readl(iomapadr + (ofs & WINDOW_MASK));
+ ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
spin_unlock(&oct5066_spin);
return ret;
}
}
}
-static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
- spin_lock(&oct5066_spin);
- oct5066_page(map, adr);
- writeb(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
- spin_lock(&oct5066_spin);
- oct5066_page(map, adr);
- writew(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&oct5066_spin);
oct5066_page(map, adr);
- writel(d, iomapadr + (adr & WINDOW_MASK));
+ writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
spin_unlock(&oct5066_spin);
}
.name = "Octagon 5066 Socket",
.phys = NO_XIP,
.size = 512 * 1024,
- .buswidth = 1,
- .read8 = oct5066_read8,
- .read16 = oct5066_read16,
- .read32 = oct5066_read32,
+ .bankwidth = 1,
+ .read = oct5066_read8,
.copy_from = oct5066_copy_from,
- .write8 = oct5066_write8,
- .write16 = oct5066_write16,
- .write32 = oct5066_write32,
+ .write = oct5066_write8,
.copy_to = oct5066_copy_to,
.map_priv_1 = 1<<6
},
.name = "Octagon 5066 Internal Flash",
.phys = NO_XIP,
.size = 2 * 1024 * 1024,
- .buswidth = 1,
- .read8 = oct5066_read8,
- .read16 = oct5066_read16,
- .read32 = oct5066_read32,
+ .bankwidth = 1,
+ .read = oct5066_read8,
.copy_from = oct5066_copy_from,
- .write8 = oct5066_write8,
- .write16 = oct5066_write16,
- .write32 = oct5066_write32,
+ .write = oct5066_write8,
.copy_to = oct5066_copy_to,
.map_priv_1 = 2<<6
}
*
* (C) 2001 Pete Popov <ppopov@mvista.com>
*
- * $Id: pb1xxx-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: pb1xxx-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#endif
#ifdef CONFIG_MIPS_PB1000
+
#define WINDOW_ADDR 0x1F800000
#define WINDOW_SIZE 0x800000
-#endif
-
-
-static struct map_info pb1xxx_map = {
- .name = "Pb1xxx flash",
-};
-
-
-#ifdef CONFIG_MIPS_PB1000
-static unsigned long flash_size = 0x00800000;
-static unsigned char flash_buswidth = 4;
static struct mtd_partition pb1xxx_partitions[] = {
{
- .name = "yamon env",
- .size = 0x00020000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "User FS",
- .size = 0x003e0000,
- .offset = 0x20000,
- },{
- .name = "boot code",
- .size = 0x100000,
- .offset = 0x400000,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw/kernel",
- .size = 0x300000,
- .offset = 0x500000
- }
+ .name = "yamon env",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE},
+ {
+ .name = "User FS",
+ .size = 0x003e0000,
+ .offset = 0x20000,},
+ {
+ .name = "boot code",
+ .size = 0x100000,
+ .offset = 0x400000,
+ .mask_flags = MTD_WRITEABLE},
+ {
+ .name = "raw/kernel",
+ .size = 0x300000,
+ .offset = 0x500000}
};
#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-static unsigned char flash_buswidth = 4;
#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MiB banks will be used. Combine the first 32MiB bank and the
- * first 28MiB of the second bank together into a single jffs/jffs2
+/* both 32MB banks will be used. Combine the first 32MB bank and the
+ * first 28MB of the second bank together into a single jffs/jffs2
* partition.
*/
-static unsigned long flash_size = 0x04000000;
#define WINDOW_ADDR 0x1C000000
#define WINDOW_SIZE 0x4000000
static struct mtd_partition pb1xxx_partitions[] = {
{
- .name = "User FS",
- .size = 0x3c00000,
- .offset = 0x0000000
+ .name = "User FS",
+ .size = 0x3c00000,
+ .offset = 0x0000000
},{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x3c00000,
- .mask_flags = MTD_WRITEABLE
+ .name = "yamon",
+ .size = 0x0100000,
+ .offset = 0x3c00000,
+ .mask_flags = MTD_WRITEABLE
},{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x3d00000
+ .name = "raw kernel",
+ .size = 0x02c0000,
+ .offset = 0x3d00000
}
};
#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-static unsigned long flash_size = 0x02000000;
#define WINDOW_ADDR 0x1E000000
#define WINDOW_SIZE 0x2000000
static struct mtd_partition pb1xxx_partitions[] = {
{
- .name = "User FS",
- .size = 0x1c00000,
- .offset = 0x0000000
+ .name = "User FS",
+ .size = 0x1c00000,
+ .offset = 0x0000000
},{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x1c00000,
- .mask_flags = MTD_WRITEABLE
+ .name = "yamon",
+ .size = 0x0100000,
+ .offset = 0x1c00000,
+ .mask_flags = MTD_WRITEABLE
},{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x1d00000
+ .name = "raw kernel",
+ .size = 0x02c0000,
+ .offset = 0x1d00000
}
};
#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-static unsigned long flash_size = 0x02000000;
#define WINDOW_ADDR 0x1C000000
#define WINDOW_SIZE 0x2000000
static struct mtd_partition pb1xxx_partitions[] = {
{
- .name = "User FS",
- .size = 0x1e00000,
- .offset = 0x0000000
+ .name = "User FS",
+ .size = 0x1e00000,
+ .offset = 0x0000000
},{
- .name = "raw kernel",
- .size = 0x0200000,
- .offset = 0x1e00000,
+ .name = "raw kernel",
+ .size = 0x0200000,
+ .offset = 0x1e00000,
}
};
#else
#error Unsupported board
#endif
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
+#define NAME "Pb1x00 Linux Flash"
+#define PADDR WINDOW_ADDR
+#define BUSWIDTH 4
+#define SIZE WINDOW_SIZE
+#define PARTITIONS 4
+
+static struct map_info pb1xxx_mtd_map = {
+ .name = NAME,
+ .size = SIZE,
+ .bankwidth = BUSWIDTH,
+ .phys = PADDR,
+};
+
+static struct mtd_info *pb1xxx_mtd;
int __init pb1xxx_mtd_init(void)
{
int nb_parts = 0;
char *part_type;
- /* Default flash buswidth */
- pb1xxx_map.buswidth = flash_buswidth;
-
/*
* Static partition definition selection
*/
part_type = "static";
parts = pb1xxx_partitions;
nb_parts = ARRAY_SIZE(pb1xxx_partitions);
- pb1xxx_map.size = flash_size;
/*
* Now let's probe for the actual flash. Do it here since
* specific machine settings might have been set above.
*/
printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n",
- pb1xxx_map.buswidth*8);
- pb1xxx_map.phys = WINDOW_ADDR;
- pb1xxx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+ BUSWIDTH*8);
+ pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
- simple_map_init(&pb1xxx_map);
+ simple_map_init(&pb1xxx_mtd_map);
- mymtd = do_map_probe("cfi_probe", &pb1xxx_map);
- if (!mymtd) {
- iounmap(pb1xxx_map.virt);
- return -ENXIO;
- }
- mymtd->owner = THIS_MODULE;
+ pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
+ if (!pb1xxx_mtd) return -ENXIO;
+ pb1xxx_mtd->owner = THIS_MODULE;
- add_mtd_partitions(mymtd, parts, nb_parts);
+ add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
return 0;
}
static void __exit pb1xxx_mtd_cleanup(void)
{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- if (parsed_parts)
- kfree(parsed_parts);
+ if (pb1xxx_mtd) {
+ del_mtd_partitions(pb1xxx_mtd);
+ map_destroy(pb1xxx_mtd);
+ iounmap((void *) pb1xxx_mtd_map.virt);
}
- if (pb1xxx_map.virt)
- iounmap(pb1xxx_map.virt);
}
module_init(pb1xxx_mtd_init);
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * $Id: pci.c,v 1.5 2003/05/20 20:59:31 dwmw2 Exp $
+ * $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $
*
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
struct pci_dev *dev;
};
+static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ map_word val;
+ val.x[0]= readb(map->base + map->translate(map, ofs));
+// printk("read8 : %08lx => %02x\n", ofs, val.x[0]);
+ return val;
+}
+
+#if 0
+static map_word mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ map_word val;
+ val.x[0] = readw(map->base + map->translate(map, ofs));
+// printk("read16: %08lx => %04x\n", ofs, val.x[0]);
+ return val;
+}
+#endif
+static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ map_word val;
+ val.x[0] = readl(map->base + map->translate(map, ofs));
+// printk("read32: %08lx => %08x\n", ofs, val.x[0]);
+ return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write8 : %08lx <= %02x\n", ofs, val.x[0]);
+ writeb(val.x[0], map->base + map->translate(map, ofs));
+}
+
+#if 0
+static void mtd_pci_write16(struct map_info *_map, map_word val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write16: %08lx <= %04x\n", ofs, val.x[0]);
+ writew(val.x[0], map->base + map->translate(map, ofs));
+}
+#endif
+static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write32: %08lx <= %08x\n", ofs, val.x[0]);
+ writel(val.x[0], map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+ .phys = NO_XIP,
+ .copy_from = mtd_pci_copyfrom,
+ .copy_to = mtd_pci_copyto,
+};
+
/*
* Intel IOP80310 Flash driver
*/
{
u32 win_base;
- map->map.buswidth = 1;
+ map->map.bankwidth = 1;
+ map->map.read = mtd_pci_read8,
+ map->map.write = mtd_pci_write8,
+
map->map.size = 0x00800000;
map->base = ioremap_nocache(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
if (!len || !base)
return -ENXIO;
- map->map.buswidth = 4;
+ map->map.bankwidth = 4;
+ map->map.read = mtd_pci_read32,
+ map->map.write = mtd_pci_write32,
map->map.size = len;
map->base = ioremap_nocache(base, len);
* Generic code follows.
*/
-static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- u8 val = readb(map->base + map->translate(map, ofs));
-// printk("read8 : %08lx => %02x\n", ofs, val);
- return val;
-}
-
-static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- u16 val = readw(map->base + map->translate(map, ofs));
-// printk("read16: %08lx => %04x\n", ofs, val);
- return val;
-}
-
-static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- u32 val = readl(map->base + map->translate(map, ofs));
-// printk("read32: %08lx => %08x\n", ofs, val);
- return val;
-}
-
-static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- memcpy_fromio(to, map->base + map->translate(map, from), len);
-}
-
-static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write8 : %08lx <= %02x\n", ofs, val);
- writeb(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write16: %08lx <= %04x\n", ofs, val);
- writew(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
-// printk("write32: %08lx <= %08x\n", ofs, val);
- writel(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
-{
- struct map_pci_info *map = (struct map_pci_info *)_map;
- memcpy_toio(map->base + map->translate(map, to), from, len);
-}
-
-static struct map_info mtd_pci_map = {
- .phys = NO_XIP,
- .read8 = mtd_pci_read8,
- .read16 = mtd_pci_read16,
- .read32 = mtd_pci_read32,
- .copy_from = mtd_pci_copyfrom,
- .write8 = mtd_pci_write8,
- .write16 = mtd_pci_write16,
- .write32 = mtd_pci_write32,
- .copy_to = mtd_pci_copyto,
-};
-
static int __devinit
mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
/*
- * $Id: pcmciamtd.c,v 1.48 2003/06/24 07:14:38 spse Exp $
+ * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $
*
* pcmciamtd.c - MTD driver for PCMCIA flash memory cards
*
#define DRIVER_DESC "PCMCIA Flash memory card driver"
-#define DRIVER_VERSION "$Revision: 1.48 $"
+#define DRIVER_VERSION "$Revision: 1.51 $"
/* Size of the PCMCIA address space: 26 bits = 64 MB */
#define MAX_PCMCIA_ADDR 0x4000000
/* Module parameters */
/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
-static int buswidth = 2;
+static int bankwidth = 2;
/* Speed of memory accesses, in ns */
static int mem_speed;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_PARM(buswidth, "i");
-MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(bankwidth, "i");
+MODULE_PARM_DESC(bankwidth, "Set bankwidth (1=8 bit, 2=16 bit, default=2)");
MODULE_PARM(mem_speed, "i");
MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
MODULE_PARM(force_size, "i");
}
-static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
{
caddr_t addr;
- u8 d;
+ map_word d = {{0}};
addr = remap_window(map, ofs);
if(!addr)
- return 0;
+ return d;
- d = readb(addr);
- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+ d.x[0] = readb(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d.x[0]);
return d;
}
-static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
{
caddr_t addr;
- u16 d;
+ map_word d = {{0}};
addr = remap_window(map, ofs);
if(!addr)
- return 0;
+ return d;
- d = readw(addr);
- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+ d.x[0] = readw(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d.x[0]);
return d;
}
}
-static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long adr)
{
caddr_t addr = remap_window(map, adr);
if(!addr)
return;
- DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d);
- writeb(d, addr);
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d.x[0]);
+ writeb(d.x[0], addr);
}
-static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long adr)
{
caddr_t addr = remap_window(map, adr);
if(!addr)
return;
- DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d);
- writew(d, addr);
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d.x[0]);
+ writew(d.x[0], addr);
}
#define DEV_REMOVED(x) (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
-static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
{
caddr_t win_base = (caddr_t)map->map_priv_2;
- u8 d;
+ map_word d = {{0}};
if(DEV_REMOVED(map))
- return 0;
+ return d;
- d = readb(win_base + ofs);
- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+ d.x[0] = readb(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d.x[0]);
return d;
}
-static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
{
caddr_t win_base = (caddr_t)map->map_priv_2;
- u16 d;
+ map_word d = {{0}};
if(DEV_REMOVED(map))
- return 0;
+ return d;
- d = readw(win_base + ofs);
- DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+ d.x[0] = readw(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d.x[0]);
return d;
}
case CISTPL_DEVICE_GEO: {
cistpl_device_geo_t *t = &parse.device_geo;
int i;
- dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+ dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
for(i = 0; i < t->ngeo; i++) {
- DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+ DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth);
DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
if(!dev->pcmcia_map.size)
dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
- if(!dev->pcmcia_map.buswidth)
- dev->pcmcia_map.buswidth = 2;
+ if(!dev->pcmcia_map.bankwidth)
+ dev->pcmcia_map.bankwidth = 2;
if(force_size) {
dev->pcmcia_map.size = force_size << 20;
DEBUG(2, "size forced to %dM", force_size);
}
- if(buswidth) {
- dev->pcmcia_map.buswidth = buswidth;
- DEBUG(2, "buswidth forced to %d", buswidth);
+ if(bankwidth) {
+ dev->pcmcia_map.bankwidth = bankwidth;
+ DEBUG(2, "bankwidth forced to %d", bankwidth);
}
dev->pcmcia_map.name = dev->mtd_name;
}
DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
- dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+ dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name);
}
card_settings(dev, link, &new_name);
dev->pcmcia_map.phys = NO_XIP;
- dev->pcmcia_map.read8 = pcmcia_read8_remap;
- dev->pcmcia_map.read16 = pcmcia_read16_remap;
dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
- dev->pcmcia_map.write8 = pcmcia_write8_remap;
- dev->pcmcia_map.write16 = pcmcia_write16_remap;
dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+ if (dev->pcmcia_map.bankwidth == 1) {
+ dev->pcmcia_map.read = pcmcia_read8_remap;
+ dev->pcmcia_map.write = pcmcia_write8_remap;
+ } else {
+ dev->pcmcia_map.read = pcmcia_read16_remap;
+ dev->pcmcia_map.write = pcmcia_write16_remap;
+ }
if(setvpp == 1)
dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
whole card - otherwise we try smaller windows until we succeed */
req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE;
- req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+ req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
req.Base = 0;
req.AccessSpeed = mem_speed;
link->win = (window_handle_t)link->handle;
DEBUG(1, "Using non remapping memory functions");
dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
- dev->pcmcia_map.read8 = pcmcia_read8;
- dev->pcmcia_map.read16 = pcmcia_read16;
+ if (dev->pcmcia_map.bankwidth == 1) {
+ dev->pcmcia_map.read = pcmcia_read8;
+ dev->pcmcia_map.write = pcmcia_write8;
+ } else {
+ dev->pcmcia_map.read = pcmcia_read16;
+ dev->pcmcia_map.write = pcmcia_write16;
+ }
dev->pcmcia_map.copy_from = pcmcia_copy_from;
- dev->pcmcia_map.write8 = pcmcia_write8;
- dev->pcmcia_map.write16 = pcmcia_write16;
dev->pcmcia_map.copy_to = pcmcia_copy_to;
}
{
info(DRIVER_DESC " " DRIVER_VERSION);
- if(buswidth && buswidth != 1 && buswidth != 2) {
- info("bad buswidth (%d), using default", buswidth);
- buswidth = 2;
+ if(bankwidth && bankwidth != 1 && bankwidth != 2) {
+ info("bad bankwidth (%d), using default", bankwidth);
+ bankwidth = 2;
}
if(force_size && (force_size < 1 || force_size > 64)) {
info("bad force_size (%d), using default", force_size);
/*
- * $Id: physmap.c,v 1.29 2003/05/29 09:24:10 dwmw2 Exp $
+ * $Id: physmap.c,v 1.33 2004/07/12 14:37:24 dwmw2 Exp $
*
* Normal mappings of chips in physical memory
+ *
+ * Copyright (C) 2003 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 031022 - [jsun] add run-time configure and partition setup
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/mtd/partitions.h>
-#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
-#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
-#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
-
static struct mtd_info *mymtd;
-
-struct map_info physmap_map = {
- .name = "Physically mapped flash",
- .size = WINDOW_SIZE,
- .buswidth = BUSWIDTH,
- .phys = WINDOW_ADDR,
-};
+struct map_info physmap_map = {.name = "phys_mapped_flash"};
#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition *mtd_parts;
static int mtd_parts_nb;
-static struct mtd_partition physmap_partitions[] = {
-#if 0
-/* Put your own partition definitions here */
- {
- .name = "bootROM",
- .size = 0x80000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "zImage",
- .size = 0x100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "ramdisk.gz",
- .size = 0x300000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "User FS",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-#endif
-};
+static int num_physmap_partitions;
+static struct mtd_partition *physmap_partitions;
-#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition))
-const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL};
+static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
+void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
+{
+ physmap_partitions=parts;
+ num_physmap_partitions=num_parts;
+}
#endif /* CONFIG_MTD_PARTITIONS */
-int __init init_physmap(void)
+static int __init init_physmap(void)
{
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
const char **type;
- printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
- physmap_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+ printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
+ physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size);
if (!physmap_map.virt) {
printk("Failed to ioremap\n");
return 0;
}
- if (NUM_PARTITIONS != 0)
+ if (num_physmap_partitions != 0)
{
printk(KERN_NOTICE
"Using physmap partition definition\n");
- add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+ add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
return 0;
}
if (mtd_parts_nb) {
del_mtd_partitions(mymtd);
kfree(mtd_parts);
- } else if (NUM_PARTITIONS) {
+ } else if (num_physmap_partitions) {
del_mtd_partitions(mymtd);
} else {
del_mtd_device(mymtd);
*
* This code is GPL
*
- * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: pnc2000.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $
*/
#include <linux/module.h>
struct map_info pnc_map = {
.name = "PNC-2000",
.size = WINDOW_SIZE,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = 0xFFFFFFFF,
.virt = WINDOW_ADDR,
};
/*
- * $Id: redwood.c,v 1.6 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: redwood.c,v 1.8 2004/07/12 21:59:44 dwmw2 Exp $
*
* drivers/mtd/maps/redwood.c
*
* FLASH map for the IBM Redwood 4/5/6 boards.
*
+ * Author: MontaVista Software, Inc. <source@mvista.com>
*
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2003 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
static struct mtd_partition redwood_flash_partitions[] = {
{
- .name = "Redwood kernel",
+ .name = "Redwood filesystem",
.offset = RW_PART0_OF,
.size = RW_PART0_SZ
},
.mask_flags = MTD_WRITEABLE /* force read-only */
},
{
- .name = "Redwood filesystem",
+ .name = "Redwood kernel",
.offset = RW_PART2_OF,
.size = RW_PART2_SZ
},
struct map_info redwood_flash_map = {
.name = "IBM Redwood",
.size = WINDOW_SIZE,
- .buswidth = 2,
+ .bankwidth = 2,
.phys = WINDOW_ADDR,
};
module_exit(cleanup_redwood_flash);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Armin Kuster <akuster@mvista.com>");
+MODULE_AUTHOR("MontaVista Software <source@mvista.com>");
MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
/*
- * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: rpxlite.c,v 1.20 2004/07/12 21:59:44 dwmw2 Exp $
*
* Handle mapping of the flash on the RPX Lite and CLLF boards
*/
static struct map_info rpxlite_map = {
.name = "RPX",
.size = WINDOW_SIZE,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = WINDOW_ADDR,
};
*
* (C) 2000 Nicolas Pitre <nico@cam.org>
*
- * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $
+ * $Id: sa1100-flash.c,v 1.39 2004/07/12 21:59:44 dwmw2 Exp $
*/
#include <linux/config.h>
sa[i].map->virt = (unsigned long)sa[i].vbase;
sa[i].map->phys = sa[i].base;
sa[i].map->set_vpp = sa[i].set_vpp;
- sa[i].map->buswidth = sa[i].width;
+ sa[i].map->bankwidth = sa[i].width;
sa[i].map->size = sa[i].size;
simple_map_init(sa[i].map);
return;
}
- sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
+ sa1100_probe_map.bankwidth = msc & MSC_RBW ? 2 : 4;
sa1100_probe_map.size = SZ_1M;
sa1100_probe_map.phys = phys;
sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
return nr;
/*
- * Retrieve the buswidth from the MSC registers.
+ * Retrieve the bankwidth from the MSC registers.
* We currently only implement CS0 and CS1 here.
*/
for (i = 0; i < nr; i++) {
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $
+ $Id: sbc_gxx.c,v 1.29 2004/07/12 22:38:29 dwmw2 Exp $
The SBC-MediaGX / SBC-GXx has up to 16 MiB of
Intel StrataFlash (28F320/28F640) in x8 mode.
}
-static __u8 sbc_gxx_read8(struct map_info *map, unsigned long ofs)
+static map_word sbc_gxx_read8(struct map_info *map, unsigned long ofs)
{
- __u8 ret;
+ map_word ret;
spin_lock(&sbc_gxx_spin);
sbc_gxx_page(map, ofs);
- ret = readb(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
- return ret;
-}
-
-static __u16 sbc_gxx_read16(struct map_info *map, unsigned long ofs)
-{
- __u16 ret;
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, ofs);
- ret = readw(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
- return ret;
-}
-
-static __u32 sbc_gxx_read32(struct map_info *map, unsigned long ofs)
-{
- __u32 ret;
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, ofs);
- ret = readl(iomapadr + (ofs & WINDOW_MASK));
+ ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
spin_unlock(&sbc_gxx_spin);
return ret;
}
}
}
-static void sbc_gxx_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, adr);
- writeb(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
-}
-
-static void sbc_gxx_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
- spin_lock(&sbc_gxx_spin);
- sbc_gxx_page(map, adr);
- writew(d, iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&sbc_gxx_spin);
-}
-
-static void sbc_gxx_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&sbc_gxx_spin);
sbc_gxx_page(map, adr);
- writel(d, iomapadr + (adr & WINDOW_MASK));
+ writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
spin_unlock(&sbc_gxx_spin);
}
.size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
of flash so the cfi probe routines find all
the chips */
- .buswidth = 1,
- .read8 = sbc_gxx_read8,
- .read16 = sbc_gxx_read16,
- .read32 = sbc_gxx_read32,
+ .bankwidth = 1,
+ .read = sbc_gxx_read8,
.copy_from = sbc_gxx_copy_from,
- .write8 = sbc_gxx_write8,
- .write16 = sbc_gxx_write16,
- .write32 = sbc_gxx_write32,
+ .write = sbc_gxx_write8,
.copy_to = sbc_gxx_copy_to
};
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: sc520cdp.c,v 1.16 2004/07/12 21:59:45 dwmw2 Exp $
*
*
* The SC520CDP is an evaluation board for the Elan SC520 processor available
{
.name = "SC520CDP Flash Bank #0",
.size = WINDOW_SIZE_0,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = WINDOW_ADDR_0
},
{
.name = "SC520CDP Flash Bank #1",
.size = WINDOW_SIZE_1,
- .buswidth = 4,
+ .bankwidth = 4,
.phys = WINDOW_ADDR_1
},
{
.name = "SC520CDP DIL Flash",
.size = WINDOW_SIZE_2,
- .buswidth = 1,
+ .bankwidth = 1,
.phys = WINDOW_ADDR_2
},
};
/*
* MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.8 2004/07/12 21:59:45 dwmw2 Exp $
* Copyright (C) 2002 Sun Microsystems, Inc.
* Tim Hockin <thockin@sun.com>
*
struct map_info scb2_map = {
.name = "SCB2 BIOS Flash",
.size = 0,
- .buswidth = 1,
+ .bankwidth = 1,
};
static int region_fail;
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
- $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $
+ $Id: scx200_docflash.c,v 1.6 2004/07/12 21:59:45 dwmw2 Exp $
National Semiconductor SCx200 flash mapped with DOCCS
*/
scx200_docflash_map.size = size;
if (width == 8)
- scx200_docflash_map.buswidth = 1;
+ scx200_docflash_map.bankwidth = 1;
else
- scx200_docflash_map.buswidth = 2;
+ scx200_docflash_map.bankwidth = 2;
simple_map_init(&scx200_docflash_map);
/*
- * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: solutionengine.c,v 1.13 2004/07/12 21:59:45 dwmw2 Exp $
*
* Flash and EPROM on Hitachi Solution Engine and similar boards.
*
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
-
+#include <linux/errno.h>
static struct mtd_info *flash_mtd;
static struct mtd_info *eprom_mtd;
struct map_info soleng_eprom_map = {
.name = "Solution Engine EPROM",
.size = 0x400000,
- .buswidth = 4,
+ .bankwidth = 4,
};
struct map_info soleng_flash_map = {
.name = "Solution Engine FLASH",
.size = 0x400000,
- .buswidth = 4,
+ .bankwidth = 4,
};
static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $
+/* $Id: sun_uflash.c,v 1.9 2004/07/12 21:59:45 dwmw2 Exp $
*
* sun_uflash - Driver implementation for user-programmable flash
* present on many Sun Microsystems SME boardsets.
struct map_info uflash_map_templ = {
.name = "SUNW,???-????",
.size = UFLASH_WINDOW_SIZE,
- .buswidth = UFLASH_BUSWIDTH,
+ .bankwidth = UFLASH_BUSWIDTH,
};
int uflash_devinit(struct linux_ebus_device* edev)
* Handle mapping of the flash memory access routines
* on TQM8xxL based devices.
*
- * $Id: tqm8xxl.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.11 2004/07/12 21:59:45 dwmw2 Exp $
*
* based on rpxlite.c
*
sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
map_banks[idx]->size = flash_size;
- map_banks[idx]->buswidth = 4;
+ map_banks[idx]->bankwidth = 4;
simple_map_init(map_banks[idx]);
* tsunami_flash.c
*
* flash chip on alpha ds10...
- * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $
+ * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $
*/
#include <asm/io.h>
#include <asm/core_tsunami.h>
#define FLASH_DISABLE_BYTE 0x00
#define MAX_TIG_FLASH_SIZE (12*1024*1024)
-static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset)
+static inline map_word tsunami_flash_read8(struct map_info *map, unsigned long offset)
{
- return tsunami_tig_readb(offset);
+ map_word val;
+ val.x[0] = tsunami_tig_readb(offset);
+ return val;
}
-static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset)
+static void tsunami_flash_write8(struct map_info *map, map_word value, unsigned long offset)
{
- tsunami_tig_writeb(value, offset);
+ tsunami_tig_writeb(value.x[0], offset);
}
static void tsunami_flash_copy_from(
.name = "flash chip on the Tsunami TIG bus",
.size = MAX_TIG_FLASH_SIZE,
.phys = NO_XIP;
- .buswidth = 1,
- .read8 = tsunami_flash_read8,
+ .bankwidth = 1,
+ .read = tsunami_flash_read8,
.copy_from = tsunami_flash_copy_from,
- .write8 = tsunami_flash_write8,
+ .write = tsunami_flash_write8,
.copy_to = tsunami_flash_copy_to,
};
static int __init init_tsunami_flash(void)
{
- static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+ static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
char **type;
tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
*
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
*
- * $Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $
+ * $Id: uclinux.c,v 1.7 2004/07/12 21:59:45 dwmw2 Exp $
*/
/****************************************************************************/
mapp = &uclinux_ram_map;
mapp->phys = (unsigned long) &_ebss;
mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
- mapp->buswidth = 4;
+ mapp->bankwidth = 4;
printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
(int) mapp->map_priv_2, (int) mapp->size);
-// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $
+// $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $
/* ######################################################################
Tempustech VMAX SBC301 MTD Driver.
__vmax301_page(map, page);
}
-static __u8 vmax301_read8(struct map_info *map, unsigned long ofs)
+static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
{
- __u8 ret;
+ map_word ret;
spin_lock(&vmax301_spin);
vmax301_page(map, ofs);
- ret = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
- return ret;
-}
-
-static __u16 vmax301_read16(struct map_info *map, unsigned long ofs)
-{
- __u16 ret;
- spin_lock(&vmax301_spin);
- vmax301_page(map, ofs);
- ret = readw(map->map_priv_2 + (ofs & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
- return ret;
-}
-
-static __u32 vmax301_read32(struct map_info *map, unsigned long ofs)
-{
- __u32 ret;
- spin_lock(&vmax301_spin);
- vmax301_page(map, ofs);
- ret = readl(map->map_priv_2 + (ofs & WINDOW_MASK));
+ ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
spin_unlock(&vmax301_spin);
return ret;
}
}
}
-static void vmax301_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
- spin_lock(&vmax301_spin);
- vmax301_page(map, adr);
- writeb(d, map->map_priv_2 + (adr & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
- spin_lock(&vmax301_spin);
- vmax301_page(map, adr);
- writew(d, map->map_priv_2 + (adr & WINDOW_MASK));
- spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
{
spin_lock(&vmax301_spin);
vmax301_page(map, adr);
- writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
+ writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
spin_unlock(&vmax301_spin);
}
.name = "VMAX301 Internal Flash",
.phys = NO_XIP,
.size = 3*2*1024*1024,
- .buswidth = 1,
- .read8 = vmax301_read8,
- .read16 = vmax301_read16,
- .read32 = vmax301_read32,
+ .bankwidth = 1,
+ .read = vmax301_read8,
.copy_from = vmax301_copy_from,
- .write8 = vmax301_write8,
- .write16 = vmax301_write16,
- .write32 = vmax301_write32,
+ .write = vmax301_write8,
.copy_to = vmax301_copy_to,
.map_priv_1 = WINDOW_START + WINDOW_LENGTH,
.map_priv_2 = 0xFFFFFFFF
.name = "VMAX301 Socket",
.phys = NO_XIP,
.size = 0,
- .buswidth = 1,
- .read8 = vmax301_read8,
- .read16 = vmax301_read16,
- .read32 = vmax301_read32,
+ .bankwidth = 1,
+ .read = vmax301_read8,
.copy_from = vmax301_copy_from,
- .write8 = vmax301_write8,
- .write16 = vmax301_write16,
- .write32 = vmax301_write32,
+ .write = vmax301_write8,
.copy_to = vmax301_copy_to,
.map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
.map_priv_2 = 0xFFFFFFFF
/*
- * $Id: wr_sbc82xx_flash.c,v 1.1 2004/06/07 10:21:32 dwmw2 Exp $
+ * $Id: wr_sbc82xx_flash.c,v 1.5 2004/07/15 14:52:02 dwmw2 Exp $
*
* Map for flash chips on Wind River PowerQUICC II SBC82xx board.
*
static struct mtd_partition bigflash_parts[] = {
{
.name = "bootloader",
- .size = 0x80000,
+ .size = 0x00100000,
.offset = 0,
}, {
.name = "file system",
- .size = MTDPART_SIZ_FULL,
+ .size = 0x01f00000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "boot config",
+ .size = 0x00100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "space",
+ .size = 0x01f00000,
.offset = MTDPART_OFS_APPEND,
}
};
static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
+#define init_sbc82xx_one_flash(map, br, or) \
+do { \
+ (map).phys = (br & 1) ? (br & 0xffff8000) : 0; \
+ (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0; \
+ switch (br & 0x00001800) { \
+ case 0x00000000: \
+ case 0x00000800: (map).bankwidth = 1; break; \
+ case 0x00001000: (map).bankwidth = 2; break; \
+ case 0x00001800: (map).bankwidth = 4; break; \
+ } \
+} while (0);
+
int __init init_sbc82xx_flash(void)
{
- volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
+ volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
int bigflash;
int i;
- /* First, register the boot flash, whichever we're booting from */
- if ((mc->memc_br0 & 0x00001800) == 0x00001800) {
- bigflash = 0;
- } else if ((mc->memc_br0 & 0x00001800) == 0x00000800) {
- bigflash = 1;
- } else {
- printk(KERN_WARNING "Bus Controller register BR0 is %08x. Cannot determine flash configuration\n", mc->memc_br0);
- return 1;
- }
+#ifdef CONFIG_SBC8560
+ mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
+#else
+ mc = &cpm2_immr->im_memctl;
+#endif
- /* Set parameters for the big flash chip (CS6 or CS0) */
- sbc82xx_flash_map[bigflash].buswidth = 4;
- sbc82xx_flash_map[bigflash].size = 0x4000000;
-
- /* Set parameters for the small flash chip (CS0 or CS6) */
- sbc82xx_flash_map[!bigflash].buswidth = 1;
- sbc82xx_flash_map[!bigflash].size = 0x200000;
+ bigflash = 1;
+ if ((mc->memc_br0 & 0x00001800) == 0x00001800)
+ bigflash = 0;
- /* Set parameters for the user flash chip (CS1) */
- sbc82xx_flash_map[2].buswidth = 4;
- sbc82xx_flash_map[2].size = 0x4000000;
+ init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
+ init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
+ init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
- sbc82xx_flash_map[0].phys = mc->memc_br0 & 0xffff8000;
- sbc82xx_flash_map[1].phys = mc->memc_br6 & 0xffff8000;
- sbc82xx_flash_map[2].phys = mc->memc_br1 & 0xffff8000;
+#ifdef CONFIG_SBC8560
+ iounmap((void *) mc);
+#endif
for (i=0; i<3; i++) {
int8_t flashcs[3] = { 0, 6, 1 };
int nr_parts;
printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
- sbc82xx_flash_map[i].name, sbc82xx_flash_map[i].size >> 20, flashcs[i]);
+ sbc82xx_flash_map[i].name,
+ (sbc82xx_flash_map[i].size >> 20),
+ flashcs[i]);
if (!sbc82xx_flash_map[i].phys) {
/* We know it can't be at zero. */
printk("): disabled by bootloader.\n");
/*
- * $Id: mtd_blkdevs.c,v 1.16 2003/06/23 13:34:43 dwmw2 Exp $
+ * $Id: mtd_blkdevs.c,v 1.22 2004/07/12 12:35:28 dwmw2 Exp $
*
* (C) 2003 David Woodhouse <dwmw2@infradead.org>
*
snprintf(gd->devfs_name, sizeof(gd->devfs_name),
"%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
- set_capacity(gd, new->size);
+ /* 2.5 has capacity in units of 512 bytes while still
+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
+ set_capacity(gd, (new->size * new->blksize) >> 9);
+
gd->private_data = new;
new->blkcore_priv = gd;
gd->queue = tr->blkcore_priv->rq;
/*
* Direct MTD block device access
*
- * $Id: mtdblock.c,v 1.63 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.64 2003/10/04 17:14:14 dwmw2 Exp $
*
* (C) 2000-2003 Nicolas Pitre <nico@cam.org>
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
/*
- * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.62 2004/07/14 13:20:42 dwmw2 Exp $
*
* Character-device access to raw MTD devices.
*
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
-static void mtd_notify_add(struct mtd_info* mtd);
-static void mtd_notify_remove(struct mtd_info* mtd);
+
+static void mtd_notify_add(struct mtd_info* mtd)
+{
+ if (!mtd)
+ return;
+
+ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+ S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
+
+ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+ S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
+}
+
+static void mtd_notify_remove(struct mtd_info* mtd)
+{
+ if (!mtd)
+ return;
+ devfs_remove("mtd/%d", mtd->index);
+ devfs_remove("mtd/%dro", mtd->index);
+}
static struct mtd_notifier notifier = {
.add = mtd_notify_add,
.remove = mtd_notify_remove,
};
+static inline void mtdchar_devfs_init(void)
+{
+ devfs_mk_dir("mtd");
+ register_mtd_user(¬ifier);
+}
+
+static inline void mtdchar_devfs_exit(void)
+{
+ unregister_mtd_user(¬ifier);
+ devfs_remove("mtd");
+}
+#else /* !DEVFS */
+#define mtdchar_devfs_init() do { } while(0)
+#define mtdchar_devfs_exit() do { } while(0)
#endif
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
memset (erase,0,sizeof(struct erase_info));
if (copy_from_user(&erase->addr, argp,
- 2 * sizeof(u_long))) {
+ sizeof(struct erase_info_user))) {
kfree(erase);
return -EFAULT;
}
ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
- if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+ if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t)))
ret = -EFAULT;
kfree(databuf);
ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
- if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+ if (put_user(retlen, (uint32_t __user *)argp))
ret = -EFAULT;
else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
ret = -EFAULT;
case MEMLOCK:
{
- unsigned long adrs[2];
+ struct erase_info_user info;
- if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+ if (copy_from_user(&info, argp, sizeof(info)))
return -EFAULT;
if (!mtd->lock)
ret = -EOPNOTSUPP;
else
- ret = mtd->lock(mtd, adrs[0], adrs[1]);
+ ret = mtd->lock(mtd, info.start, info.length);
break;
}
case MEMUNLOCK:
{
- unsigned long adrs[2];
+ struct erase_info_user info;
- if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+ if (copy_from_user(&info, argp, sizeof(info)))
return -EFAULT;
if (!mtd->unlock)
ret = -EOPNOTSUPP;
else
- ret = mtd->unlock(mtd, adrs[0], adrs[1]);
+ ret = mtd->unlock(mtd, info.start, info.length);
break;
}
return -EFAULT;
break;
}
+
+ case MEMGETOOBSEL:
+ {
+ if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo)))
+ return -EFAULT;
+ break;
+ }
+
+ case MEMGETBADBLOCK:
+ {
+ loff_t offs;
+ if (copy_from_user(&offs, argp, sizeof(loff_t)))
+ return -EFAULT;
+ if (!mtd->block_isbad)
+ ret = -EOPNOTSUPP;
+ else
+ return mtd->block_isbad(mtd, offs);
+ break;
+ }
+
+ case MEMSETBADBLOCK:
+ {
+ loff_t offs;
+
+ if (copy_from_user(&offs, argp, sizeof(loff_t)))
+ return -EFAULT;
+ if (!mtd->block_markbad)
+ ret = -EOPNOTSUPP;
+ else
+ return mtd->block_markbad(mtd, offs);
+ break;
+ }
+
default:
DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
ret = -ENOTTY;
.release = mtd_close,
};
-
-#ifdef CONFIG_DEVFS_FS
-/* Notification that a new device has been added. Create the devfs entry for
- * it. */
-
-static void mtd_notify_add(struct mtd_info* mtd)
-{
- if (!mtd)
- return;
- devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
- S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
- devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
- S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%dro", mtd->index);
-}
-
-static void mtd_notify_remove(struct mtd_info* mtd)
-{
- if (!mtd)
- return;
- devfs_remove("mtd/%d", mtd->index);
- devfs_remove("mtd/%dro", mtd->index);
-}
-#endif
-
static int __init init_mtdchar(void)
{
if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
return -EAGAIN;
}
-#ifdef CONFIG_DEVFS_FS
- devfs_mk_dir("mtd");
-
- register_mtd_user(¬ifier);
-#endif
+ mtdchar_devfs_init();
return 0;
}
static void __exit cleanup_mtdchar(void)
{
-#ifdef CONFIG_DEVFS_FS
- unregister_mtd_user(¬ifier);
- devfs_remove("mtd");
-#endif
+ mtdchar_devfs_exit();
unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
}
*
* This code is GPL
*
- * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
*/
#include <linux/module.h>
struct mtd_concat *concat = CONCAT(mtd);
struct mtd_info *subdev;
int i, err;
- u_int32_t length;
+ u_int32_t length, offset = 0;
struct erase_info *erase;
if (!(mtd->flags & MTD_WRITEABLE))
return -EINVAL;
}
+ instr->fail_addr = 0xffffffff;
+
/* make a local copy of instr to avoid modifying the caller's struct */
erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
*/
for (i = 0; i < concat->num_subdev; i++) {
subdev = concat->subdev[i];
- if (subdev->size <= erase->addr)
+ if (subdev->size <= erase->addr) {
erase->addr -= subdev->size;
- else
+ offset += subdev->size;
+ } else {
break;
+ }
}
/* must never happen since size limit has been verified above */
* block alignment has been checked above */
if (err == -EINVAL)
BUG();
+ if (erase->fail_addr != 0xffffffff)
+ instr->fail_addr = erase->fail_addr + offset;
break;
}
/*
* current subdevice, i.e. at offset zero.
*/
erase->addr = 0;
+ offset += subdev->size;
}
+ instr->state = erase->state;
kfree(erase);
if (err)
return err;
- instr->state = MTD_ERASE_DONE;
if (instr->callback)
instr->callback(instr);
return 0;
/*
- * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.42 2004/07/13 10:21:13 dwmw2 Exp $
*
* Core registration and callback routines for MTD
* drivers and users.
/* Support for /proc/mtd */
#ifdef CONFIG_PROC_FS
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
static struct proc_dir_entry *proc_mtd;
-#endif
static inline int mtd_proc_info (char *buf, int i)
{
this->erasesize, this->name);
}
-static int mtd_read_proc ( char *page, char **start, off_t off,int count
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-#else
- ,int unused
-#endif
- )
+static int mtd_read_proc (char *page, char **start, off_t off, int count,
+ int *eof, void *data_unused)
{
int len, l, i;
off_t begin = 0;
}
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
*eof = 1;
-#endif
done:
up(&mtd_table_mutex);
return ((count < begin+len-off) ? count : begin+len-off);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
-struct proc_dir_entry mtd_proc_entry = {
- 0, /* low_ino: the inode -- dynamic */
- 3, "mtd", /* len of name and name */
- S_IFREG | S_IRUGO, /* mode */
- 1, 0, 0, /* nlinks, owner, group */
- 0, NULL, /* size - unused; operations -- use default */
- &mtd_read_proc, /* function used to read data */
- /* nothing more */
- };
-#endif
-
#endif /* CONFIG_PROC_FS */
/*====================================================================*/
int __init init_mtd(void)
{
#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
- proc_mtd->read_proc = mtd_read_proc;
-#else
- proc_register_dynamic(&proc_root,&mtd_proc_entry);
-#endif
-#endif
-
-#if LINUX_VERSION_CODE < 0x20212
- init_mtd_devices();
+ proc_mtd->read_proc = mtd_read_proc;
#endif
#ifdef CONFIG_PM
#endif
#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
if (proc_mtd)
- remove_proc_entry( "mtd", NULL);
-#else
- proc_unregister(&proc_root,mtd_proc_entry.low_ino);
-#endif
+ remove_proc_entry( "mtd", NULL);
#endif
}
*
* This code is GPL
*
- * $Id: mtdpart.c,v 1.41 2003/06/18 14:53:02 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.46 2004/07/12 13:28:07 dwmw2 Exp $
*
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
* added support for read_oob, write_oob
static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
{
struct mtd_part *part = PART(mtd);
+ int ret;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (instr->addr >= mtd->size)
return -EINVAL;
instr->addr += part->offset;
- return part->master->erase(part->master, instr);
+ ret = part->master->erase(part->master, instr);
+ if (instr->fail_addr != 0xffffffff)
+ instr->fail_addr -= part->offset;
+ return ret;
}
static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
part->master->resume(part->master);
}
+static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_part *part = PART(mtd);
+ if (ofs >= mtd->size)
+ return -EINVAL;
+ ofs += part->offset;
+ return part->master->block_isbad(part->master, ofs);
+}
+
+static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (ofs >= mtd->size)
+ return -EINVAL;
+ ofs += part->offset;
+ return part->master->block_markbad(part->master, ofs);
+}
+
/*
* This function unregisters and destroy all slave MTD objects which are
* attached to the given master MTD object.
*/
int add_mtd_partitions(struct mtd_info *master,
- struct mtd_partition *parts,
+ const struct mtd_partition *parts,
int nbparts)
{
struct mtd_part *slave;
slave->mtd.lock = part_lock;
if (master->unlock)
slave->mtd.unlock = part_unlock;
+ if (master->block_isbad)
+ slave->mtd.block_isbad = part_block_isbad;
+ if (master->block_markbad)
+ slave->mtd.block_markbad = part_block_markbad;
slave->mtd.erase = part_erase;
slave->master = master;
slave->offset = parts[i].offset;
parts[i].name);
}
+ /* copy oobinfo from master */
+ memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
+
if(parts[i].mtdp)
{ /* store the object pointer (caller may or may not register it */
*parts[i].mtdp = &slave->mtd;
# drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.4 2003/05/28 10:04:23 dwmw2 Exp $
+# $Id: Kconfig,v 1.14 2004/07/13 00:14:35 dbrown Exp $
menu "NAND Flash Device Drivers"
depends on MTD!=n
depends on MTD
help
This enables support for accessing all type of NAND flash
- devices with an 8-bit data bus interface. For further information see
+ devices. For further information see
<http://www.linux-mtd.infradead.org/tech/nand.html>.
config MTD_NAND_VERIFY_WRITE
help
If you had to ask, you don't have one. Say 'N'.
+config MTD_NAND_TOTO
+ tristate "NAND Flash device on TOTO board"
+ depends on ARM && ARCH_OMAP && MTD_NAND
+ help
+ Support for NAND flash on Texas Instruments Toto platform.
+
config MTD_NAND_IDS
tristate
default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
-
-endmenu
+config MTD_NAND_TX4925NDFMC
+ tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
+ depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND
+ help
+ This enables the driver for the NAND flash device found on the
+ Toshiba RBTX4925 reference board, which is a SmartMediaCard.
+
+config MTD_NAND_TX4938NDFMC
+ tristate "NAND Flash device on Toshiba RBTX4938 reference board"
+ depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND
+ help
+ This enables the driver for the NAND flash device found on the
+ Toshiba RBTX4938 reference board.
+
+config MTD_NAND_AU1550
+ tristate "Au1550 NAND support"
+ depends on SOC_AU1550 && MTD_NAND
+ help
+ This enables the driver for the NAND flash controller on the
+ AMD/Alchemy 1550 SOC.
+
+config MTD_NAND_PPCHAMELEONEVB
+ tristate "NAND Flash device on PPChameleonEVB board"
+ depends on PPCHAMELEONEVB && MTD_NAND
+ help
+ This enables the NAND flash driver on the PPChameleon EVB Board.
+
+config MTD_NAND_DISKONCHIP
+ tristate "DiskOnChip 2000 and Millennium (NAND reimplementation) (EXPERIMENTAL)"
+ depends on MTD_NAND && EXPERIMENTAL
+ help
+ This is a reimplementation of M-Systems DiskOnChip 2000 and
+ Millennium as a standard NAND device driver, as opposed to the
+ earlier self-contained MTD device drivers.
+ This should enable, among other things, proper JFFS2 operation on
+ these devices.
+
+config MTD_NAND_DISKONCHIP_BBTWRITE
+ bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
+ depends on MTD_NAND_DISKONCHIP
+ help
+ On DiskOnChip devices shipped with the INFTL filesystem (Millennium
+ and 2000 TSOP/Alon), Linux reserves some space at the end of the
+ device for the Bad Block Table (BBT). If you have existing INFTL
+ data on your device (created by non-Linux tools such as M-Systems'
+ DOS drivers), your data might overlap the area Linux wants to use for
+ the BBT. If this is a concern for you, leave this option disabled and
+ Linux will not write BBT data into this area.
+ The downside of leaving this option disabled is that if bad blocks
+ are detected by Linux, they will not be recorded in the BBT, which
+ could cause future problems.
+ Once you enable this option, new filesystems (INFTL or others, created
+ in Linux or other operating systems) will not use the reserved area.
+ The only reason not to enable this option is to prevent damage to
+ preexisting filesystems.
+ Even if you leave this disabled, you can enable BBT writes at module
+ load time (assuming you build diskonchip as a module) with the module
+ parameter "inftl_bbt_write=1".
+endmenu
#
# linux/drivers/nand/Makefile
#
-# $Id: Makefile.common,v 1.2 2003/05/28 11:38:54 dwmw2 Exp $
+# $Id: Makefile.common,v 1.9 2004/07/12 16:07:31 dwmw2 Exp $
-obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
-obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
-obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
-obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
-obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
+obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
+obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
+
+obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
+obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
+obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
+obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
+obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o
+obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o
+obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
+obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
+obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
+
+nand-objs = nand_base.o nand_bbt.o
* Derived from drivers/mtd/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
- * $Id: autcpu12.c,v 1.11 2003/06/04 17:04:09 gleixner Exp $
+ * $Id: autcpu12.c,v 1.19 2004/07/12 15:02:15 dwmw2 Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* Overview:
* This is a device driver for the NAND flash device found on the
* autronix autcpu12 board, which is a SmartMediaCard. It supports
- * 16MB, 32MB and 64MB cards.
+ * 16MiB, 32MiB and 64MiB cards.
*
*
* 02-12-2002 TG Cleanup of module params
/*
* Define partitions for flash devices
*/
-extern struct nand_oobinfo jffs2_oobinfo;
-
static struct mtd_partition partition_info16k[] = {
- { .name = "AUTCPU12 flash partition 1",
- .offset = 0,
- .size = 8 * SZ_1M },
- { .name = "AUTCPU12 flash partition 2",
- .offset = 8 * SZ_1M,
- .size = 8 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 1",
+ .offset = 0,
+ .size = 8 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 2",
+ .offset = 8 * SZ_1M,
+ .size = 8 * SZ_1M },
};
static struct mtd_partition partition_info32k[] = {
- { .name = "AUTCPU12 flash partition 1",
- .offset = 0,
- .size = 8 * SZ_1M },
- { .name = "AUTCPU12 flash partition 2",
- .offset = 8 * SZ_1M,
- .size = 24 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 1",
+ .offset = 0,
+ .size = 8 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 2",
+ .offset = 8 * SZ_1M,
+ .size = 24 * SZ_1M },
};
static struct mtd_partition partition_info64k[] = {
- { .name = "AUTCPU12 flash partition 1",
- .offset = 0,
- .size = 16 * SZ_1M },
- { .name = "AUTCPU12 flash partition 2",
- .offset = 16 * SZ_1M,
- .size = 48 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 1",
+ .offset = 0,
+ .size = 16 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 2",
+ .offset = 16 * SZ_1M,
+ .size = 48 * SZ_1M },
};
static struct mtd_partition partition_info128k[] = {
- { .name = "AUTCPU12 flash partition 1",
- .offset = 0,
- .size = 16 * SZ_1M },
- { .name = "AUTCPU12 flash partition 2",
- .offset = 16 * SZ_1M,
- .size = 112 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 1",
+ .offset = 0,
+ .size = 16 * SZ_1M },
+ { .name = "AUTCPU12 flash partition 2",
+ .offset = 16 * SZ_1M,
+ .size = 112 * SZ_1M },
};
#define NUM_PARTITIONS16K 2
/*
* hardware specific access to control-lines
*/
-void autcpu12_hwcontrol(int cmd)
+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
{
switch(cmd){
/*
* read device ready pin
*/
-int autcpu12_device_ready(void)
+int autcpu12_device_ready(struct mtd_info *mtd)
{
return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
}
+
/*
* Main initialization routine
*/
this->chip_delay = 20;
this->eccmode = NAND_ECC_SOFT;
+ /* Enable the following for a flash based bad block table */
+ /*
+ this->options = NAND_USE_FLASH_BBT;
+ */
+ this->options = NAND_USE_FLASH_BBT;
+
/* Scan to find existance of the device */
- if (nand_scan (autcpu12_mtd)) {
+ if (nand_scan (autcpu12_mtd, 1)) {
err = -ENXIO;
goto out_ior;
}
-
- /* Allocate memory for internal data buffer */
- this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
- if (!this->data_buf) {
- printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
- err = -ENOMEM;
- goto out_ior;
- }
-
+
/* Register the partitions */
switch(autcpu12_mtd->size){
case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
default: {
printk ("Unsupported SmartMedia device\n");
err = -ENXIO;
- goto out_buf;
+ goto out_ior;
}
}
goto out;
-out_buf:
- kfree (this->data_buf);
out_ior:
iounmap((void *)autcpu12_fio_base);
out_mtd:
#ifdef MODULE
static void __exit autcpu12_cleanup (void)
{
- struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
-
- /* Unregister partitions */
- del_mtd_partitions(autcpu12_mtd);
-
- /* Unregister the device */
- del_mtd_device (autcpu12_mtd);
-
- /* Free internal data buffers */
- kfree (this->data_buf);
+ /* Release resources, unregister device */
+ nand_release (autcpu12_mtd);
/* unmap physical adress */
iounmap((void *)autcpu12_fio_base);
-
+
/* Free the MTD device structure */
kfree (autcpu12_mtd);
}
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*
- * $Id: edb7312.c,v 1.5 2003/04/20 07:24:40 gleixner Exp $
+ * $Id: edb7312.c,v 1.8 2004/07/12 15:03:26 dwmw2 Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
/*
* hardware specific access to control-lines
*/
-static void ep7312_hwcontrol(int cmd)
+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
{
switch(cmd) {
/*
* read device ready pin
*/
-static int ep7312_device_ready(void)
+static int ep7312_device_ready(struct mtd_info *mtd)
{
return 1;
}
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
/*
* Main initialization routine
this->chip_delay = 15;
/* Scan to find existence of the device */
- if (nand_scan (ep7312_mtd)) {
+ if (nand_scan (ep7312_mtd, 1)) {
iounmap((void *)ep7312_fio_base);
kfree (ep7312_mtd);
return -ENXIO;
return -ENOMEM;
}
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts,
- "edb7312-nand");
+#ifdef CONFIG_PARTITIONS
+ ep7312_mtd->name = "edb7312-nand";
+ mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
+ &mtd_parts, 0);
if (mtd_parts_nb > 0)
- part_type = "command line";
+ part_type = "command line";
else
- mtd_parts_nb = 0;
+ mtd_parts_nb = 0;
#endif
- if (mtd_parts_nb == 0)
- {
+ if (mtd_parts_nb == 0) {
mtd_parts = partition_info;
mtd_parts_nb = NUM_PARTITIONS;
part_type = "static";
+++ /dev/null
-/*
- * drivers/mtd/nand.c
- *
- * Overview:
- * This is the generic MTD driver for NAND flash devices. It should be
- * capable of working with almost all NAND chips currently available.
- *
- * Additional technical information is available on
- * http://www.linux-mtd.infradead.org/tech/nand.html
- *
- * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- * 10-29-2001 Thomas Gleixner (tglx@linutronix.de)
- * - Changed nand_chip structure for controlline function to
- * support different hardware structures (Access to
- * controllines ALE,CLE,NCE via hardware specific function.
- * - exit out of "failed erase block" changed, to avoid
- * driver hangup
- * - init_waitqueue_head added in function nand_scan !!
- *
- * 01-30-2002 Thomas Gleixner (tglx@linutronix.de)
- * change in nand_writev to block invalid vecs entries
- *
- * 02-11-2002 Thomas Gleixner (tglx@linutronix.de)
- * - major rewrite to avoid duplicated code
- * common nand_write_page function
- * common get_chip function
- * - added oob_config structure for out of band layouts
- * - write_oob changed for partial programming
- * - read cache for faster access for subsequent reads
- * from the same page.
- * - support for different read/write address
- * - support for device ready/busy line
- * - read oob for more than one page enabled
- *
- * 02-27-2002 Thomas Gleixner (tglx@linutronix.de)
- * - command-delay can be programmed
- * - fixed exit from erase with callback-function enabled
- *
- * 03-21-2002 Thomas Gleixner (tglx@linutronix.de)
- * - DEBUG improvements provided by Elizabeth Clarke
- * (eclarke@aminocom.com)
- * - added zero check for this->chip_delay
- *
- * 04-03-2002 Thomas Gleixner (tglx@linutronix.de)
- * - added added hw-driver supplied command and wait functions
- * - changed blocking for erase (erase suspend enabled)
- * - check pointers before accessing flash provided by
- * John Hall (john.hall@optionexist.co.uk)
- *
- * 04-09-2002 Thomas Gleixner (tglx@linutronix.de)
- * - nand_wait repaired
- *
- * 04-28-2002 Thomas Gleixner (tglx@linutronix.de)
- * - OOB config defines moved to nand.h
- *
- * 08-01-2002 Thomas Gleixner (tglx@linutronix.de)
- * - changed my mailaddress, added pointer to tech/nand.html
- *
- * 08-07-2002 Thomas Gleixner (tglx@linutronix.de)
- * forced bad block location to byte 5 of OOB, even if
- * CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent
- * erase /dev/mtdX from erasing bad blocks and destroying
- * bad block info
- *
- * 08-10-2002 Thomas Gleixner (tglx@linutronix.de)
- * Fixed writing tail of data. Thanks to Alice Hennessy
- * <ahennessy@mvista.com>.
- *
- * 08-10-2002 Thomas Gleixner (tglx@linutronix.de)
- * nand_read_ecc and nand_write_page restructured to support
- * hardware ECC. Thanks to Steven Hein (ssh@sgi.com)
- * for basic implementation and suggestions.
- * 3 new pointers in nand_chip structure:
- * calculate_ecc, correct_data, enabled_hwecc
- * forcing all hw-drivers to support page cache
- * eccvalid_pos is now mandatory
- *
- * 08-17-2002 tglx: fixed signed/unsigned missmatch in write.c
- * Thanks to Ken Offer <koffer@arlut.utexas.edu>
- *
- * 08-29-2002 tglx: use buffered read/write only for non pagealigned
- * access, speed up the aligned path by using the fs-buffer
- * reset chip removed from nand_select(), implicit done
- * only, when erase is interrupted
- * waitfuntion use yield, instead of schedule_timeout
- * support for 6byte/512byte hardware ECC
- * read_ecc, write_ecc extended for different oob-layout
- * selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB,
- * NAND_YAFFS_OOB. fs-driver gives one of these constants
- * to select the oob-layout fitting the filesystem.
- * oobdata can be read together with the raw data, when
- * the fs-driver supplies a big enough buffer.
- * size = 12 * number of pages to read (256B pagesize)
- * 24 * number of pages to read (512B pagesize)
- * the buffer contains 8/16 byte oobdata and 4/8 byte
- * returncode from calculate_ecc
- * oobdata can be given from filesystem to program them
- * in one go together with the raw data. ECC codes are
- * filled in at the place selected by oobsel.
- *
- * 09-04-2002 tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk))
- *
- * 11-11-2002 tglx: fixed debug output in nand_write_page
- * (John Hall (john.hall@optionexist.co.uk))
- *
- * 11-25-2002 tglx: Moved device ID/ manufacturer ID from nand_ids.h
- * Splitted device ID and manufacturer ID table.
- * Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for
- * mtd->read / mtd->write and is controllable by the fs driver
- * for mtd->read_ecc / mtd->write_ecc
- * some minor cleanups
- *
- * 12-05-2002 tglx: Dave Ellis (DGE@sixnetio) provided the fix for
- * WRITE_VERIFY long time ago. Thanks for remembering me.
- *
- * 02-14-2003 tglx: Reject non page aligned writes
- * Fixed ecc select in nand_write_page to match semantics.
- *
- * 02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector
- *
- * 02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to
- + a structure, which will be supplied by a filesystem driver
- * If NULL is given, then the defaults (none or defaults
- * supplied by ioctl (MEMSETOOBSEL) are used.
- * For partitions the partition defaults are used (mtdpart.c)
- *
- * 06-04-2003 tglx: fix compile errors and fix write verify problem for
- * some chips, which need either a delay between the readback
- * and the next write command or have the CE removed. The
- * CE disable/enable is much faster than a 20us delay and
- * it should work on all available chips.
- *
- * $Id: nand.c,v 1.46 2003/06/04 17:10:36 gleixner Exp $
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-/*
- * Macros for low-level register control
- */
-#define nand_select() this->hwcontrol(NAND_CTL_SETNCE);
-#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
-
-/*
- * NAND low-level MTD interface functions
- */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
-static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
-static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t * retlen);
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
- unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
-static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
-static void nand_sync (struct mtd_info *mtd);
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel);
-
-
-/*
- * Send command to NAND device
- */
-static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
- register struct nand_chip *this = mtd->priv;
- register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
-
- /* Begin command latch cycle */
- this->hwcontrol (NAND_CTL_SETCLE);
- /*
- * Write out the command to the device.
- */
- if (command != NAND_CMD_SEQIN)
- writeb (command, NAND_IO_ADDR);
- else {
- if (mtd->oobblock == 256 && column >= 256) {
- column -= 256;
- writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
- } else if (mtd->oobblock == 512 && column >= 256) {
- if (column < 512) {
- column -= 256;
- writeb (NAND_CMD_READ1, NAND_IO_ADDR);
- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
- } else {
- column -= 512;
- writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- } else {
- writeb (NAND_CMD_READ0, NAND_IO_ADDR);
- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
- }
- }
-
- /* Set ALE and clear CLE to start address cycle */
- this->hwcontrol (NAND_CTL_CLRCLE);
-
- if (column != -1 || page_addr != -1) {
- this->hwcontrol (NAND_CTL_SETALE);
-
- /* Serially input address */
- if (column != -1)
- writeb (column, NAND_IO_ADDR);
- if (page_addr != -1) {
- writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
- writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
- /* One more address cycle for higher density devices */
- if (mtd->size & 0x0c000000)
- writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
- }
- /* Latch in address */
- this->hwcontrol (NAND_CTL_CLRALE);
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
- this->hwcontrol (NAND_CTL_SETCLE);
- writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
- this->hwcontrol (NAND_CTL_CLRCLE);
- while ( !(readb (this->IO_ADDR_R) & 0x40));
- return;
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
- }
-
- /* wait until command is processed */
- while (!this->dev_ready());
-}
-
-/*
- * Get chip for selected access
- */
-static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
-{
-
- DECLARE_WAITQUEUE (wait, current);
-
- /*
- * Grab the lock and see if the device is available
- * For erasing, we keep the spinlock until the
- * erase command is written.
- */
-retry:
- spin_lock_bh (&this->chip_lock);
-
- if (this->state == FL_READY) {
- this->state = new_state;
- if (new_state != FL_ERASING)
- spin_unlock_bh (&this->chip_lock);
- return;
- }
-
- if (this->state == FL_ERASING) {
- if (new_state != FL_ERASING) {
- this->state = new_state;
- spin_unlock_bh (&this->chip_lock);
- nand_select (); /* select in any case */
- this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
- return;
- }
- }
-
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule ();
- remove_wait_queue (&this->wq, &wait);
- goto retry;
-}
-
-/*
- * Wait for command done. This applies to erase and program only
- * Erase can take up to 400ms and program up to 20ms according to
- * general NAND and SmartMedia specs
- *
-*/
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
-{
-
- unsigned long timeo = jiffies;
- int status;
-
- if (state == FL_ERASING)
- timeo += (HZ * 400) / 1000;
- else
- timeo += (HZ * 20) / 1000;
-
- spin_lock_bh (&this->chip_lock);
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-
- while (time_before(jiffies, timeo)) {
- /* Check, if we were interrupted */
- if (this->state != state) {
- spin_unlock_bh (&this->chip_lock);
- return 0;
- }
- if (this->dev_ready) {
- if (this->dev_ready ())
- break;
- }
- if (readb (this->IO_ADDR_R) & 0x40)
- break;
-
- spin_unlock_bh (&this->chip_lock);
- yield ();
- spin_lock_bh (&this->chip_lock);
- }
- status = (int) readb (this->IO_ADDR_R);
- spin_unlock_bh (&this->chip_lock);
-
- return status;
-}
-
-/*
- * Nand_page_program function is used for write and writev !
- * This function will always program a full page of data
- * If you call it with a non page aligned buffer, you're lost :)
- */
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel)
-{
- int i, status;
- u_char ecc_code[6], *oob_data;
- int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
- int *oob_config = oobsel->eccpos;
-
- /* pad oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf) {
- oob_data = &this->data_buf[mtd->oobblock];
- for (i = 0; i < mtd->oobsize; i++)
- oob_data[i] = 0xff;
- } else
- oob_data = oob_buf;
-
- /* Send command to begin auto page programming */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
-
- /* Write out complete page of data, take care of eccmode */
- switch (eccmode) {
- /* No ecc and software ecc 3/256, write all */
- case NAND_ECC_NONE:
- printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
- for (i = 0; i < mtd->oobblock; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
- break;
- case NAND_ECC_SOFT:
- this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- /* Calculate and write the second ECC for 512 Byte page size */
- if (mtd->oobblock == 512) {
- this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
- for (i = 3; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- }
- for (i = 0; i < mtd->oobblock; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
- break;
-
- /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */
- case NAND_ECC_HW3_256:
- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write */
- for (i = 0; i < mtd->eccsize; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
-
- this->calculate_ecc (NULL, &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
-
- if (mtd->oobblock == 512) {
- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write*/
- for (i = mtd->eccsize; i < mtd->oobblock; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
- this->calculate_ecc (NULL, &(ecc_code[3]));
- for (i = 3; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- }
- break;
-
- /* Hardware ecc 3 byte / 512 byte data, write full page */
- case NAND_ECC_HW3_512:
- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */
- for (i = 0; i < mtd->oobblock; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
- this->calculate_ecc (NULL, &(ecc_code[0]));
- for (i = 0; i < 3; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- break;
-
- /* Hardware ecc 6 byte / 512 byte data, write full page */
- case NAND_ECC_HW6_512:
- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */
- for (i = 0; i < mtd->oobblock; i++)
- writeb ( this->data_poi[i] , this->IO_ADDR_W);
- this->calculate_ecc (NULL, &(ecc_code[0]));
- for (i = 0; i < 6; i++)
- oob_data[oob_config[i]] = ecc_code[i];
- break;
-
- default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
- }
-
- /* Write out OOB data */
- for (i = 0; i < mtd->oobsize; i++)
- writeb ( oob_data[i] , this->IO_ADDR_W);
-
- /* Send command to actually program the data */
- this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- /* call wait ready function */
- status = this->waitfunc (mtd, this, FL_WRITING);
-
- /* See if device thinks it succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
- return -EIO;
- }
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /*
- * The NAND device assumes that it is always writing to
- * a cleanly erased page. Hence, it performs its internal
- * write verification only on bits that transitioned from
- * 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was
- * not completely erased or the page is becoming unusable
- * due to wear. The read with ECC would catch the error
- * later when the ECC page check fails, but we would rather
- * catch it early in the page write stage. Better to write
- * no data than invalid data.
- */
-
- /* Send command to read back the page */
- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
- /* Loop through and verify the data */
- for (i = 0; i < mtd->oobblock; i++) {
- if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- return -EIO;
- }
- }
-
- /* check, if we have a fs-supplied oob-buffer */
- if (oob_buf) {
- for (i = 0; i < mtd->oobsize; i++) {
- if (oob_data[i] != readb (this->IO_ADDR_R)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- return -EIO;
- }
- }
- } else {
- if (eccmode != NAND_ECC_NONE) {
- int ecc_bytes = 0;
-
- switch (this->eccmode) {
- case NAND_ECC_SOFT:
- case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
- case NAND_ECC_HW3_512: ecc_bytes = 3; break;
- case NAND_ECC_HW6_512: ecc_bytes = 6; break;
- }
-
- for (i = 0; i < mtd->oobsize; i++)
- oob_data[i] = readb (this->IO_ADDR_R);
-
- for (i = 0; i < ecc_bytes; i++) {
- if (oob_data[oob_config[i]] != ecc_code[i]) {
- DEBUG (MTD_DEBUG_LEVEL0,
- "%s: Failed ECC write "
- "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
- return -EIO;
- }
- }
- }
- }
- /*
- * Terminate the read command. This is faster than sending a reset command or
- * applying a 20us delay before issuing the next programm sequence.
- * This is not a problem for all chips, but I have found a bunch of them.
- */
- nand_deselect();
- nand_select();
-#endif
- return 0;
-}
-
-/*
-* Use NAND read ECC
-*/
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-{
- return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL));
-}
-
-
-/*
- * NAND read with ECC
- */
-static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
-{
- int j, col, page, end, ecc;
- int erase_state = 0;
- int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
- struct nand_chip *this = mtd->priv;
- u_char *data_poi, *oob_data = oob_buf;
- u_char ecc_calc[6];
- u_char ecc_code[6];
- int eccmode;
- int *oob_config;
-
- // use chip default if zero
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
- eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
- oob_config = oobsel->eccpos;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
-
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
- *retlen = 0;
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd ,FL_READING, &erase_state);
-
- /* Select the NAND device */
- nand_select ();
-
- /* First we calculate the starting page */
- page = from >> this->page_shift;
-
- /* Get raw starting column */
- col = from & (mtd->oobblock - 1);
-
- end = mtd->oobblock;
- ecc = mtd->eccsize;
-
- /* Send the read command */
- this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
-
- /* Loop until all data read */
- while (read < len) {
-
- /* If we have consequent page reads, apply delay or wait for ready/busy pin */
- if (read) {
- if (!this->dev_ready)
- udelay (this->chip_delay);
- else
- while (!this->dev_ready());
- }
-
- /*
- * If the read is not page aligned, we have to read into data buffer
- * due to ecc, else we read into return buffer direct
- */
- if (!col && (len - read) >= end)
- data_poi = &buf[read];
- else
- data_poi = this->data_buf;
-
- /* get oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf) {
- oob_data = &this->data_buf[end];
- oob = 0;
- }
-
- j = 0;
- switch (eccmode) {
- case NAND_ECC_NONE: /* No ECC, Read in a page */
- printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
- while (j < end)
- data_poi[j++] = readb (this->IO_ADDR_R);
- break;
-
- case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
- while (j < end)
- data_poi[j++] = readb (this->IO_ADDR_R);
- this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
- if (mtd->oobblock == 512)
- this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
- break;
-
- case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
- this->enable_hwecc (NAND_ECC_READ);
- while (j < ecc)
- data_poi[j++] = readb (this->IO_ADDR_R);
- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */
-
- if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
- this->enable_hwecc (NAND_ECC_READ);
- while (j < end)
- data_poi[j++] = readb (this->IO_ADDR_R);
- this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
- }
- break;
-
- case NAND_ECC_HW3_512:
- case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */
- this->enable_hwecc (NAND_ECC_READ);
- while (j < end)
- data_poi[j++] = readb (this->IO_ADDR_R);
- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */
- break;
-
- default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
- }
-
- /* read oobdata */
- for (j = 0; j < mtd->oobsize; j++)
- oob_data[oob + j] = readb (this->IO_ADDR_R);
-
- /* Skip ECC, if not active */
- if (eccmode == NAND_ECC_NONE)
- goto readdata;
-
- /* Pick the ECC bytes out of the oob data */
- for (j = 0; j < 6; j++)
- ecc_code[j] = oob_data[oob + oob_config[j]];
-
- /* correct data, if neccecary */
- ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
- /* check, if we have a fs supplied oob-buffer */
- if (oob_buf) {
- oob += mtd->oobsize;
- *((int *)&oob_data[oob]) = ecc_status;
- oob += sizeof(int);
- }
- if (ecc_status == -1) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
- ecc_failed++;
- }
-
- if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
- ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
- if (oob_buf) {
- *((int *)&oob_data[oob]) = ecc_status;
- oob += sizeof(int);
- }
- if (ecc_status == -1) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
- ecc_failed++;
- }
- }
-readdata:
- if (col || (len - read) < end) {
- for (j = col; j < end && read < len; j++)
- buf[read++] = data_poi[j];
- } else
- read += mtd->oobblock;
- /* For subsequent reads align to page boundary. */
- col = 0;
- /* Increment page address */
- page++;
- }
-
- /* De-select the NAND device */
- nand_deselect ();
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- /*
- * Return success, if no ECC failures, else -EIO
- * fs driver will take care of that, because
- * retlen == desired len and result == -EIO
- */
- *retlen = read;
- return ecc_failed ? -EIO : 0;
-}
-
-/*
- * NAND read out-of-band
- */
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-{
- int i, col, page;
- int erase_state = 0;
- struct nand_chip *this = mtd->priv;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
-
- /* Shift to get page */
- page = ((int) from) >> this->page_shift;
-
- /* Mask to get column */
- col = from & 0x0f;
-
- /* Initialize return length value */
- *retlen = 0;
-
- /* Do not allow reads past end of device */
- if ((from + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
- *retlen = 0;
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd , FL_READING, &erase_state);
-
- /* Select the NAND device */
- nand_select ();
-
- /* Send the read command */
- this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
- /*
- * Read the data, if we read more than one page
- * oob data, let the device transfer the data !
- */
- for (i = 0; i < len; i++) {
- buf[i] = readb (this->IO_ADDR_R);
- if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
- udelay (this->chip_delay);
- }
- /* De-select the NAND device */
- nand_deselect ();
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- /* Return happy */
- *retlen = len;
- return 0;
-}
-
-#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
-
-/*
-* Use NAND write ECC
-*/
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
-{
- return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
-}
-/*
- * NAND write with ECC
- */
-static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
-{
- int page, ret = 0, oob = 0, written = 0;
- struct nand_chip *this = mtd->priv;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
- /* Do not allow write past end of device */
- if ((to + len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
- return -EINVAL;
- }
-
- /* reject writes, which are not page aligned */
- if (NOTALIGNED (to) || NOTALIGNED(len)) {
- printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
- return -EINVAL;
- }
-
- // if oobsel is NULL, use chip defaults
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
- nand_select ();
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR_R) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
- }
-
- /* Loop until all data is written */
- while (written < len) {
- int cnt = mtd->oobblock;
- this->data_poi = (u_char*) &buf[written];
- /* We use the same function for write and writev */
- if (eccbuf) {
- ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
- oob += mtd->oobsize;
- } else
- ret = nand_write_page (mtd, this, page, NULL, oobsel);
-
- if (ret)
- goto out;
-
- /* Update written bytes count */
- written += cnt;
- /* Increment page address */
- page++;
- }
-
-out:
- /* De-select the NAND device */
- nand_deselect ();
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- *retlen = written;
- return ret;
-}
-
-/*
- * NAND write out-of-band
- */
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
-{
- int i, column, page, status, ret = 0;
- struct nand_chip *this = mtd->priv;
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
-
- /* Mask to get column */
- column = to & 0x1f;
-
- /* Initialize return length value */
- *retlen = 0;
-
- /* Do not allow write past end of page */
- if ((column + len) > mtd->oobsize) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
- nand_select ();
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR_R) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
- }
-
- /* Write out desired data */
- this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
- /* prepad 0xff for partial programming */
- for (i = 0; i < column; i++)
- writeb (0xff, this->IO_ADDR_W);
- /* write data */
- for (i = 0; i < len; i++)
- writeb (buf[i], this->IO_ADDR_W);
- /* postpad 0xff for partial programming */
- for (i = len + column; i < mtd->oobsize; i++)
- writeb (0xff, this->IO_ADDR_W);
-
- /* Send command to program the OOB data */
- this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- status = this->waitfunc (mtd, this, FL_WRITING);
-
- /* See if device thinks it succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
- ret = -EIO;
- goto out;
- }
- /* Return happy */
- *retlen = len;
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);
-
- /* Loop through and verify the data */
- for (i = 0; i < len; i++) {
- if (buf[i] != readb (this->IO_ADDR_R)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
- ret = -EIO;
- goto out;
- }
- }
-#endif
-
-out:
- /* De-select the NAND device */
- nand_deselect ();
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- return ret;
-}
-
-
-/*
- * NAND write with kvec
- */
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
- loff_t to, size_t * retlen)
-{
- return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));
-}
-
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
- loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
-{
- int i, page, len, total_len, ret = 0, written = 0;
- struct nand_chip *this = mtd->priv;
-
- /* Calculate total length of data */
- total_len = 0;
- for (i = 0; i < count; i++)
- total_len += (int) vecs[i].iov_len;
-
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
-
- /* Do not allow write past end of page */
- if ((to + total_len) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
- return -EINVAL;
- }
-
- /* reject writes, which are not page aligned */
- if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
- printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
- return -EINVAL;
- }
-
- // if oobsel is NULL, use chip defaults
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
- /* Shift to get page */
- page = ((int) to) >> this->page_shift;
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_WRITING, NULL);
-
- /* Select the NAND device */
- nand_select ();
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR_R) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
- ret = -EIO;
- goto out;
- }
-
- /* Loop until all kvec' data has been written */
- len = 0;
- while (count) {
- /*
- * Check, if the tuple gives us not enough data for a
- * full page write. Then we can use the iov direct,
- * else we have to copy into data_buf.
- */
- if ((vecs->iov_len - len) >= mtd->oobblock) {
- this->data_poi = vecs->iov_base;
- this->data_poi += len;
- len += mtd->oobblock;
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- } else {
- /*
- * Read data out of each tuple until we have a full page
- * to write or we've read all the tuples.
- */
- int cnt = 0;
- while ((cnt < mtd->oobblock) && count) {
- if (vecs->iov_base != NULL && vecs->iov_len) {
- this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
- }
- /* Check, if we have to switch to the next tuple */
- if (len >= (int) vecs->iov_len) {
- vecs++;
- len = 0;
- count--;
- }
- }
- this->data_poi = this->data_buf;
- }
-
- /* We use the same function for write and writev !) */
- ret = nand_write_page (mtd, this, page, NULL, oobsel);
- if (ret)
- goto out;
-
- /* Update written bytes count */
- written += mtd->oobblock;
-
- /* Increment page address */
- page++;
- }
-
-out:
- /* De-select the NAND device */
- nand_deselect ();
-
- /* Wake up anyone waiting on the device */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock_bh (&this->chip_lock);
-
- *retlen = written;
- return ret;
-}
-
-/*
- * NAND erase a block
- */
-static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
- int page, len, status, pages_per_block, ret;
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE (wait, current);
-
- DEBUG (MTD_DEBUG_LEVEL3,
- "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
-
- /* Start address must align on block boundary */
- if (instr->addr & (mtd->erasesize - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
- return -EINVAL;
- }
-
- /* Length must align on block boundary */
- if (instr->len & (mtd->erasesize - 1)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
- return -EINVAL;
- }
-
- /* Do not allow erase past end of device */
- if ((instr->len + instr->addr) > mtd->size) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
- return -EINVAL;
- }
-
- /* Grab the lock and see if the device is available */
- nand_get_chip (this, mtd, FL_ERASING, NULL);
-
- /* Shift to get first page */
- page = (int) (instr->addr >> this->page_shift);
-
- /* Calculate pages in each block */
- pages_per_block = mtd->erasesize / mtd->oobblock;
-
- /* Select the NAND device */
- nand_select ();
-
- /* Check the WP bit */
- this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- if (!(readb (this->IO_ADDR_R) & 0x80)) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
-
- /* Loop through the pages */
- len = instr->len;
-
- instr->state = MTD_ERASING;
-
- while (len) {
- /* Check if we have a bad block, we do not erase bad blocks ! */
- this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
- if (readb (this->IO_ADDR_R) != 0xff) {
- printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
-
- /* Send commands to erase a page */
- this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
- this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
-
- spin_unlock_bh (&this->chip_lock);
- status = this->waitfunc (mtd, this, FL_ERASING);
-
- /* Get spinlock, in case we exit */
- spin_lock_bh (&this->chip_lock);
- /* See if block erase succeeded */
- if (status & 0x01) {
- DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
-
- /* Check, if we were interupted */
- if (this->state == FL_ERASING) {
- /* Increment page address and decrement length */
- len -= mtd->erasesize;
- page += pages_per_block;
- }
- /* Release the spin lock */
- spin_unlock_bh (&this->chip_lock);
-erase_retry:
- spin_lock_bh (&this->chip_lock);
- /* Check the state and sleep if it changed */
- if (this->state == FL_ERASING || this->state == FL_READY) {
- /* Select the NAND device again, if we were interrupted */
- this->state = FL_ERASING;
- nand_select ();
- continue;
- } else {
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule ();
- remove_wait_queue (&this->wq, &wait);
- goto erase_retry;
- }
- }
- instr->state = MTD_ERASE_DONE;
-
-erase_exit:
- /* De-select the NAND device */
- nand_deselect ();
- spin_unlock_bh (&this->chip_lock);
-
- ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret && instr->callback)
- instr->callback (instr);
-
- /* The device is ready */
- spin_lock_bh (&this->chip_lock);
- this->state = FL_READY;
- spin_unlock_bh (&this->chip_lock);
-
- /* Return more or less happy */
- return ret;
-}
-
-/*
- * NAND sync
- */
-static void nand_sync (struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- DECLARE_WAITQUEUE (wait, current);
-
- DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
-
-retry:
- /* Grab the spinlock */
- spin_lock_bh (&this->chip_lock);
-
- /* See what's going on */
- switch (this->state) {
- case FL_READY:
- case FL_SYNCING:
- this->state = FL_SYNCING;
- spin_unlock_bh (&this->chip_lock);
- break;
-
- default:
- /* Not an idle state */
- add_wait_queue (&this->wq, &wait);
- spin_unlock_bh (&this->chip_lock);
- schedule ();
-
- remove_wait_queue (&this->wq, &wait);
- goto retry;
- }
-
- /* Lock the device */
- spin_lock_bh (&this->chip_lock);
-
- /* Set the device to be ready again */
- if (this->state == FL_SYNCING) {
- this->state = FL_READY;
- wake_up (&this->wq);
- }
-
- /* Unlock the device */
- spin_unlock_bh (&this->chip_lock);
-}
-
-/*
- * Scan for the NAND device
- */
-int nand_scan (struct mtd_info *mtd)
-{
- int i, nand_maf_id, nand_dev_id;
- struct nand_chip *this = mtd->priv;
-
- /* check for proper chip_delay setup, set 20us if not */
- if (!this->chip_delay)
- this->chip_delay = 20;
-
- /* check, if a user supplied command function given */
- if (this->cmdfunc == NULL)
- this->cmdfunc = nand_command;
-
- /* check, if a user supplied wait function given */
- if (this->waitfunc == NULL)
- this->waitfunc = nand_wait;
-
- /* Select the device */
- nand_select ();
-
- /* Send the command for reading device ID */
- this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-
- /* Read manufacturer and device IDs */
- nand_maf_id = readb (this->IO_ADDR_R);
- nand_dev_id = readb (this->IO_ADDR_R);
-
- /* Print and store flash device information */
- for (i = 0; nand_flash_ids[i].name != NULL; i++) {
- if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
- mtd->name = nand_flash_ids[i].name;
- mtd->erasesize = nand_flash_ids[i].erasesize;
- mtd->size = (1 << nand_flash_ids[i].chipshift);
- mtd->eccsize = 256;
- if (nand_flash_ids[i].page256) {
- mtd->oobblock = 256;
- mtd->oobsize = 8;
- this->page_shift = 8;
- } else {
- mtd->oobblock = 512;
- mtd->oobsize = 16;
- this->page_shift = 9;
- }
- /* Try to identify manufacturer */
- for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
- if (nand_manuf_ids[i].id == nand_maf_id)
- break;
- }
- printk (KERN_INFO "NAND device: Manufacture ID:"
- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[i].name , mtd->name);
- break;
- }
- }
-
- /*
- * check ECC mode, default to software
- * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
- * fallback to software ECC
- */
- this->eccsize = 256; /* set default eccsize */
-
- switch (this->eccmode) {
-
- case NAND_ECC_HW3_512:
- if (mtd->oobblock == 256) {
- printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
- this->eccmode = NAND_ECC_SOFT;
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- break;
- } else
- this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
-
- case NAND_ECC_HW3_256:
- if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
- break;
- printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
- BUG();
-
- case NAND_ECC_NONE:
- printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
- this->eccmode = NAND_ECC_NONE;
- break;
-
- case NAND_ECC_SOFT:
- this->calculate_ecc = nand_calculate_ecc;
- this->correct_data = nand_correct_data;
- break;
-
- default:
- printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
- BUG();
- }
-
- /* Initialize state, waitqueue and spinlock */
- this->state = FL_READY;
- init_waitqueue_head (&this->wq);
- spin_lock_init (&this->chip_lock);
-
- /* De-select the device */
- nand_deselect ();
-
- /* Print warning message for no device */
- if (!mtd->size) {
- printk (KERN_WARNING "No NAND device found!!!\n");
- return 1;
- }
-
- /* Fill in remaining MTD driver data */
- mtd->type = MTD_NANDFLASH;
- mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
- mtd->ecctype = MTD_ECC_SW;
- mtd->erase = nand_erase;
- mtd->point = NULL;
- mtd->unpoint = NULL;
- mtd->read = nand_read;
- mtd->write = nand_write;
- mtd->read_ecc = nand_read_ecc;
- mtd->write_ecc = nand_write_ecc;
- mtd->read_oob = nand_read_oob;
- mtd->write_oob = nand_write_oob;
- mtd->readv = NULL;
- mtd->writev = nand_writev;
- mtd->writev_ecc = nand_writev_ecc;
- mtd->sync = nand_sync;
- mtd->lock = NULL;
- mtd->unlock = NULL;
- mtd->suspend = NULL;
- mtd->resume = NULL;
- mtd->owner = THIS_MODULE;
-
- /* Return happy */
- return 0;
-}
-
-EXPORT_SYMBOL (nand_scan);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION ("Generic NAND flash driver code");
/*
- * drivers/mtd/nand_ecc.c
+ * This file contains an ECC algorithm from Toshiba that detects and
+ * corrects 1 bit errors in a 256 byte block of data.
*
- * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * Toshiba America Electronics Components, Inc.
+ * drivers/mtd/nand/nand_ecc.c
*
- * $Id: nand_ecc.c,v 1.9 2003/02/20 13:34:19 sjhill Exp $
+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
+ * Toshiba America Electronics Components, Inc.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
+ * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
*
- * This file contains an ECC algorithm from Toshiba that detects and
- * corrects 1 bit errors in a 256 byte block of data.
+ * This file 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 or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * As a special exception, if other files instantiate templates or use
+ * macros or inline functions from these files, or you compile these
+ * files and link them with other works to produce a work based on these
+ * files, these files do not by themselves cause the resulting work to be
+ * covered by the GNU General Public License. However the source code for
+ * these files must still be made available in accordance with section (3)
+ * of the GNU General Public License.
+ *
+ * This exception does not invalidate any other reasons why a work based on
+ * this file might be covered by the GNU General Public License.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mtd/nand_ecc.h>
/*
* Pre-calculated 256-way 1 byte column parity
};
-/*
+/**
+ * nand_trans_result - [GENERIC] create non-inverted ECC
+ * @reg2: line parity reg 2
+ * @reg3: line parity reg 3
+ * @ecc_code: ecc
+ *
* Creates non-inverted ECC code from line parity
*/
static void nand_trans_result(u_char reg2, u_char reg3,
ecc_code[1] = tmp2;
}
-/*
- * Calculate 3 byte ECC code for 256 byte block
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
+ * @mtd: MTD block structure
+ * @dat: raw data
+ * @ecc_code: buffer for ECC
*/
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
u_char idx, reg1, reg2, reg3;
int j;
ecc_code[0] = ~ecc_code[0];
ecc_code[1] = ~ecc_code[1];
ecc_code[2] = ((~reg1) << 2) | 0x03;
+ return 0;
}
-/*
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd: MTD block structure
+ * @dat: raw data read from the chip
+ * @read_ecc: ECC from the chip
+ * @calc_ecc: the ECC calculated from raw data
+ *
* Detect and correct a 1 bit error for 256 byte block
*/
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
{
u_char a, b, c, d1, d2, d3, add, bit, i;
* drivers/mtd/nandids.c
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- *
- * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $
+ *
+ * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
*/
#include <linux/module.h>
#include <linux/mtd/nand.h>
-
/*
* Chip ID list
+*
+* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
+* options
+*
+* Pagesize; 0, 256, 512
+* 0 get this information from the extended chip ID
++ 256 256 Byte page size
+* 512 512 Byte page size
*/
struct nand_flash_dev nand_flash_ids[] = {
- {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1},
- {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1},
- {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0},
- {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1},
- {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1},
- {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1},
- {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0},
- {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0},
- {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0},
- {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0},
- {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0},
- {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0},
- {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0},
- {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0},
- {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0},
+ {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
+
+ {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+ {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+
+ {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
+
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0},
+
+ /* These are the new chips with large page size. The pagesize
+ * and the erasesize is determined from the extended id bytes
+ */
+ /* 1 Gigabit */
+ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 2 Gigabit */
+ {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 4 Gigabit */
+ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 8 Gigabit */
+ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 16 Gigabit */
+ {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
+ * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
+ * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
+ * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
+ * There are more speed improvements for reads and writes possible, but not implemented now
+ */
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+
{NULL,}
};
{NAND_MFR_SAMSUNG, "Samsung"},
{NAND_MFR_FUJITSU, "Fujitsu"},
{NAND_MFR_NATIONAL, "National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_STMICRO, "ST Micro"},
{0x0, "Unknown"}
};
-
EXPORT_SYMBOL (nand_manuf_ids);
EXPORT_SYMBOL (nand_flash_ids);
* to controllines (due to change in nand.c)
* page_cache added
*
- * $Id: spia.c,v 1.19 2003/04/20 07:24:40 gleixner Exp $
+ * $Id: spia.c,v 1.21 2003/07/11 15:12:29 dwmw2 Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* a 64Mibit (8MiB x 8 bits) NAND flash device.
*/
+#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
/*
* Values specific to the SPIA board (used with EP7212 processor)
*/
-#define SPIA_IO_ADDR = 0xd0000000 /* Start of EP7212 IO address space */
-#define SPIA_FIO_ADDR = 0xf0000000 /* Address where flash is mapped */
-#define SPIA_PEDR = 0x0080 /*
+#define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */
+#define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */
+#define SPIA_PEDR 0x0080 /*
* IO offset to Port E data register
* where the CLE, ALE and NCE pins
* are wired to.
*/
-#define SPIA_PEDDR = 0x00c0 /*
+#define SPIA_PEDDR 0x00c0 /*
* IO offset to Port E data direction
* register so we can control the IO
* lines.
MODULE_PARM(spia_pedr, "i");
MODULE_PARM(spia_peddr, "i");
-__setup("spia_io_base=",spia_io_base);
-__setup("spia_fio_base=",spia_fio_base);
-__setup("spia_pedr=",spia_pedr);
-__setup("spia_peddr=",spia_peddr);
-
/*
* Define partitions for flash device
*/
/*
* hardware specific access to control-lines
*/
-void spia_hwcontrol(int cmd){
+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
switch(cmd){
this->chip_delay = 15;
/* Scan to find existence of the device */
- if (nand_scan (spia_mtd)) {
+ if (nand_scan (spia_mtd, 1)) {
kfree (spia_mtd);
return -ENXIO;
}
/* Linux driver for NAND Flash Translation Layer */
/* (c) 1999 Machine Vision Holdings, Inc. */
/* Author: David Woodhouse <dwmw2@infradead.org> */
-/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.96 2004/06/28 13:52:55 dbrown Exp $ */
/*
The contents of this file are distributed under the GNU General
struct NFTLrecord *nftl;
unsigned long temp;
- if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+ if (mtd->type != MTD_NANDFLASH)
+ return;
+ /* OK, this is moderately ugly. But probably safe. Alternatives? */
+ if (memcmp(mtd->name, "DiskOnChip", 10))
return;
+ if (!mtd->block_isbad) {
+ printk(KERN_ERR
+"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
+ return;
+ }
+
DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
nftl->mbd.devnum = -1;
nftl->mbd.blksize = 512;
nftl->mbd.tr = tr;
+ memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+ nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (NFTL_mount(nftl) < 0) {
printk(KERN_WARNING "NFTL: could not mount device\n");
if (BlockMap[block] == BLOCK_NIL)
continue;
- ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
+ ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+ 512, &retlen, movebuf);
if (ret < 0) {
- ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
+ ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
+ (block * 512), 512, &retlen,
- movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
+ movebuf);
if (ret != -EIO)
printk("Error went away on retry.\n");
}
+ memset(&oob, 0xff, sizeof(struct nftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
- 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
+ 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
}
/* add the header so that it is now a valid chain */
if (NFTL_formatblock(nftl, thisEUN) < 0) {
/* could not erase : mark block as reserved
- * FixMe: Update Bad Unit Table on disk
*/
nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
} else {
u16 writeEUN;
unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
size_t retlen;
- u8 eccbuf[6];
+ struct nftl_oob oob;
writeEUN = NFTL_findwriteunit(nftl, block);
return 1;
}
+ memset(&oob, 0xff, sizeof(struct nftl_oob));
+ oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
- 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
- /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
+ 512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
+ /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
return 0;
}
} else {
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
size_t retlen;
- u_char eccbuf[6];
- if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
+ if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
return -EIO;
}
return 0;
int __init init_nftl(void)
{
- printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev);
+ printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.96 $, nftlmount.c %s\n", nftlmountrev);
return register_mtd_blktrans(&nftl_tr);
}
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
- * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.36 2004/06/28 13:52:55 dbrown Exp $
*
* 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
#define SECTORSIZE 512
-char nftlmountrev[]="$Revision: 1.34 $";
+char nftlmountrev[]="$Revision: 1.36 $";
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
* various device information of the NFTL partition and Bad Unit Table. Update
/* Assume logical EraseSize == physical erasesize for starting the scan.
We'll sort it out later if we find a MediaHeader which says otherwise */
+ /* Actually, we won't. The new DiskOnChip driver has already scanned
+ the MediaHeader and adjusted the virtual erasesize it presents in
+ the mtd device accordingly. We could even get rid of
+ nftl->EraseSize if there were any point in doing so. */
nftl->EraseSize = nftl->mbd.mtd->erasesize;
nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
/* Check for ANAND header first. Then can whinge if it's found but later
checks fail */
- if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
+ ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf);
+ /* We ignore ret in case the ECC of the MediaHeader is invalid
+ (which is apparently acceptable) */
+ if (retlen != SECTORSIZE) {
static int warncount = 5;
if (warncount) {
/* Finally reread to check ECC */
if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
- &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
+ &retlen, buf, (char *)&oob, NULL) < 0)) {
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue;
memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
/* Do some sanity checks on it */
+#if 0
+The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
+erasesize based on UnitSizeFactor. So the erasesize we read from the mtd
+device is already correct.
if (mh->UnitSizeFactor == 0) {
printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
} else if (mh->UnitSizeFactor < 0xfc) {
nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
}
+#endif
nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
for (i = 0; i < nftl->nb_blocks; i++) {
+#if 0
+The new DiskOnChip driver already scanned the bad block table. Just query it.
if ((i & (SECTORSIZE - 1)) == 0) {
/* read one sector for every SECTORSIZE of blocks */
if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
i + SECTORSIZE, SECTORSIZE, &retlen, buf,
- (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
+ (char *)&oob, NULL)) < 0) {
printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
ret);
kfree(nftl->ReplUnitTable);
/* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
if (buf[i & (SECTORSIZE - 1)] != 0xff)
nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+#endif
+ if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
+ nftl->ReplUnitTable[i] = BLOCK_RESERVED;
}
nftl->MediaUnit = block;
int check_oob)
{
int i, retlen;
- u8 buf[SECTORSIZE];
+ u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
for (i = 0; i < len; i += SECTORSIZE) {
- /* we want to read the sector without ECC check here since a free
- sector does not have ECC syndrome on it yet */
- if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+ if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
if (check_oob) {
- if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
- &retlen, buf) < 0)
- return -1;
- if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
+ if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
return -1;
}
address += SECTORSIZE;
* Return: 0 when succeed, -1 on error.
*
* ToDo: 1. Is it neceressary to check_free_sector after erasing ??
- * 2. UnitSizeFactor != 0xFF
*/
int NFTL_formatblock(struct NFTLrecord *nftl, int block)
{
MTD_ERASE(nftl->mbd.mtd, instr);
if (instr->state == MTD_ERASE_FAILED) {
- /* could not format, FixMe: We should update the BadUnitTable
- both in memory and on disk */
printk("Error while formatting block %d\n", block);
- return -1;
- } else {
+ goto fail;
+ }
+
/* increase and write Wear-Leveling info */
nb_erases = le32_to_cpu(uci.WearInfo);
nb_erases++;
* FixMe: is this check really necessary ? since we have check the
* return code after the erase operation. */
if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
- return -1;
+ goto fail;
uci.WearInfo = le32_to_cpu(nb_erases);
if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
&retlen, (char *)&uci) < 0)
- return -1;
+ goto fail;
return 0;
- }
+fail:
+ /* could not format, update the bad block table (caller is responsible
+ for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
+ nftl->mbd.mtd->block_markbad(nftl->mbd.mtd, instr->addr);
+ return -1;
}
/* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
printk("Formatting block %d\n", block);
if (NFTL_formatblock(nftl, block) < 0) {
- /* cannot format !!!! Mark it as Bad Unit,
- FixMe: update the BadUnitTable on disk */
+ /* cannot format !!!! Mark it as Bad Unit */
nftl->ReplUnitTable[block] = BLOCK_RESERVED;
} else {
nftl->ReplUnitTable[block] = BLOCK_FREE;
/*
- * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $
+ * $Id: redboot.c,v 1.13 2004/04/01 10:17:40 gthomas Exp $
*
* Parse RedBoot-style Flash Image System (FIS) tables and
* produce a Linux partition array to match.
char *names;
char *nullname;
int namelen = 0;
+ int nulllen = 0;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
static char nullstring[] = "unallocated";
+#endif
- buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ buf = kmalloc(master->erasesize, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Read the start of the last erase block */
ret = master->read(master, master->size - master->erasesize,
- PAGE_SIZE, &retlen, (void *)buf);
+ master->erasesize, &retlen, (void *)buf);
if (ret)
goto out;
- if (retlen != PAGE_SIZE) {
+ if (retlen != master->erasesize) {
ret = -EIO;
goto out;
}
goto out;
}
- for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
+ for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
struct fis_list *new_fl, **prev;
if (buf[i].name[0] == 0xff)
nrparts++;
}
- if (fl->img->flash_base)
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ if (fl->img->flash_base) {
nrparts++;
+ nulllen = sizeof(nullstring);
+ }
for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
- if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
+ if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
nrparts++;
+ nulllen = sizeof(nullstring);
+ }
}
- parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL);
+#endif
+ parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
- memset(parts, 0, sizeof(*parts)*nrparts + namelen);
+ memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
- /* FIXME: Include nullname only if it's used */
nullname = (char *)&parts[nrparts];
- sprintf(nullname, nullstring);
- names = nullname + sizeof(nullstring);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ if (nulllen > 0) {
+ strcpy(nullname, nullstring);
+ }
+#endif
+ names = nullname + nulllen;
i=0;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (fl->img->flash_base) {
parts[0].name = nullname;
parts[0].size = fl->img->flash_base;
parts[0].offset = 0;
+ i++;
}
+#endif
for ( ; i<nrparts; i++) {
parts[i].size = fl->img->size;
parts[i].offset = fl->img->flash_base;
parts[i].name = names;
strcpy(names, fl->img->name);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
+ if (!memcmp(names, "RedBoot", 8) ||
+ !memcmp(names, "RedBoot config", 15) ||
+ !memcmp(names, "FIS directory", 14)) {
+ parts[i].mask_flags = MTD_WRITEABLE;
+ }
+#endif
names += strlen(names)+1;
- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
i++;
parts[i].offset = parts[i-1].size + parts[i-1].offset;
parts[i].size = fl->next->img->flash_base - parts[i].offset;
parts[i].name = nullname;
}
+#endif
tmp_fl = fl;
fl = fl->next;
kfree(tmp_fl);
To compile this driver as a module, choose M here: the module
will be called tg3. This is recommended.
+config GIANFAR
+ tristate "Gianfar Ethernet"
+ depends on 85xx
+ help
+ This driver supports the Gigabit TSEC on the MPC85xx
+ family of chips, and the FEC on the 8540
+
+config GFAR_NAPI
+ bool "NAPI Support"
+ depends on GIANFAR
+
endmenu
#
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_GIANFAR) += gianfar.o gianfar_ethtool.o gianfar_phy.o
#
# link order important here
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_MPSC
+ bool "Marvell MPSC serial port support"
+ depends on PPC32 && MV64X60
+ select SERIAL_CORE
+ help
+ Say Y here if you want to use the Marvell MPSC serial controller.
+
+config SERIAL_MPSC_CONSOLE
+ bool "Support for console on Marvell MPSC serial port"
+ depends on SERIAL_MPSC
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you want to support a serial console on a Marvell MPSC.
+
config SERIAL_PXA
bool "PXA serial port support"
depends on ARM && ARCH_PXA
# $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
#
+obj-$(CONFIG_SERIAL_MPSC) += mpsc/
+
serial-8250-y :=
serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o
serial-8250-$(CONFIG_GSC) += 8250_gsc.o
config JFFS_PROC_FS
bool "JFFS stats available in /proc filesystem"
- depends on JFFS_FS && PROC
+ depends on JFFS_FS && PROC_FS
help
Enabling this option will cause statistics from mounted JFFS file systems
to be made available to the user in the /proc/fs/jffs/ directory.
config JFFS2_FS
tristate "Journalling Flash File System v2 (JFFS2) support"
- depends on MTD
select CRC32
- select ZLIB_INFLATE
- select ZLIB_DEFLATE
+ depends on MTD
help
JFFS2 is the second generation of the Journalling Flash File System
for use on diskless embedded devices. It provides improved wear
Say 'N' unless you have NAND flash and you are willing to test and
develop JFFS2 support for it.
+config JFFS2_COMPRESSION_OPTIONS
+ bool "Advanced compression options for JFFS2"
+ default n
+ help
+ Enabling this option allows you to explicitly choose which
+ compression modules, if any, are enabled in JFFS2. Removing
+ compressors and mean you cannot read existing file systems,
+ and enabling experimental compressors can mean that you
+ write a file system which cannot be read by a standard kernel.
+
+ If unsure, you should _definitely_ say 'N'.
+
+config JFFS2_ZLIB
+ bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS
+ select ZLIB_INFLATE
+ select ZLIB_DEFLATE
+ depends on JFFS2_FS
+ default y
+ help
+ Zlib is designed to be a free, general-purpose, legally unencumbered,
+ lossless data-compression library for use on virtually any computer
+ hardware and operating system. See http://www.gzip.org/zlib/ for
+ further information.
+
+ Say 'Y' if unsure.
+
+config JFFS2_RTIME
+ bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+ depends on JFFS2_FS
+ default y
+ help
+ Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+
+config JFFS2_RUBIN
+ bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
+ depends on JFFS2_FS
+ default n
+ help
+ RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+
+choice
+ prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
+ default JFFS2_CMODE_PRIORITY
+ depends on JFFS2_FS
+ help
+ You can set here the default compression mode of JFFS2 from
+ the avaiable compression modes. Don't touch if unsure.
+
+config JFFS2_CMODE_NONE
+ bool "no compression"
+ help
+ Uses no compression.
+
+config JFFS2_CMODE_PRIORITY
+ bool "priority"
+ help
+ Tries the compressors in a predefinied order and chooses the first
+ successful one.
+
+config JFFS2_CMODE_SIZE
+ bool "size (EXPERIMENTAL)"
+ help
+ Tries all compressors and chooses the one which has the smallest
+ result.
+
+endchoice
+
+config JFFS2_PROC
+ bool "JFFS2 proc interface support" if JFFS2_COMPRESSION_OPTIONS
+ depends on JFFS2_FS && PROC_FS
+ default n
+ help
+ You can read some statistics and set the compression mode and
+ compressor priorities with this interface.
+
+
config CRAMFS
tristate "Compressed ROM file system support"
select ZLIB_INFLATE
obj-$(CONFIG_CRAMFS) += cramfs/
obj-$(CONFIG_RAMFS) += ramfs/
obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
+obj-$(CONFIG_RELAYFS_FS) += relayfs/
obj-$(CONFIG_CODA_FS) += coda/
obj-$(CONFIG_MINIX_FS) += minix/
obj-$(CONFIG_FAT_FS) += fat/
inode->i_uid = attr->ia_uid;
if (ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
+ if (ia_valid & ATTR_XID)
+ inode->i_xid = attr->ia_xid;
if (ia_valid & ATTR_ATIME)
inode->i_atime = attr->ia_atime;
if (ia_valid & ATTR_MTIME)
dn_mask |= DN_ATTRIB;
if (ia_valid & ATTR_GID)
dn_mask |= DN_ATTRIB;
+ if (ia_valid & ATTR_XID)
+ dn_mask |= DN_ATTRIB;
if (ia_valid & ATTR_SIZE)
dn_mask |= DN_MODIFY;
/* both times implies a utime(s) call */
error = security_inode_setattr(dentry, attr);
if (!error) {
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
+ (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid))
error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
if (!error)
error = inode_setattr(inode, attr);
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/init.h>
+#include <linux/vs_memory.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/security.h>
#include <linux/syscalls.h>
-#include <linux/vs_memory.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
#include <linux/ckrm.h>
-#include <linux/vs_memory.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <linux/quotaops.h>
#include <linux/sched.h>
#include <linux/buffer_head.h>
+#include <linux/vs_base.h>
+#include <linux/vs_dlimit.h>
/*
* balloc.c contains the blocks allocation and deallocation routines
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(es->s_r_blocks_count);
+ DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks);
+
if (free_blocks < count)
count = free_blocks;
}
error_return:
brelse(bitmap_bh);
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, freed);
release_blocks(sb, freed);
DQUOT_FREE_BLOCK(inode, freed);
}
*err = -ENOSPC;
goto out_dquot;
}
+ if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, es_alloc)) {
+ *err = -ENOSPC;
+ goto out_dlimit;
+ }
ext2_debug ("goal=%lu.\n", goal);
*err = 0;
out_release:
group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc);
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, es_alloc);
+out_dlimit:
release_blocks(sb, es_alloc);
out_dquot:
DQUOT_FREE_BLOCK(inode, dq_alloc);
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
#include <linux/random.h>
+#include <linux/vs_base.h>
+#include <linux/vs_dlimit.h>
+
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
if (!is_bad_inode(inode)) {
/* Quota is already initialized in iput() */
ext2_xattr_delete_inode(inode);
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
DQUOT_FREE_INODE(inode);
DQUOT_DROP(inode);
}
if (!inode)
return ERR_PTR(-ENOMEM);
+ if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+ err = -ENOSPC;
+ goto fail_dlim;
+ }
ei = EXT2_I(inode);
sbi = EXT2_SB(sb);
es = sbi->s_es;
return inode;
fail2:
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return ERR_PTR(err);
fail:
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
+fail_dlim:
make_bad_inode(inode);
iput(inode);
return ERR_PTR(err);
if (error)
return error;
if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
- (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+ (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) ||
+ (iattr->ia_valid & ATTR_XID && iattr->ia_xid != inode->i_xid)) {
error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0;
if (error)
return error;
}
+ if (iattr->ia_valid & ATTR_ATTR_FLAG)
+ ext2_setattr_flags(inode, iattr->ia_attr_flags);
+
error = inode_setattr(inode, iattr);
if (!error && (iattr->ia_valid & ATTR_MODE))
error = ext2_acl_chmod(inode);
#include <linux/mbcache.h>
#include <linux/quotaops.h>
#include <linux/rwsem.h>
+#include <linux/vs_dlimit.h>
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
the inode. */
ea_bdebug(new_bh, "reusing block");
+ error = -ENOSPC;
+ if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+ goto cleanup;
error = -EDQUOT;
if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
unlock_buffer(new_bh);
goto cleanup;
}
/* Decrement the refcount only. */
HDR(old_bh)->h_refcount = cpu_to_le32(
le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
DQUOT_FREE_BLOCK(inode, 1);
mark_buffer_dirty(old_bh);
ea_bdebug(old_bh, "refcount now=%d",
mark_buffer_dirty(bh);
if (IS_SYNC(inode))
sync_dirty_buffer(bh);
+ DLIMIT_FREE_BLOCK(inode->i_sb, inode->i_xid, 1);
DQUOT_FREE_BLOCK(inode, 1);
}
ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
#include <linux/ext3_jbd.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
+#include <linux/vs_dlimit.h>
/*
* balloc.c contains the blocks allocation and deallocation routines
error_return:
brelse(bitmap_bh);
ext3_std_error(sb, err);
- if (dquot_freed_blocks)
+ if (dquot_freed_blocks) {
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, dquot_freed_blocks);
DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
+ }
return;
}
return -1;
}
-static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
+static int ext3_has_free_blocks(struct super_block *sb)
{
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
int free_blocks, root_blocks;
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
+
+ DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks);
+
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
sbi->s_resuid != current->fsuid &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
*/
int ext3_should_retry_alloc(struct super_block *sb, int *retries)
{
- if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3)
+ if (!ext3_has_free_blocks(sb) || (*retries)++ > 3)
return 0;
jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
*errp = -EDQUOT;
return 0;
}
+ if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+ goto out_dlimit;
sbi = EXT3_SB(sb);
es = EXT3_SB(sb)->s_es;
ext3_debug("goal=%lu.\n", goal);
- if (!ext3_has_free_blocks(sbi)) {
+ if (!ext3_has_free_blocks(sb)) {
*errp = -ENOSPC;
goto out;
}
io_error:
*errp = -EIO;
out:
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
+out_dlimit:
if (fatal) {
*errp = fatal;
ext3_std_error(sb, fatal);
/*
* Undo the block allocation
*/
- if (!performed_allocation)
+ if (!performed_allocation) {
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
DQUOT_FREE_BLOCK(inode, 1);
+ }
brelse(bitmap_bh);
return 0;
}
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/random.h>
+#include <linux/vs_dlimit.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
*/
DQUOT_INIT(inode);
ext3_xattr_delete_inode(handle, inode);
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
DQUOT_FREE_INODE(inode);
DQUOT_DROP(inode);
inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);
+ if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+ err = -ENOSPC;
+ goto fail_dlim;
+ }
ei = EXT3_I(inode);
sbi = EXT3_SB(sb);
ext3_debug("allocating inode %lu\n", inode->i_ino);
goto really_out;
fail:
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
+fail_dlim:
ext3_std_error(sb, err);
out:
iput(inode);
return ret;
fail2:
+ DLIMIT_FREE_INODE(sb, inode->i_xid);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return error;
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
+ (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) {
handle_t *handle;
/* (user+group)*(old+new) structure, inode write (sb,
inode->i_uid = attr->ia_uid;
if (attr->ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
+ if (attr->ia_valid & ATTR_XID)
+ inode->i_xid = attr->ia_xid;
error = ext3_mark_inode_dirty(handle, inode);
ext3_journal_stop(handle);
}
return ret;
}
#endif
-
#if defined(CONFIG_VSERVER_LEGACY) && !defined(CONFIG_INOXID_NONE)
case EXT3_IOC_SETXID: {
handle_t *handle;
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
- Opt_tagxid, Opt_ignore, Opt_err, Opt_resize,
+ Opt_tagxid, Opt_ignore, Opt_err
};
static match_table_t tokens = {
#include <linux/mbcache.h>
#include <linux/quotaops.h>
#include <linux/rwsem.h>
+#include <linux/vs_dlimit.h>
#include "xattr.h"
#include "acl.h"
the inode. */
ea_bdebug(new_bh, "reusing block");
+ error = -ENOSPC;
+ if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+ goto cleanup;
error = -EDQUOT;
if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
unlock_buffer(new_bh);
journal_release_buffer(handle, new_bh,
credits);
/* Decrement the refcount only. */
HDR(old_bh)->h_refcount = cpu_to_le32(
le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
+ DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
DQUOT_FREE_BLOCK(inode, 1);
ext3_journal_dirty_metadata(handle, old_bh);
ea_bdebug(old_bh, "refcount now=%d",
ext3_journal_dirty_metadata(handle, bh);
if (IS_SYNC(inode))
handle->h_sync = 1;
+ DLIMIT_FREE_BLOCK(inode->i_sb, inode->i_xid, 1);
DQUOT_FREE_BLOCK(inode, 1);
}
ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
+#include <linux/vs_base.h>
/*
* This is needed for the following functions:
list_add(&inode->i_list, &inode_in_use);
inode->i_ino = ++last_ino;
inode->i_state = 0;
+ inode->i_xid = vx_current_xid();
spin_unlock(&inode_lock);
}
return inode;
#
-# Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
+# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
#
-# $Id: Makefile,v 1.34 2002/03/08 11:27:59 dwmw2 Exp $
+# $Id: Makefile.common,v 1.5 2004/07/15 16:06:41 dwmw2 Exp $
#
obj-$(CONFIG_JFFS2_FS) += jffs2.o
-jffs2-y := compr.o compr_rubin.o compr_rtime.o compr_zlib.o
-jffs2-y += dir.o file.o ioctl.o nodelist.o malloc.o
+jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o
jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o
jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
jffs2-y += super.o
jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
+jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
+jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
+jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
+jffs2-$(CONFIG_JFFS2_PROC) += proc.o
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: background.c,v 1.44 2003/10/08 13:29:55 dwmw2 Exp $
+ * $Id: background.c,v 1.49 2004/07/13 08:56:40 dwmw2 Exp $
*
*/
static int jffs2_garbage_collect_thread(void *);
-static int thread_should_wake(struct jffs2_sb_info *c);
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
{
spin_lock(&c->erase_completion_lock);
- if (c->gc_task && thread_should_wake(c))
+ if (c->gc_task && jffs2_thread_should_wake(c))
send_sig(SIGHUP, c->gc_task, 1);
spin_unlock(&c->erase_completion_lock);
}
for (;;) {
allow_signal(SIGHUP);
- if (!thread_should_wake(c)) {
+ if (!jffs2_thread_should_wake(c)) {
set_current_state (TASK_INTERRUPTIBLE);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
- /* Yes, there's a race here; we checked thread_should_wake() before
- setting current->state to TASK_INTERRUPTIBLE. But it doesn't
+ /* Yes, there's a race here; we checked jffs2_thread_should_wake()
+ before setting current->state to TASK_INTERRUPTIBLE. But it doesn't
matter - We don't care if we miss a wakeup, because the GC thread
is only an optimisation anyway. */
schedule();
spin_unlock(&c->erase_completion_lock);
complete_and_exit(&c->gc_thread_exit, 0);
}
-
-static int thread_should_wake(struct jffs2_sb_info *c)
-{
- int ret = 0;
- uint32_t dirty;
-
- if (c->unchecked_size) {
- D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
- c->unchecked_size, c->checked_ino));
- return 1;
- }
-
- /* dirty_size contains blocks on erase_pending_list
- * those blocks are counted in c->nr_erasing_blocks.
- * If one block is actually erased, it is not longer counted as dirty_space
- * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
- * with c->nr_erasing_blocks * c->sector_size again.
- * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
- * This helps us to force gc and pick eventually a clean block to spread the load.
- */
- dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
-
- if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
- (dirty > c->nospc_dirty_size))
- ret = 1;
-
- D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
- c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
-
- return ret;
-}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: build.c,v 1.52 2003/10/09 00:38:38 dwmw2 Exp $
+ * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
*
*/
#include <linux/slab.h>
#include "nodelist.h"
-int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
-int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
static inline struct jffs2_inode_cache *
first_inode_chain(int *i, struct jffs2_sb_info *c)
ic; \
ic = next_inode(&i, ic, (c)))
+
+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+ struct jffs2_full_dirent *fd;
+
+ D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
+
+ /* For each child, increase nlink */
+ for(fd = ic->scan_dents; fd; fd = fd->next) {
+ struct jffs2_inode_cache *child_ic;
+ if (!fd->ino)
+ continue;
+
+ /* XXX: Can get high latency here with huge directories */
+
+ child_ic = jffs2_get_ino_cache(c, fd->ino);
+ if (!child_ic) {
+ printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
+ fd->name, fd->ino, ic->ino);
+ continue;
+ }
+
+ if (child_ic->nlink++ && fd->type == DT_DIR) {
+ printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
+ if (fd->ino == 1 && ic->ino == 1) {
+ printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
+ printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
+ }
+ /* What do we do about it? */
+ }
+ D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
+ /* Can't free them. We might need them in pass 2 */
+ }
+}
+
/* Scan plan:
- Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
- Scan directory tree from top down, setting nlink in inocaches
int ret;
int i;
struct jffs2_inode_cache *ic;
+ struct jffs2_full_dirent *dead_fds = NULL;
/* First, scan the medium and build all the inode caches with
lists of physical nodes */
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode(i, c, ic) {
D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
- ret = jffs2_build_inode_pass1(c, ic);
- if (ret) {
- D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
- return ret;
+
+ D1(BUG_ON(ic->ino > c->highest_ino));
+
+ if (ic->scan_dents) {
+ jffs2_build_inode_pass1(c, ic);
+ cond_resched();
}
- cond_resched();
}
D1(printk(KERN_DEBUG "Pass 1 complete\n"));
- D1(jffs2_dump_block_lists(c));
/* Next, scan for inodes with nlink == 0 and remove them. If
they were directories, then decrement the nlink of their
children too, and repeat the scan. As that's going to be
a fairly uncommon occurrence, it's not so evil to do it this
way. Recursion bad. */
- do {
- D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
- ret = 0;
- for_each_inode(i, c, ic) {
- D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
- if (ic->nlink)
- continue;
+ D1(printk(KERN_DEBUG "Pass 2 starting\n"));
+
+ for_each_inode(i, c, ic) {
+ D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
+ if (ic->nlink)
+ continue;
- /* XXX: Can get high latency here. Move the cond_resched() from the end of the loop? */
+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
+ cond_resched();
+ }
- ret = jffs2_build_remove_unlinked_inode(c, ic);
- if (ret)
- break;
- /* -EAGAIN means the inode's nlink was zero, so we deleted it,
- and furthermore that it had children and their nlink has now
- gone to zero too. So we have to restart the scan. */
- }
- D1(jffs2_dump_block_lists(c));
+ D1(printk(KERN_DEBUG "Pass 2a starting\n"));
- cond_resched();
-
- } while(ret == -EAGAIN);
+ while (dead_fds) {
+ struct jffs2_inode_cache *ic;
+ struct jffs2_full_dirent *fd = dead_fds;
+
+ dead_fds = fd->next;
+
+ ic = jffs2_get_ino_cache(c, fd->ino);
+ D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));
+
+ if (ic)
+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
+ jffs2_free_full_dirent(fd);
+ }
D1(printk(KERN_DEBUG "Pass 2 complete\n"));
- /* Finally, we can scan again and free the dirent nodes and scan_info structs */
+ /* Finally, we can scan again and free the dirent structs */
for_each_inode(i, c, ic) {
struct jffs2_full_dirent *fd;
D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
return ret;
}
-int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-{
- struct jffs2_full_dirent *fd;
-
- D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
-
- if (ic->ino > c->highest_ino)
- c->highest_ino = ic->ino;
-
- /* For each child, increase nlink */
- for(fd=ic->scan_dents; fd; fd = fd->next) {
- struct jffs2_inode_cache *child_ic;
- if (!fd->ino)
- continue;
-
- /* XXX: Can get high latency here with huge directories */
-
- child_ic = jffs2_get_ino_cache(c, fd->ino);
- if (!child_ic) {
- printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
- fd->name, fd->ino, ic->ino);
- continue;
- }
-
- if (child_ic->nlink++ && fd->type == DT_DIR) {
- printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
- if (fd->ino == 1 && ic->ino == 1) {
- printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
- printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
- }
- /* What do we do about it? */
- }
- D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
- /* Can't free them. We might need them in pass 2 */
- }
- return 0;
-}
-
-int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
{
struct jffs2_raw_node_ref *raw;
struct jffs2_full_dirent *fd;
- int ret = 0;
D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
jffs2_free_full_dirent(fd);
continue;
}
- jffs2_free_full_dirent(fd);
+
+ /* Reduce nlink of the child. If it's now zero, stick it on the
+ dead_fds list to be cleaned up later. Else just free the fd */
+
child_ic->nlink--;
+
+ if (!child_ic->nlink) {
+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
+ fd->ino, fd->name));
+ fd->next = *dead_fds;
+ *dead_fds = fd;
+ } else {
+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
+ fd->ino, fd->name, child_ic->nlink));
+ jffs2_free_full_dirent(fd);
+ }
}
- ret = -EAGAIN;
}
/*
We don't delete the inocache from the hash list and free it yet.
The erase code will do that, when all the nodes are completely gone.
*/
-
- return ret;
}
static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
- *
* Created by Arjan van de Ven <arjanv@redhat.com>
*
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * University of Szeged, Hungary
+ *
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr.c,v 1.27 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr.c,v 1.41 2004/06/24 09:51:38 havasi Exp $
*
*/
-#if defined(__KERNEL__) || defined (__ECOS)
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#else
-#define KERN_DEBUG
-#define KERN_NOTICE
-#define KERN_WARNING
-#define printk printf
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#endif
+#include "compr.h"
+
+static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED;
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-#include <linux/jffs2.h>
+void jffs2_set_compression_mode(int mode)
+{
+ jffs2_compression_mode = mode;
+}
-int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
+int jffs2_get_compression_mode(void)
+{
+ return jffs2_compression_mode;
+}
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
/* jffs2_compress:
* @data: Pointer to uncompressed data
- * @cdata: Pointer to buffer for compressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
* @datalen: On entry, holds the amount of data available for compression.
* On exit, expected to hold the amount of data actually compressed.
* @cdatalen: On entry, holds the amount of space available for compressed
* data. On exit, expected to hold the actual size of the compressed
* data.
*
- * Returns: Byte to be stored with data indicating compression type used.
+ * Returns: Lower byte to be stored with data indicating compression type used.
* Zero is used to show that the data could not be compressed - the
* compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
*
* If the cdata buffer isn't large enough to hold all the uncompressed data,
* jffs2_compress should compress as much as will fit, and should set
* *datalen accordingly to show the amount of data which were compressed.
*/
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *datalen, uint32_t *cdatalen)
+uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ unsigned char *data_in, unsigned char **cpage_out,
+ uint32_t *datalen, uint32_t *cdatalen)
{
- int ret;
+ int ret = JFFS2_COMPR_NONE;
+ int compr_ret;
+ struct jffs2_compressor *this, *best=NULL;
+ unsigned char *output_buf = NULL, *tmp_buf;
+ uint32_t orig_slen, orig_dlen;
+ uint32_t best_slen=0, best_dlen=0;
- ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_ZLIB;
- }
-#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
- ret = jffs2_dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_DYNRUBIN;
- }
-#endif
-#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */
- ret = jffs2_rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_RUBINMIPS;
- }
-#endif
- /* rtime does manage to recompress already-compressed data */
- ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
- if (!ret) {
- return JFFS2_COMPR_RTIME;
- }
-#if 0
- /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */
- /* If we get here, no compression is going to work */
- /* But we might want to use the fragmentation part -- Arjan */
- memcpy(cpage_out,data_in,min(*datalen,*cdatalen));
- if (*datalen > *cdatalen)
- *datalen = *cdatalen;
-#endif
- return JFFS2_COMPR_NONE; /* We failed to compress */
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_NONE:
+ break;
+ case JFFS2_COMPR_MODE_PRIORITY:
+ output_buf = kmalloc(*cdatalen,GFP_KERNEL);
+ if (!output_buf) {
+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
+ goto out;
+ }
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->usecount--;
+ if (!compr_ret) {
+ ret = this->compr;
+ this->stat_compr_blocks++;
+ this->stat_compr_orig_size += *datalen;
+ this->stat_compr_new_size += *cdatalen;
+ break;
+ }
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
+ break;
+ case JFFS2_COMPR_MODE_SIZE:
+ orig_slen = *datalen;
+ orig_dlen = *cdatalen;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ /* Skip decompress-only backwards-compatibility and disabled modules */
+ if ((!this->compress)||(this->disabled))
+ continue;
+ /* Allocating memory for output buffer if necessary */
+ if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ kfree(this->compr_buf);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->compr_buf_size=0;
+ this->compr_buf=NULL;
+ }
+ if (!this->compr_buf) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
+ spin_lock(&jffs2_compressor_list_lock);
+ if (!tmp_buf) {
+ printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+ continue;
+ }
+ else {
+ this->compr_buf = tmp_buf;
+ this->compr_buf_size = orig_dlen;
+ }
+ }
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ *datalen = orig_slen;
+ *cdatalen = orig_dlen;
+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ this->usecount--;
+ if (!compr_ret) {
+ if ((!best_dlen)||(best_dlen>*cdatalen)) {
+ best_dlen = *cdatalen;
+ best_slen = *datalen;
+ best = this;
+ }
+ }
+ }
+ if (best_dlen) {
+ *cdatalen = best_dlen;
+ *datalen = best_slen;
+ output_buf = best->compr_buf;
+ best->compr_buf = NULL;
+ best->compr_buf_size = 0;
+ best->stat_compr_blocks++;
+ best->stat_compr_orig_size += best_slen;
+ best->stat_compr_new_size += best_dlen;
+ ret = best->compr;
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ break;
+ default:
+ printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+ }
+ out:
+ if (ret == JFFS2_COMPR_NONE) {
+ *cpage_out = data_in;
+ *datalen = *cdatalen;
+ none_stat_compr_blocks++;
+ none_stat_compr_size += *datalen;
+ }
+ else {
+ *cpage_out = output_buf;
+ }
+ return ret;
}
-
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ uint16_t comprtype, unsigned char *cdata_in,
unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
{
- switch (comprtype) {
+ struct jffs2_compressor *this;
+ int ret;
+
+ switch (comprtype & 0xff) {
case JFFS2_COMPR_NONE:
/* This should be special-cased elsewhere, but we might as well deal with it */
memcpy(data_out, cdata_in, datalen);
+ none_stat_decompr_blocks++;
break;
-
case JFFS2_COMPR_ZERO:
memset(data_out, 0, datalen);
break;
+ default:
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (comprtype == this->compr) {
+ this->usecount++;
+ spin_unlock(&jffs2_compressor_list_lock);
+ ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
+ spin_lock(&jffs2_compressor_list_lock);
+ if (ret) {
+ printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
+ }
+ else {
+ this->stat_decompr_blocks++;
+ }
+ this->usecount--;
+ spin_unlock(&jffs2_compressor_list_lock);
+ return ret;
+ }
+ }
+ printk(KERN_WARNING "JFFS2 compression type 0x%02x not avaiable.\n", comprtype);
+ spin_unlock(&jffs2_compressor_list_lock);
+ return -EIO;
+ }
+ return 0;
+}
- case JFFS2_COMPR_ZLIB:
- jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen);
- break;
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+ struct jffs2_compressor *this;
- case JFFS2_COMPR_RTIME:
- jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
- break;
+ if (!comp->name) {
+ printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+ return -1;
+ }
+ comp->compr_buf_size=0;
+ comp->compr_buf=NULL;
+ comp->usecount=0;
+ comp->stat_compr_orig_size=0;
+ comp->stat_compr_new_size=0;
+ comp->stat_compr_blocks=0;
+ comp->stat_decompr_blocks=0;
+ D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+
+ spin_lock(&jffs2_compressor_list_lock);
+
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (this->priority < comp->priority) {
+ list_add(&comp->list, this->list.prev);
+ goto out;
+ }
+ }
+ list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+ })
+
+ spin_unlock(&jffs2_compressor_list_lock);
+
+ return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+ D2(struct jffs2_compressor *this;)
+
+ D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+
+ spin_lock(&jffs2_compressor_list_lock);
+
+ if (comp->usecount) {
+ spin_unlock(&jffs2_compressor_list_lock);
+ printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
+ return -1;
+ }
+ list_del(&comp->list);
+
+ D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+ printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+ })
+ spin_unlock(&jffs2_compressor_list_lock);
+ return 0;
+}
+
+#ifdef CONFIG_JFFS2_PROC
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+ struct jffs2_compressor *this;
+ char *buf, *act_buf;
+
+ act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+ if ((this->disabled)||(!this->compress))
+ act_buf += sprintf(act_buf,"disabled");
+ else
+ act_buf += sprintf(act_buf,"enabled");
+ act_buf += sprintf(act_buf,"\n");
+ }
+ return buf;
+}
+
+char *jffs2_stats(void)
+{
+ struct jffs2_compressor *this;
+ char *buf, *act_buf;
+
+ act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+
+ act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
+ act_buf += sprintf(act_buf,"%10s ","none");
+ act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
+ none_stat_compr_size, none_stat_decompr_blocks);
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ act_buf += sprintf(act_buf,"%10s ",this->name);
+ if ((this->disabled)||(!this->compress))
+ act_buf += sprintf(act_buf,"- ");
+ else
+ act_buf += sprintf(act_buf,"+ ");
+ act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks,
+ this->stat_compr_new_size, this->stat_compr_orig_size,
+ this->stat_decompr_blocks);
+ act_buf += sprintf(act_buf,"\n");
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+
+ return buf;
+}
+
+char *jffs2_get_compression_mode_name(void)
+{
+ switch (jffs2_compression_mode) {
+ case JFFS2_COMPR_MODE_NONE:
+ return "none";
+ case JFFS2_COMPR_MODE_PRIORITY:
+ return "priority";
+ case JFFS2_COMPR_MODE_SIZE:
+ return "size";
+ }
+ return "unkown";
+}
+
+int jffs2_set_compression_mode_name(const char *name)
+{
+ if (!strcmp("none",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+ return 0;
+ }
+ if (!strcmp("priority",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+ return 0;
+ }
+ if (!strcmp("size",name)) {
+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+ return 0;
+ }
+ return 1;
+}
+
+static int jffs2_compressor_Xable(const char *name, int disabled)
+{
+ struct jffs2_compressor *this;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (!strcmp(this->name, name)) {
+ this->disabled = disabled;
+ spin_unlock(&jffs2_compressor_list_lock);
+ return 0;
+ }
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
+ return 1;
+}
+
+int jffs2_enable_compressor_name(const char *name)
+{
+ return jffs2_compressor_Xable(name, 0);
+}
+
+int jffs2_disable_compressor_name(const char *name)
+{
+ return jffs2_compressor_Xable(name, 1);
+}
+
+int jffs2_set_compressor_priority(const char *name, int priority)
+{
+ struct jffs2_compressor *this,*comp;
+ spin_lock(&jffs2_compressor_list_lock);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (!strcmp(this->name, name)) {
+ this->priority = priority;
+ comp = this;
+ goto reinsert;
+ }
+ }
+ spin_unlock(&jffs2_compressor_list_lock);
+ printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
+ return 1;
+reinsert:
+ /* list is sorted in the order of priority, so if
+ we change it we have to reinsert it into the
+ good place */
+ list_del(&comp->list);
+ list_for_each_entry(this, &jffs2_compressor_list, list) {
+ if (this->priority < comp->priority) {
+ list_add(&comp->list, this->list.prev);
+ spin_unlock(&jffs2_compressor_list_lock);
+ return 0;
+ }
+ }
+ list_add_tail(&comp->list, &jffs2_compressor_list);
+ spin_unlock(&jffs2_compressor_list_lock);
+ return 0;
+}
- case JFFS2_COMPR_RUBINMIPS:
-#if 0 /* Disabled 23/9/1 */
- jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
-#else
- printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n");
#endif
- break;
- case JFFS2_COMPR_DYNRUBIN:
-#if 1 /* Phase this one out */
- jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
+
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
+{
+ if (orig != comprbuf)
+ kfree(comprbuf);
+}
+
+int jffs2_compressors_init(void)
+{
+/* Registering compressors */
+#ifdef CONFIG_JFFS2_ZLIB
+ jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+ jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_RUBIN
+ jffs2_rubinmips_init();
+ jffs2_dynrubin_init();
+#endif
+#ifdef CONFIG_JFFS2_LZARI
+ jffs2_lzari_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_init();
+#endif
+/* Setting default compression mode */
+#ifdef CONFIG_JFFS2_CMODE_NONE
+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+ D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
#else
- printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n");
+#ifdef CONFIG_JFFS2_CMODE_SIZE
+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+ D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+#else
+ D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
#endif
- break;
+#endif
+ return 0;
+}
- default:
- printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
- return -EIO;
- }
- return 0;
+int jffs2_compressors_exit(void)
+{
+/* Unregistering compressors */
+#ifdef CONFIG_JFFS2_LZO
+ jffs2_lzo_exit();
+#endif
+#ifdef CONFIG_JFFS2_LZARI
+ jffs2_lzari_exit();
+#endif
+#ifdef CONFIG_JFFS2_RUBIN
+ jffs2_dynrubin_exit();
+ jffs2_rubinmips_exit();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+ jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+ jffs2_zlib_exit();
+#endif
+ return 0;
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
*
*
* Very simple lz77-ish encoder.
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/jffs2.h>
+#include "compr.h"
/* _compress returns the compressed size, -1 if bigger */
int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *sourcelen, uint32_t *dstlen)
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
{
short positions[256];
int outpos = 0;
}
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t srclen, uint32_t destlen)
+int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
{
short positions[256];
int outpos = 0;
outpos+=repeat;
}
}
- }
+ }
+ return 0;
}
+static struct jffs2_compressor jffs2_rtime_comp = {
+ .priority = JFFS2_RTIME_PRIORITY,
+ .name = "rtime",
+ .compr = JFFS2_COMPR_RTIME,
+ .compress = &jffs2_rtime_compress,
+ .decompress = &jffs2_rtime_decompress,
+#ifdef JFFS2_RTIME_DISABLED
+ .disabled = 1,
+#else
+ .disabled = 0,
+#endif
+};
+
+int jffs2_rtime_init(void)
+{
+ return jffs2_register_compressor(&jffs2_rtime_comp);
+}
+void jffs2_rtime_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_rubin.c,v 1.17 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
*
*/
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/jffs2.h>
#include "compr_rubin.h"
#include "histo_mips.h"
-
-
+#include "compr.h"
static void init_rubin(struct rubin_state *rs, int div, int *bits)
{
#if 0
/* _compress returns the compressed size, -1 if bigger */
int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *sourcelen, uint32_t *dstlen)
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
{
return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
}
#endif
int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *sourcelen, uint32_t *dstlen)
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
{
int bits[8];
unsigned char histo[256];
}
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t sourcelen, uint32_t dstlen)
+int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t sourcelen, uint32_t dstlen, void *model)
{
rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
+ return 0;
}
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t sourcelen, uint32_t dstlen)
+int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t sourcelen, uint32_t dstlen, void *model)
{
int bits[8];
int c;
bits[c] = data_in[c];
rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
+ return 0;
+}
+
+static struct jffs2_compressor jffs2_rubinmips_comp = {
+ .priority = JFFS2_RUBINMIPS_PRIORITY,
+ .name = "rubinmips",
+ .compr = JFFS2_COMPR_DYNRUBIN,
+ .compress = NULL, /*&jffs2_rubinmips_compress,*/
+ .decompress = &jffs2_rubinmips_decompress,
+#ifdef JFFS2_RUBINMIPS_DISABLED
+ .disabled = 1,
+#else
+ .disabled = 0,
+#endif
+};
+
+int jffs2_rubinmips_init(void)
+{
+ return jffs2_register_compressor(&jffs2_rubinmips_comp);
+}
+
+void jffs2_rubinmips_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_rubinmips_comp);
+}
+
+static struct jffs2_compressor jffs2_dynrubin_comp = {
+ .priority = JFFS2_DYNRUBIN_PRIORITY,
+ .name = "dynrubin",
+ .compr = JFFS2_COMPR_RUBINMIPS,
+ .compress = jffs2_dynrubin_compress,
+ .decompress = &jffs2_dynrubin_decompress,
+#ifdef JFFS2_DYNRUBIN_DISABLED
+ .disabled = 1,
+#else
+ .disabled = 0,
+#endif
+};
+
+int jffs2_dynrubin_init(void)
+{
+ return jffs2_register_compressor(&jffs2_dynrubin_comp);
+}
+
+void jffs2_dynrubin_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_dynrubin_comp);
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/zlib.h>
#include <linux/zutil.h>
#include <asm/semaphore.h>
#include "nodelist.h"
+#include "compr.h"
/* Plan: call deflate() with avail_in == *sourcelen,
avail_out = *dstlen - 12 and flush == Z_FINISH.
static z_stream inf_strm, def_strm;
#ifdef __KERNEL__ /* Linux-only */
-int __init jffs2_zlib_init(void)
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+static int __init alloc_workspaces(void)
{
def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
if (!def_strm.workspace) {
return 0;
}
-void jffs2_zlib_exit(void)
+static void free_workspaces(void)
{
vfree(def_strm.workspace);
vfree(inf_strm.workspace);
}
+#else
+#define alloc_workspaces() (0)
+#define free_workspaces() do { } while(0)
#endif /* __KERNEL__ */
int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *sourcelen, uint32_t *dstlen)
+ uint32_t *sourcelen, uint32_t *dstlen, void *model)
{
int ret;
return ret;
}
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t srclen, uint32_t destlen)
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+ uint32_t srclen, uint32_t destlen, void *model)
{
int ret;
int wbits = MAX_WBITS;
if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
printk(KERN_WARNING "inflateInit failed\n");
up(&inflate_sem);
- return;
+ return 1;
}
while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
}
zlib_inflateEnd(&inf_strm);
up(&inflate_sem);
+ return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+ .priority = JFFS2_ZLIB_PRIORITY,
+ .name = "zlib",
+ .compr = JFFS2_COMPR_ZLIB,
+ .compress = &jffs2_zlib_compress,
+ .decompress = &jffs2_zlib_decompress,
+#ifdef JFFS2_ZLIB_DISABLED
+ .disabled = 1,
+#else
+ .disabled = 0,
+#endif
+};
+
+int __init jffs2_zlib_init(void)
+{
+ int ret;
+
+ ret = alloc_workspaces();
+ if (ret)
+ return ret;
+
+ ret = jffs2_register_compressor(&jffs2_zlib_comp);
+ if (ret)
+ free_workspaces();
+
+ return ret;
+}
+
+void jffs2_zlib_exit(void)
+{
+ jffs2_unregister_compressor(&jffs2_zlib_comp);
+ free_workspaces();
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: erase.c,v 1.53 2003/10/08 17:22:54 dwmw2 Exp $
+ * $Id: erase.c,v 1.60 2004/06/30 17:26:15 dbrown Exp $
*
*/
#ifndef __ECOS
static void jffs2_erase_callback(struct erase_info *);
#endif
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
int ret;
+ uint32_t bad_offset;
#ifdef __ECOS
ret = jffs2_flash_erase(c, jeb);
if (!ret) {
instr->len = c->sector_size;
instr->callback = jffs2_erase_callback;
instr->priv = (unsigned long)(&instr[1]);
+ instr->fail_addr = 0xffffffff;
((struct erase_priv_struct *)instr->priv)->jeb = jeb;
((struct erase_priv_struct *)instr->priv)->c = c;
- /* NAND , read out the fail counter, if possible */
- if (!jffs2_can_mark_obsolete(c))
- jffs2_nand_read_failcnt(c,jeb);
-
ret = c->mtd->erase(c->mtd, instr);
if (!ret)
return;
+ bad_offset = instr->fail_addr;
kfree(instr);
#endif /* __ECOS */
else
printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
- jffs2_erase_failed(c, jeb);
+ jffs2_erase_failed(c, jeb, bad_offset);
}
-void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
{
struct jffs2_eraseblock *jeb;
spin_unlock(&c->erase_completion_lock);
jffs2_mark_erased_block(c, jeb);
+ if (!--count) {
+ D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n"));
+ goto done;
+ }
+
} else if (!list_empty(&c->erase_pending_list)) {
jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
}
spin_unlock(&c->erase_completion_lock);
+ done:
D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
up(&c->erase_free_sem);
jffs2_erase_pending_trigger(c);
}
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
{
- spin_lock(&c->erase_completion_lock);
- c->erasing_size -= c->sector_size;
- c->bad_size += c->sector_size;
- list_del(&jeb->list);
- list_add(&jeb->list, &c->bad_list);
- c->nr_erasing_blocks--;
- spin_unlock(&c->erase_completion_lock);
- wake_up(&c->erase_wait);
+ /* For NAND, if the failure did not occur at the device level for a
+ specific physical page, don't bother updating the bad block table. */
+ if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
+ /* We had a device-level failure to erase. Let's see if we've
+ failed too many times. */
+ if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
+ /* We'd like to give this block another try. */
+ spin_lock(&c->erase_completion_lock);
+ list_del(&jeb->list);
+ list_add(&jeb->list, &c->erase_pending_list);
+ c->erasing_size -= c->sector_size;
+ c->dirty_size += c->sector_size;
+ jeb->dirty_size = c->sector_size;
+ spin_unlock(&c->erase_completion_lock);
+ return;
+ }
+ }
+
+ spin_lock(&c->erase_completion_lock);
+ c->erasing_size -= c->sector_size;
+ c->bad_size += c->sector_size;
+ list_del(&jeb->list);
+ list_add(&jeb->list, &c->bad_list);
+ c->nr_erasing_blocks--;
+ spin_unlock(&c->erase_completion_lock);
+ wake_up(&c->erase_wait);
}
#ifndef __ECOS
if(instr->state != MTD_ERASE_DONE) {
printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
- jffs2_erase_failed(priv->c, priv->jeb);
+ jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
} else {
jffs2_erase_succeeded(priv->c, priv->jeb);
}
jeb->last_node = NULL;
}
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-{
- OFNI_BS_2SFFJ(c)->s_dirt = 1;
-}
-
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
struct jffs2_raw_node_ref *marker_ref = NULL;
unsigned char *ebuf;
size_t retlen;
int ret;
+ uint32_t bad_offset;
if (!jffs2_cleanmarker_oob(c)) {
marker_ref = jffs2_alloc_raw_node_ref();
uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
int i;
+ bad_offset = ofs;
+
ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
if (ret) {
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
/* It's OK. We know it's properly aligned */
unsigned long datum = *(unsigned long *)(&ebuf[i]);
if (datum + 1) {
- printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
+ bad_offset += i;
+ printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
bad:
if (!jffs2_cleanmarker_oob(c))
jffs2_free_raw_node_ref(marker_ref);
- else
- jffs2_write_nand_badblock( c ,jeb );
kfree(ebuf);
bad2:
spin_lock(&c->erase_completion_lock);
- c->erasing_size -= c->sector_size;
- c->bad_size += c->sector_size;
-
- list_add_tail(&jeb->list, &c->bad_list);
- c->nr_erasing_blocks--;
+ /* Stick it on a list (any list) so
+ erase_failed can take it right off
+ again. Silly, but shouldn't happen
+ often. */
+ list_add(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
- wake_up(&c->erase_wait);
+ jffs2_erase_failed(c, jeb, bad_offset);
return;
}
}
}
kfree(ebuf);
}
-
+
+ bad_offset = jeb->offset;
+
/* Write the erase complete marker */
D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
if (jffs2_cleanmarker_oob(c)) {
.totlen = cpu_to_je32(c->cleanmarker_size)
};
- marker.hdr_crc = cpu_to_je32(crc32(0, &marker, je32_to_cpu(marker.totlen) - 4));
+ marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
- ret = jffs2_flash_write(c, jeb->offset, je32_to_cpu(marker.totlen), &retlen, (char *)&marker);
+ /* We only write the header; the rest was noise or padding anyway */
+ ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
if (ret) {
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
jeb->offset, ret);
goto bad2;
}
- if (retlen != je32_to_cpu(marker.totlen)) {
+ if (retlen != sizeof(marker)) {
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n",
- jeb->offset, je32_to_cpu(marker.totlen), retlen);
+ jeb->offset, sizeof(marker), retlen);
goto bad2;
}
marker_ref->next_in_ino = NULL;
marker_ref->next_phys = NULL;
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
- marker_ref->totlen = PAD(je32_to_cpu(marker.totlen));
+ marker_ref->__totlen = c->cleanmarker_size;
jeb->first_node = jeb->last_node = marker_ref;
- jeb->free_size = c->sector_size - marker_ref->totlen;
- jeb->used_size = marker_ref->totlen;
+ jeb->free_size = c->sector_size - c->cleanmarker_size;
+ jeb->used_size = c->cleanmarker_size;
jeb->dirty_size = 0;
jeb->wasted_size = 0;
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: file.c,v 1.96 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: file.c,v 1.98 2004/03/19 16:41:09 dwmw2 Exp $
*
*/
unsigned char *pg_buf;
int ret;
- D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
+ D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
if (!PageLocked(pg))
PAGE_BUG(pg);
flush_dcache_page(pg);
kunmap(pg);
- D1(printk(KERN_DEBUG "readpage finished\n"));
+ D2(printk(KERN_DEBUG "readpage finished\n"));
return 0;
}
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
struct jffs2_raw_inode *ri;
+ unsigned aligned_start = start & ~3;
int ret = 0;
uint32_t writtenlen = 0;
hurt to do it again. The alternative is ifdefs, which are ugly. */
kmap(pg);
- ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start,
- (pg->index << PAGE_CACHE_SHIFT) + start,
- end - start, &writtenlen);
+ ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
+ (pg->index << PAGE_CACHE_SHIFT) + aligned_start,
+ end - aligned_start, &writtenlen);
kunmap(pg);
/* There was an error writing. */
SetPageError(pg);
}
+
+ /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
+ if (writtenlen < (start&3))
+ writtenlen = 0;
+ else
+ writtenlen -= (start&3);
if (writtenlen) {
if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: fs.c,v 1.32 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: fs.c,v 1.46 2004/07/13 08:56:54 dwmw2 Exp $
*
*/
mdata = kmalloc(f->metadata->size, GFP_USER);
if (!mdata)
return -ENOMEM;
- ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
+ ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
if (ret) {
kfree(mdata);
return ret;
old_metadata = f->metadata;
- if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
- vmtruncate(inode, iattr->ia_size);
+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
- }
if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
jffs2_add_full_dnode_to_inode(c, f, new_metadata);
up(&f->sem);
jffs2_complete_reservation(c);
+ /* We have to do the vmtruncate() without f->sem held, since
+ some pages may be locked and waiting for it in readpage().
+ We are protected from a simultaneous write() extending i_size
+ back past iattr->ia_size, because do_truncate() holds the
+ generic inode semaphore. */
+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
+ vmtruncate(inode, iattr->ia_size);
+
return 0;
}
case S_IFCHR:
/* Read the device numbers from the media */
D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
- if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
+ if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
/* Eep */
printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
up(&f->sem);
struct iattr iattr;
if (!(inode->i_state & I_DIRTY_DATASYNC)) {
- D1(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
+ D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
return;
}
/* We stop if it was running, then restart if it needs to.
This also catches the case where it was stopped and this
- is just a remount to restart it */
- if (!(sb->s_flags & MS_RDONLY))
+ is just a remount to restart it.
+ Flush the writebuffer, if neccecary, else we loose it */
+ if (!(sb->s_flags & MS_RDONLY)) {
jffs2_stop_garbage_collect_thread(c);
+ down(&c->alloc_sem);
+ jffs2_flush_wbuf_pad(c);
+ up(&c->alloc_sem);
+ }
if (!(*flags & MS_RDONLY))
jffs2_start_garbage_collect_thread(c);
D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
jffs2_garbage_collect_trigger(c);
- jffs2_erase_pending_blocks(c);
+ jffs2_erase_pending_blocks(c, 0);
jffs2_flush_wbuf_gc(c, 0);
}
c = JFFS2_SB_INFO(sb);
+#ifndef CONFIG_JFFS2_FS_NAND
+ if (c->mtd->type == MTD_NANDFLASH) {
+ printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
+ return -EINVAL;
+ }
+#endif
+
c->flash_size = c->mtd->size;
/*
* Check, if we have to concatenate physical blocks to larger virtual blocks
* to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
*/
- blocks = c->flash_size / c->mtd->erasesize;
- while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024))
+ c->sector_size = c->mtd->erasesize;
+ blocks = c->flash_size / c->sector_size;
+ while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
blocks >>= 1;
+ c->sector_size <<= 1;
+ }
- c->sector_size = c->flash_size / blocks;
+ /*
+ * Size alignment check
+ */
+ if ((c->sector_size * blocks) != c->flash_size) {
+ c->flash_size = c->sector_size * blocks;
+ printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
+ c->flash_size / 1024);
+ }
+
if (c->sector_size != c->mtd->erasesize)
printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n",
c->mtd->erasesize / 1024, c->sector_size / 1024);
c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
/* Joern -- stick alignment for weird 8-byte-page flash here */
- if (jffs2_cleanmarker_oob(c)) {
- /* NAND (or other bizarre) flash... do setup accordingly */
- ret = jffs2_nand_flash_setup(c);
- if (ret)
- return ret;
- }
+ /* NAND (or other bizarre) flash... do setup accordingly */
+ ret = jffs2_flash_setup(c);
+ if (ret)
+ return ret;
c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
if (!c->inocache_list) {
out_inohash:
kfree(c->inocache_list);
out_wbuf:
- jffs2_nand_flash_cleanup(c);
+ jffs2_flash_cleanup(c);
+
+ return ret;
+}
+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f)
+{
+ iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+ int inum, int nlink)
+{
+ struct inode *inode;
+ struct jffs2_inode_cache *ic;
+ if (!nlink) {
+ /* The inode has zero nlink but its nodes weren't yet marked
+ obsolete. This has to be because we're still waiting for
+ the final (close() and) iput() to happen.
+
+ There's a possibility that the final iput() could have
+ happened while we were contemplating. In order to ensure
+ that we don't cause a new read_inode() (which would fail)
+ for the inode in question, we use ilookup() in this case
+ instead of iget().
+
+ The nlink can't _become_ zero at this point because we're
+ holding the alloc_sem, and jffs2_do_unlink() would also
+ need that while decrementing nlink on any inode.
+ */
+ inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+ if (!inode) {
+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+ inum));
+
+ spin_lock(&c->inocache_lock);
+ ic = jffs2_get_ino_cache(c, inum);
+ if (!ic) {
+ D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+ spin_unlock(&c->inocache_lock);
+ return NULL;
+ }
+ if (ic->state != INO_STATE_CHECKEDABSENT) {
+ /* Wait for progress. Don't just loop */
+ D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
+ ic->ino, ic->state));
+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+ } else {
+ spin_unlock(&c->inocache_lock);
+ }
+
+ return NULL;
+ }
+ } else {
+ /* Inode has links to it still; they're not going away because
+ jffs2_do_unlink() would need the alloc_sem and we have it.
+ Just iget() it, and if read_inode() is necessary that's OK.
+ */
+ inode = iget(OFNI_BS_2SFFJ(c), inum);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ }
+ if (is_bad_inode(inode)) {
+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
+ inum, nlink);
+ /* NB. This will happen again. We need to do something appropriate here. */
+ iput(inode);
+ return ERR_PTR(-EIO);
+ }
+
+ return JFFS2_INODE_INFO(inode);
+}
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f,
+ unsigned long offset,
+ unsigned long *priv)
+{
+ struct inode *inode = OFNI_EDONI_2SFFJ(f);
+ struct page *pg;
+
+ pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
+ (void *)jffs2_do_readpage_unlock, inode);
+ if (IS_ERR(pg))
+ return (void *)pg;
+
+ *priv = (unsigned long)pg;
+ return kmap(pg);
+}
+
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+ unsigned char *ptr,
+ unsigned long *priv)
+{
+ struct page *pg = (void *)*priv;
+
+ kunmap(pg);
+ page_cache_release(pg);
+}
+
+int jffs2_flash_setup(struct jffs2_sb_info *c) {
+ int ret = 0;
+
+ if (jffs2_cleanmarker_oob(c)) {
+ /* NAND flash... do setup accordingly */
+ ret = jffs2_nand_flash_setup(c);
+ if (ret)
+ return ret;
+ }
+ /* add setups for other bizarre flashes here... */
return ret;
}
+
+void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
+
+ if (jffs2_cleanmarker_oob(c)) {
+ jffs2_nand_flash_cleanup(c);
+ }
+
+ /* add cleanups for other bizarre flashes here... */
+}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.114 2003/10/09 13:53:35 dwmw2 Exp $
+ * $Id: gc.c,v 1.136 2004/05/27 19:06:09 gleixner Exp $
*
*/
#include <linux/compiler.h>
#include <linux/stat.h>
#include "nodelist.h"
+#include "compr.h"
static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
struct jffs2_inode_cache *ic,
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
uint32_t start, uint32_t end);
static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic);
+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f);
/* Called with erase_completion_lock held */
static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
nextlist = &c->erasable_list;
} else {
/* Eep. All were empty */
- printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
+ D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
return NULL;
}
*/
int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
{
+ struct jffs2_inode_info *f;
struct jffs2_inode_cache *ic;
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw;
- uint32_t inum;
- int ret = 0;
+ int ret = 0, inum, nlink;
if (down_interruptible(&c->alloc_sem))
return -EINTR;
ic->state = INO_STATE_CHECKING;
spin_unlock(&c->inocache_lock);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino));
+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino));
ret = jffs2_do_crccheck_inode(c, ic);
if (ret)
jeb = jffs2_find_gc_block(c);
if (!jeb) {
- printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
+ D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
spin_unlock(&c->erase_completion_lock);
up(&c->alloc_sem);
return -EIO;
while(ref_obsolete(raw)) {
D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
- jeb->gc_node = raw = raw->next_phys;
- if (!raw) {
+ raw = raw->next_phys;
+ if (unlikely(!raw)) {
printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
+ jeb->gc_node = raw;
spin_unlock(&c->erase_completion_lock);
up(&c->alloc_sem);
BUG();
}
}
+ jeb->gc_node = raw;
+
D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
+
if (!raw->next_in_ino) {
/* Inode-less node. Clean marker, snapshot or something like that */
/* FIXME: If it's something that needs to be copied, including something
up(&c->alloc_sem);
goto eraseit_lock;
}
-
- inum = jffs2_raw_ref_to_inum(raw);
- D1(printk(KERN_DEBUG "Inode number is #%u\n", inum));
+
+ ic = jffs2_raw_ref_to_ic(raw);
+
+ /* We need to hold the inocache. Either the erase_completion_lock or
+ the inocache_lock are sufficient; we trade down since the inocache_lock
+ causes less contention. */
+ spin_lock(&c->inocache_lock);
spin_unlock(&c->erase_completion_lock);
- D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), inum));
+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
/* Three possibilities:
1. Inode is already in-core. We must iget it and do proper
3. Inode is not in-core, node is not pristine. We must iget()
and take the slow path.
*/
- spin_lock(&c->inocache_lock);
- ic = jffs2_get_ino_cache(c, inum);
-
- /* This should never fail unless I'm particularly stupid.
- So we don't check before dereferencing it */
switch(ic->state) {
case INO_STATE_CHECKEDABSENT:
ic->state = INO_STATE_GC;
else {
D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
- inum));
+ ic->ino));
}
break;
case INO_STATE_PRESENT:
- case INO_STATE_UNCHECKED:
- /* It's in-core or hasn't been checked. GC must iget() it. */
+ /* It's in-core. GC must iget() it. */
break;
+ case INO_STATE_UNCHECKED:
case INO_STATE_CHECKING:
+ case INO_STATE_GC:
/* Should never happen. We should have finished checking
- by the time we actually start doing any GC. */
+ by the time we actually start doing any GC, and since
+ we're holding the alloc_sem, no other garbage collection
+ can happen.
+ */
+ printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
+ ic->ino, ic->state);
+ up(&c->alloc_sem);
+ spin_unlock(&c->inocache_lock);
BUG();
-
- case INO_STATE_GC:
- /* Should never happen. We are holding the alloc_sem,
- no other garbage collection can happen. Note that we
- do depend on this later when deciding to do a simple
- node copy */
- BUG();
-
case INO_STATE_READING:
/* Someone's currently trying to read it. We must wait for
them to finish and then go through the full iget() route
up(&c->alloc_sem);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
- inum, ic->state));
+ ic->ino, ic->state));
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
/* And because we dropped the alloc_sem we must start again from the
beginning. Ponder chance of livelock here -- we're returning success
A: Small enough that I don't care :)
*/
return 0;
-
}
- spin_unlock(&c->inocache_lock);
-
/* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
node intact, and we don't have to muck about with the fragtree etc.
because we know it's not in-core. If it _was_ in-core, we go through
all the iget() crap anyway */
if (ic->state == INO_STATE_GC) {
+ spin_unlock(&c->inocache_lock);
+
ret = jffs2_garbage_collect_pristine(c, ic, raw);
- jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
- if (ret != -EBADFD)
+ spin_lock(&c->inocache_lock);
+ ic->state = INO_STATE_CHECKEDABSENT;
+ wake_up(&c->inocache_wq);
+
+ if (ret != -EBADFD) {
+ spin_unlock(&c->inocache_lock);
goto release_sem;
+ }
- /* Fall through if it wanted us to */
+ /* Fall through if it wanted us to, with inocache_lock held */
}
- ret = jffs2_garbage_collect_live(c, jeb, raw, ic);
+ /* Prevent the fairly unlikely race where the gcblock is
+ entirely obsoleted by the final close of a file which had
+ the only valid nodes in the block, followed by erasure,
+ followed by freeing of the ic because the erased block(s)
+ held _all_ the nodes of that inode.... never been seen but
+ it's vaguely possible. */
+
+ inum = ic->ino;
+ nlink = ic->nlink;
+ spin_unlock(&c->inocache_lock);
+
+ f = jffs2_gc_fetch_inode(c, inum, nlink);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ if (!f)
+ return 0;
+
+ ret = jffs2_garbage_collect_live(c, jeb, raw, f);
+
+ jffs2_gc_release_inode(c, f);
release_sem:
up(&c->alloc_sem);
return ret;
}
-
static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f)
{
- struct jffs2_inode_info *f;
struct jffs2_node_frag *frag;
struct jffs2_full_dnode *fn = NULL;
struct jffs2_full_dirent *fd;
uint32_t start = 0, end = 0, nrfrags = 0;
- struct inode *inode;
int ret = 0;
- inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
- if (is_bad_inode(inode)) {
- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
- /* NB. This will happen again. We need to do something appropriate here. */
- up(&c->alloc_sem);
- iput(inode);
- return -EIO;
- }
-
- f = JFFS2_INODE_INFO(inode);
down(&f->sem);
/* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */
+ spin_lock(&c->erase_completion_lock);
+
+ if (c->gcblock != jeb) {
+ spin_unlock(&c->erase_completion_lock);
+ D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));
+ goto upnout;
+ }
if (ref_obsolete(raw)) {
+ spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
/* They'll call again */
goto upnout;
}
+ spin_unlock(&c->erase_completion_lock);
+
/* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */
if (f->metadata && f->metadata->raw == raw) {
fn = f->metadata;
if (frag->node && frag->node->raw == raw) {
fn = frag->node;
end = frag->ofs + frag->size;
-#if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */
- if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) {
- if (fn->frags > 1) {
- printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags);
- mark_ref_normal(raw);
- }
- /* A hole node which isn't multi-page should be garbage-collected
- and merged anyway, so we just check for the frag size here,
- rather than mucking around with actually reading the node
- and checking the compression type, which is the real way
- to tell a hole node. */
- if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE) {
- printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
- ref_offset(raw));
- mark_ref_normal(raw);
- }
-
- if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE) {
- printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
- ref_offset(raw), frag->ofs, frag->ofs+frag->size);
- mark_ref_normal(raw);
- }
- }
-#endif
if (!nrfrags++)
start = frag->ofs;
if (nrfrags == frag->node->frags)
}
if (fn) {
if (ref_flags(raw) == REF_PRISTINE) {
- ret = jffs2_garbage_collect_pristine(c, ic, raw);
+ ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
if (!ret) {
/* Urgh. Return it sensibly. */
- frag->node->raw = ic->nodes;
+ frag->node->raw = f->inocache->nodes;
}
if (ret != -EBADFD)
goto upnout;
}
upnout:
up(&f->sem);
- iput(inode);
return ret;
}
size_t retlen;
int ret;
uint32_t phys_ofs, alloclen;
- uint32_t crc;
+ uint32_t crc, rawlen;
int retried = 0;
D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
+ rawlen = ref_totlen(c, c->gcblock, raw);
+
/* Ask for a small amount of space (or the totlen if smaller) because we
don't want to force wastage of the end of a block if splitting would
work. */
- ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, raw->totlen),
- &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN,
+ rawlen), &phys_ofs, &alloclen);
if (ret)
return ret;
- if (alloclen < raw->totlen) {
+ if (alloclen < rawlen) {
/* Doesn't fit untouched. We'll go the old route and split it */
return -EBADFD;
}
- node = kmalloc(raw->totlen, GFP_KERNEL);
+ node = kmalloc(rawlen, GFP_KERNEL);
if (!node)
return -ENOMEM;
- ret = jffs2_flash_read(c, ref_offset(raw), raw->totlen, &retlen, (char *)node);
- if (!ret && retlen != raw->totlen)
+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
+ if (!ret && retlen != rawlen)
ret = -EIO;
if (ret)
goto out_node;
/* OK, all the CRCs are good; this node can just be copied as-is. */
retry:
nraw->flash_offset = phys_ofs;
- nraw->totlen = raw->totlen;
+ nraw->__totlen = rawlen;
nraw->next_phys = NULL;
- ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node);
+ ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
- if (ret || (retlen != raw->totlen)) {
+ if (ret || (retlen != rawlen)) {
printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
- raw->totlen, phys_ofs, ret, retlen);
+ rawlen, phys_ofs, ret, retlen);
if (retlen) {
/* Doesn't belong to any inode */
nraw->next_in_ino = NULL;
ACCT_SANITY_CHECK(c,jeb);
D1(ACCT_PARANOIA_CHECK(jeb));
- ret = jffs2_reserve_space_gc(c, raw->totlen, &phys_ofs, &dummy);
+ ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
if (!ret) {
D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
return -ENOMEM;
}
- ret = jffs2_read_dnode(c, fn, mdata, 0, mdatalen);
+ ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);
if (ret) {
printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
kfree(mdata);
delete a 'real' dirent with the same name that's still
somewhere else on the flash. */
if (!jffs2_can_mark_obsolete(c)) {
- struct jffs2_raw_dirent rd;
+ struct jffs2_raw_dirent *rd;
struct jffs2_raw_node_ref *raw;
int ret;
size_t retlen;
int name_len = strlen(fd->name);
uint32_t name_crc = crc32(0, fd->name, name_len);
- char *namebuf = NULL;
+ uint32_t rawlen = ref_totlen(c, jeb, fd->raw);
+
+ rd = kmalloc(rawlen, GFP_KERNEL);
+ if (!rd)
+ return -ENOMEM;
/* Prevent the erase code from nicking the obsolete node refs while
we're looking at them. I really don't like this extra lock but
down(&c->erase_free_sem);
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
+
/* We only care about obsolete ones */
if (!(ref_obsolete(raw)))
continue;
+ /* Any dirent with the same name is going to have the same length... */
+ if (ref_totlen(c, NULL, raw) != rawlen)
+ continue;
+
/* Doesn't matter if there's one in the same erase block. We're going to
delete it too at the same time. */
if ((raw->flash_offset & ~(c->sector_size-1)) ==
(fd->raw->flash_offset & ~(c->sector_size-1)))
continue;
- /* This is an obsolete node belonging to the same directory */
- ret = jffs2_flash_read(c, ref_offset(raw), sizeof(struct jffs2_unknown_node), &retlen, (char *)&rd);
+ D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
+
+ /* This is an obsolete node belonging to the same directory, and it's of the right
+ length. We need to take a closer look...*/
+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);
if (ret) {
- printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x\n", ret, ref_offset(raw));
+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));
/* If we can't read it, we don't need to continue to obsolete it. Continue */
continue;
}
- if (retlen != sizeof(struct jffs2_unknown_node)) {
+ if (retlen != rawlen) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n",
- retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw));
+ retlen, rawlen, ref_offset(raw));
continue;
}
- if (je16_to_cpu(rd.nodetype) != JFFS2_NODETYPE_DIRENT ||
- PAD(je32_to_cpu(rd.totlen)) != PAD(sizeof(rd) + name_len))
- continue;
- /* OK, it's a dirent node, it's the right length. We have to take a
- closer look at it... */
- ret = jffs2_flash_read(c, ref_offset(raw), sizeof(rd), &retlen, (char *)&rd);
- if (ret) {
- printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x\n", ret, ref_offset(raw));
- /* If we can't read it, we don't need to continune to obsolete it. Continue */
+ if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)
continue;
- }
- if (retlen != sizeof(rd)) {
- printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading from obsolete node at %08x\n",
- retlen, sizeof(rd), ref_offset(raw));
- continue;
- }
/* If the name CRC doesn't match, skip */
- if (je32_to_cpu(rd.name_crc) != name_crc)
+ if (je32_to_cpu(rd->name_crc) != name_crc)
continue;
+
/* If the name length doesn't match, or it's another deletion dirent, skip */
- if (rd.nsize != name_len || !je32_to_cpu(rd.ino))
+ if (rd->nsize != name_len || !je32_to_cpu(rd->ino))
continue;
/* OK, check the actual name now */
- if (!namebuf) {
- namebuf = kmalloc(name_len + 1, GFP_KERNEL);
- if (!namebuf) {
- up(&c->erase_free_sem);
- return -ENOMEM;
- }
- }
- /* We read the extra byte before it so it's a word-aligned read */
- ret = jffs2_flash_read(c, (ref_offset(raw))+sizeof(rd)-1, name_len+1, &retlen, namebuf);
- if (ret) {
- printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x\n", ret, ref_offset(raw));
- /* If we can't read it, we don't need to continune to obsolete it. Continue */
- continue;
- }
- if (retlen != name_len+1) {
- printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %d) reading name from obsolete node at %08x\n",
- retlen, name_len+1, ref_offset(raw));
- continue;
- }
- if (memcmp(namebuf+1, fd->name, name_len))
+ if (memcmp(rd->name, fd->name, name_len))
continue;
/* OK. The name really does match. There really is still an older node on
the flash which our deletion dirent obsoletes. So we have to write out
a new deletion dirent to replace it */
-
- if (namebuf)
- kfree(namebuf);
-
up(&c->erase_free_sem);
+
+ D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
+ ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
+ kfree(rd);
+
return jffs2_garbage_collect_dirent(c, jeb, f, fd);
}
up(&c->erase_free_sem);
-
- if (namebuf)
- kfree(namebuf);
+ kfree(rd);
}
/* No need for it any more. Just mark it obsolete and remove it from the list */
je32_to_cpu(ri.ino));
});
+ /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
+ mark_ref_normal(new_fn->raw);
+
for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);
frag; frag = frag_next(frag)) {
if (frag->ofs > fn->size + fn->ofs)
uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
int ret = 0;
unsigned char *comprbuf = NULL, *writebuf;
- struct page *pg;
+ unsigned long pg;
unsigned char *pg_ptr;
- /* FIXME: */ struct inode *inode = OFNI_EDONI_2SFFJ(f);
-
+
memset(&ri, 0, sizeof(ri));
D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
* page OK. We'll actually write it out again in commit_write, which is a little
* suboptimal, but at least we're correct.
*/
-#ifdef __ECOS
- pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#else
- pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#endif
- if (IS_ERR(pg)) {
- printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
- return PTR_ERR(pg);
+ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
+
+ if (IS_ERR(pg_ptr)) {
+ printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
+ return PTR_ERR(pg_ptr);
}
- pg_ptr = (char *)kmap(pg);
- comprbuf = kmalloc(end - start, GFP_KERNEL);
offset = start;
while(offset < orig_end) {
uint32_t datalen;
uint32_t cdatalen;
- char comprtype = JFFS2_COMPR_NONE;
+ uint16_t comprtype = JFFS2_COMPR_NONE;
ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
- if (comprbuf) {
- comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
- }
- if (comprtype) {
- writebuf = comprbuf;
- } else {
- datalen = cdatalen;
- }
+ comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
+
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
ri.offset = cpu_to_je32(offset);
ri.csize = cpu_to_je32(cdatalen);
ri.dsize = cpu_to_je32(datalen);
- ri.compr = comprtype;
+ ri.compr = comprtype & 0xff;
+ ri.usercompr = (comprtype >> 8) & 0xff;
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
- ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
+ ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
- new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, ALLOC_GC);
+ new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
+
+ jffs2_free_comprbuf(comprbuf, writebuf);
if (IS_ERR(new_fn)) {
printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
f->metadata = NULL;
}
}
- if (comprbuf) kfree(comprbuf);
- kunmap(pg);
- /* XXX: Does the page get freed automatically? */
- /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
- page_cache_release(pg);
+ jffs2_gc_release_page(c, pg_ptr, &pg);
return ret;
}
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: ioctl.c,v 1.7 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $
*
*/
{
/* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which
will include compression support etc. */
- return -EINVAL;
+ return -ENOTTY;
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: malloc.c,v 1.25 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $
*
*/
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.c,v 1.80 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.86 2003/10/31 15:37:51 dwmw2 Exp $
*
*/
/* Put a new tmp_dnode_info into the list, keeping the list in
order of increasing version
*/
-void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
{
struct jffs2_tmp_dnode_info **prev = list;
cond_resched();
/* FIXME: point() */
- err = jffs2_flash_read(c, (ref_offset(ref)), min_t(uint32_t, ref->totlen, sizeof(node)), &retlen, (void *)&node);
+ err = jffs2_flash_read(c, (ref_offset(ref)),
+ min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
+ &retlen, (void *)&node);
if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
goto free_out;
/* Check we've managed to read at least the common node header */
- if (retlen < min_t(uint32_t, ref->totlen, sizeof(node.u))) {
+ if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO;
goto free_out;
/* If we've never checked the CRCs on this node, check them now. */
if (ref_flags(ref) == REF_UNCHECKED) {
- uint32_t crc;
+ uint32_t crc, len;
struct jffs2_eraseblock *jeb;
crc = crc32(0, &node, sizeof(node.i)-8);
/* Mark the node as having been checked and fix the accounting accordingly */
spin_lock(&c->erase_completion_lock);
jeb = &c->blocks[ref->flash_offset / c->sector_size];
- jeb->used_size += ref->totlen;
- jeb->unchecked_size -= ref->totlen;
- c->used_size += ref->totlen;
- c->unchecked_size -= ref->totlen;
+ len = ref_totlen(c, jeb, ref);
+
+ jeb->used_size += len;
+ jeb->unchecked_size -= len;
+ c->used_size += len;
+ c->unchecked_size -= len;
/* If node covers at least a whole page, or if it starts at the
beginning of a page and runs to the end of the file, or if
default:
if (ref_flags(ref) == REF_UNCHECKED) {
struct jffs2_eraseblock *jeb;
+ uint32_t len;
printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
je16_to_cpu(node.u.nodetype), ref_offset(ref));
/* Mark the node as having been checked and fix the accounting accordingly */
spin_lock(&c->erase_completion_lock);
jeb = &c->blocks[ref->flash_offset / c->sector_size];
- jeb->used_size += ref->totlen;
- jeb->unchecked_size -= ref->totlen;
- c->used_size += ref->totlen;
- c->unchecked_size -= ref->totlen;
+ len = ref_totlen(c, jeb, ref);
+
+ jeb->used_size += len;
+ jeb->unchecked_size -= len;
+ c->used_size += len;
+ c->unchecked_size -= len;
mark_ref_normal(ref);
spin_unlock(&c->erase_completion_lock);
jffs2_free_node_frag(frag);
frag = parent;
+
+ cond_resched();
}
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.h,v 1.104 2003/10/08 11:45:11 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.119 2004/05/26 12:28:12 gleixner Exp $
*
*/
#define D2(x)
#endif
+#define JFFS2_NATIVE_ENDIAN
+
+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
+ whatever OS we're actually running on here too. */
+
+#if defined(JFFS2_NATIVE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){x})
+#define cpu_to_je32(x) ((jint32_t){x})
+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
+
+#define je16_to_cpu(x) ((x).v16)
+#define je32_to_cpu(x) ((x).v32)
+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
+#elif defined(JFFS2_BIG_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (be16_to_cpu(x.v16))
+#define je32_to_cpu(x) (be32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
+#elif defined(JFFS2_LITTLE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (le16_to_cpu(x.v16))
+#define je32_to_cpu(x) (le32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
+#else
+#error wibble
+#endif
+
/*
This is all we need to keep in-core for each raw node during normal
operation. As and when we do read_inode on a particular inode, we can
word so you know when you've got there :) */
struct jffs2_raw_node_ref *next_phys;
uint32_t flash_offset;
- uint32_t totlen;
-
+ uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
+};
+
/* flash_offset & 3 always has to be zero, because nodes are
always aligned at 4 bytes. So we have a couple of extra bits
- to play with. So we set the least significant bit to 1 to
- signify that the node is obsoleted by later nodes.
- */
+ to play with, which indicate the node's status; see below: */
#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */
#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */
#define REF_PRISTINE 2 /* Completely clean. GC without looking */
#define ref_offset(ref) ((ref)->flash_offset & ~3)
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
-};
/*
Used for keeping track of deletion nodes &c, which can only be marked
BUG(); \
} \
if (ref_flags(ref2) == REF_UNCHECKED) \
- my_unchecked_size += ref2->totlen; \
+ my_unchecked_size += ref_totlen(c, jeb, ref2); \
else if (!ref_obsolete(ref2)) \
- my_used_size += ref2->totlen; \
+ my_used_size += ref_totlen(c, jeb, ref2); \
if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
} \
} while(0)
+/* Calculate totlen from surrounding nodes or eraseblock */
+static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
+ struct jffs2_eraseblock *jeb,
+ struct jffs2_raw_node_ref *ref)
+{
+ uint32_t ref_end;
+
+ if (ref->next_phys)
+ ref_end = ref_offset(ref->next_phys);
+ else {
+ if (!jeb)
+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
+
+ /* Last node in block. Use free_space */
+ BUG_ON(ref != jeb->last_node);
+ ref_end = jeb->offset + c->sector_size - jeb->free_size;
+ }
+ return ref_end - ref_offset(ref);
+}
+
+static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
+ struct jffs2_eraseblock *jeb,
+ struct jffs2_raw_node_ref *ref)
+{
+ uint32_t ret;
+
+ D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
+ printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
+ jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
+ BUG();
+ })
+
+#if 1
+ ret = ref->__totlen;
+#else
+ /* This doesn't actually work yet */
+ ret = __ref_totlen(c, jeb, ref);
+ if (ret != ref->__totlen) {
+ printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
+ ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
+ ret, ref->__totlen);
+ if (!jeb)
+ jeb = &c->blocks[ref->flash_offset / c->sector_size];
+ paranoia_failed_dump(jeb);
+ BUG();
+ }
+#endif
+ return ret;
+}
+
+
#define ALLOC_NORMAL 0 /* Normal allocation */
#define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
#define ALLOC_GC 2 /* Space requested for GC. Give it or die */
#define PAD(x) (((x)+3)&~3)
-static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
+static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw)
{
while(raw->next_in_ino) {
raw = raw->next_in_ino;
}
- return ((struct jffs2_inode_cache *)raw)->ino;
+ return ((struct jffs2_inode_cache *)raw);
}
static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
/* nodelist.c */
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
-void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
uint32_t *highest_version, uint32_t *latest_mctime,
void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
/* nodemgmt.c */
+int jffs2_thread_should_wake(struct jffs2_sb_info *c);
int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
/* read.c */
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len);
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ struct jffs2_full_dnode *fd, unsigned char *buf,
+ int ofs, int len);
int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned char *buf, uint32_t offset, uint32_t len);
char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
-
-/* compr.c */
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
- uint32_t *datalen, uint32_t *cdatalen);
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
- unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-
/* scan.c */
int jffs2_scan_medium(struct jffs2_sb_info *c);
void jffs2_rotate_lists(struct jffs2_sb_info *c);
/* erase.c */
void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
#ifdef CONFIG_JFFS2_FS_NAND
/* wbuf.c */
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
#endif
-/* compr_zlib.c */
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-
#endif /* __JFFS2_NODELIST_H__ */
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodemgmt.c,v 1.102 2003/10/08 17:21:19 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $
*
*/
if (list_empty(&c->free_list)) {
- DECLARE_WAITQUEUE(wait, current);
-
if (!c->nr_erasing_blocks &&
!list_empty(&c->erasable_list)) {
struct jffs2_eraseblock *ejeb;
list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
return -ENOSPC;
}
- /* Make sure this can't deadlock. Someone has to start the erases
- of erase_pending blocks */
-#ifdef __ECOS
- /* In eCos, we don't have a handy kernel thread doing the erases for
- us. We do them ourselves right now. */
- jffs2_erase_pending_blocks(c);
-#else
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&c->erase_wait, &wait);
- D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
- c->nr_erasing_blocks, list_empty(&c->erasable_list)?"yes":"no",
- list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
- if (!list_empty(&c->erase_pending_list)) {
- D1(printk(KERN_DEBUG "Triggering pending erases\n"));
- jffs2_erase_pending_trigger(c);
- }
+
spin_unlock(&c->erase_completion_lock);
- schedule();
- remove_wait_queue(&c->erase_wait, &wait);
+ /* Don't wait for it; just erase one right now */
+ jffs2_erase_pending_blocks(c, 1);
spin_lock(&c->erase_completion_lock);
- if (signal_pending(current)) {
- return -EINTR;
- }
-#endif
+
/* An erase may have failed, decreasing the
amount of free space available. So we must
restart from the beginning */
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
{
struct jffs2_eraseblock *jeb;
- uint32_t len = new->totlen;
+ uint32_t len;
jeb = &c->blocks[new->flash_offset / c->sector_size];
+ len = ref_totlen(c, jeb, new);
+
D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
#if 1
if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
spin_lock(&c->erase_completion_lock);
if (ref_flags(ref) == REF_UNCHECKED) {
- D1(if (unlikely(jeb->unchecked_size < ref->totlen)) {
+ D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
- ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
- D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
- jeb->unchecked_size -= ref->totlen;
- c->unchecked_size -= ref->totlen;
+ D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
+ jeb->unchecked_size -= ref_totlen(c, jeb, ref);
+ c->unchecked_size -= ref_totlen(c, jeb, ref);
} else {
- D1(if (unlikely(jeb->used_size < ref->totlen)) {
+ D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
- ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
- D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
- jeb->used_size -= ref->totlen;
- c->used_size -= ref->totlen;
+ D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
+ jeb->used_size -= ref_totlen(c, jeb, ref);
+ c->used_size -= ref_totlen(c, jeb, ref);
}
// Take care, that wasted size is taken into concern
- if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
+ if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
D1(printk("Dirtying\n"));
- addedsize = ref->totlen;
- jeb->dirty_size += ref->totlen;
- c->dirty_size += ref->totlen;
+ addedsize = ref_totlen(c, jeb, ref);
+ jeb->dirty_size += ref_totlen(c, jeb, ref);
+ c->dirty_size += ref_totlen(c, jeb, ref);
/* Convert wasted space to dirty, if not a bad block */
if (jeb->wasted_size) {
} else {
D1(printk("Wasting\n"));
addedsize = 0;
- jeb->wasted_size += ref->totlen;
- c->wasted_size += ref->totlen;
+ jeb->wasted_size += ref_totlen(c, jeb, ref);
+ c->wasted_size += ref_totlen(c, jeb, ref);
}
ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
if (jffs2_wbuf_dirty(c)) {
D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
-#if 0 /* This check was added to allow us to find places where we added nodes to the lists
- after dropping the alloc_sem, and it did that just fine. But it also caused us to
- lock the alloc_sem in other places, like clear_inode(), when we wouldn't otherwise
- have needed to. So I suspect it's outlived its usefulness. Thomas? */
-
- /* We've changed the rules slightly. After
- writing a node you now mustn't drop the
- alloc_sem before you've finished all the
- list management - this is so that when we
- get here, we know that no other nodes have
- been written, and the above check on wbuf
- is valid - wbuf_len is nonzero IFF the node
- which obsoletes this node is still in the
- wbuf.
-
- So we BUG() if that new rule is broken, to
- make sure we catch it and fix it.
- */
- if (!down_trylock(&c->alloc_sem)) {
- up(&c->alloc_sem);
- printk(KERN_CRIT "jffs2_mark_node_obsolete() called with wbuf active but alloc_sem not locked!\n");
- BUG();
- }
-#endif
} else {
if (jiffies & 127) {
/* Most of the time, we just erase it immediately. Otherwise we
printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
return;
}
- if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) {
- printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref->totlen);
+ if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
+ printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
return;
}
if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
- D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
+ D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
return;
}
/* XXX FIXME: This is ugly now */
}
}
#endif /* CONFIG_JFFS2_FS_DEBUG */
+
+int jffs2_thread_should_wake(struct jffs2_sb_info *c)
+{
+ int ret = 0;
+ uint32_t dirty;
+
+ if (c->unchecked_size) {
+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
+ c->unchecked_size, c->checked_ino));
+ return 1;
+ }
+
+ /* dirty_size contains blocks on erase_pending_list
+ * those blocks are counted in c->nr_erasing_blocks.
+ * If one block is actually erased, it is not longer counted as dirty_space
+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
+ * with c->nr_erasing_blocks * c->sector_size again.
+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
+ * This helps us to force gc and pick eventually a clean block to spread the load.
+ */
+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
+
+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
+ (dirty > c->nospc_dirty_size))
+ ret = 1;
+
+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+
+ return ret;
+}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: os-linux.h,v 1.37 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.47 2004/07/14 13:20:23 dwmw2 Exp $
*
*/
#define kstatfs statfs
#endif
+struct kstatfs;
+struct kvec;
+
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
#endif
-/* Hmmm. P'raps generic code should only ever see versions of signal
- functions which do the locking automatically? */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) && !defined(__rh_config_h__)
-#define current_sig_lock current->sigmask_lock
-#else
-#define current_sig_lock current->sighand->siglock
-#endif
-
#define sleep_on_spinunlock(wq, s) \
do { \
DECLARE_WAITQUEUE(__wait, current); \
#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
-#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
-#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
+#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
#define jffs2_nand_flash_setup(c) (0)
#define jffs2_nand_flash_cleanup(c) do {} while(0)
#define jffs2_wbuf_dirty(c) (0)
#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
-struct kstatfs;
-struct kvec;
/* wbuf.c */
int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
void jffs2_wbuf_timeout(unsigned long data);
void jffs2_wbuf_process(void *data);
int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
#endif /* NAND */
+/* erase.c */
+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
+{
+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
+}
+
/* background.c */
int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_write_super (struct super_block *);
int jffs2_remount_fs (struct super_block *, int *, char *);
int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f);
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+ int inum, int nlink);
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f,
+ unsigned long offset,
+ unsigned long *priv);
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+ unsigned char *pg,
+ unsigned long *priv);
+int jffs2_flash_setup(struct jffs2_sb_info *c);
+void jffs2_flash_cleanup(struct jffs2_sb_info *c);
+
/* writev.c */
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
-/* super.c */
-
#endif /* __JFFS2_OS_LINUX_H__ */
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
*
*/
#include <linux/mtd/mtd.h>
#include <linux/compiler.h>
#include "nodelist.h"
+#include "compr.h"
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ struct jffs2_full_dnode *fd, unsigned char *buf,
+ int ofs, int len)
{
struct jffs2_raw_inode *ri;
size_t readlen;
if (ri->compr != JFFS2_COMPR_NONE) {
D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
- ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
+ ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
if (ret) {
printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
goto out_decomprbuf;
D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
frag->ofs+fragofs, frag->ofs+fragofs+readlen,
ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
- ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
+ ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
D2(printk(KERN_DEBUG "node read done\n"));
if (ret) {
D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
}
buf[f->metadata->size]=0;
- ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size);
+ ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
up(&f->sem);
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: readinode.c,v 1.107 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: readinode.c,v 1.113 2003/11/03 13:20:33 dwmw2 Exp $
*
*/
printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
}
}
+
+static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
+{
+ struct jffs2_node_frag *frag;
+ int bitched = 0;
+
+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
+
+ struct jffs2_full_dnode *fn = frag->node;
+ if (!fn || !fn->raw)
+ continue;
+
+ if (ref_flags(fn->raw) == REF_PRISTINE) {
+
+ if (fn->frags > 1) {
+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags);
+ bitched = 1;
+ }
+ /* A hole node which isn't multi-page should be garbage-collected
+ and merged anyway, so we just check for the frag size here,
+ rather than mucking around with actually reading the node
+ and checking the compression type, which is the real way
+ to tell a hole node. */
+ if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
+ ref_offset(fn->raw));
+ bitched = 1;
+ }
+
+ if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
+ ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
+ bitched = 1;
+ }
+ }
+ }
+
+ if (bitched) {
+ struct jffs2_node_frag *thisfrag;
+
+ printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino);
+ thisfrag = frag_first(&f->fragtree);
+ while (thisfrag) {
+ if (!thisfrag->node) {
+ printk("Frag @0x%x-0x%x; node-less hole\n",
+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
+ } else if (!thisfrag->node->raw) {
+ printk("Frag @0x%x-0x%x; raw-less hole\n",
+ thisfrag->ofs, thisfrag->size + thisfrag->ofs);
+ } else {
+ printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n",
+ thisfrag->ofs, thisfrag->size + thisfrag->ofs,
+ ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw),
+ thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size);
+ }
+ thisfrag = frag_next(thisfrag);
+ }
+ }
+ return bitched;
+}
#endif /* D1 */
static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
mark_ref_normal(next->node->raw);
}
}
+ D2(if (jffs2_sanitycheck_fragtree(f)) {
+ printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n",
+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
+ return 0;
+ })
D2(jffs2_print_frag_list(f));
return 0;
}
}
}
spin_unlock(&c->inocache_lock);
+
if (!f->inocache && ino == 1) {
/* Special case - no root inode on medium */
f->inocache = jffs2_alloc_inode_cache();
fn = tn->fn;
if (f->metadata) {
- if (tn->version > mdata_ver) {
+ if (likely(tn->version >= mdata_ver)) {
D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
jffs2_mark_node_obsolete(c, f->metadata->raw);
jffs2_free_full_dnode(f->metadata);
mdata_ver = 0;
} else {
- D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n",
- ref_offset(f->metadata->raw), tn->version, mdata_ver));
+ /* This should never happen. */
+ printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n",
+ ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw));
jffs2_mark_node_obsolete(c, fn->raw);
jffs2_free_full_dnode(fn);
+ /* Fill in latest_node from the metadata, not this one we're about to free... */
+ fn = f->metadata;
goto next_tn;
}
}
tn_list = tn->next;
jffs2_free_tmp_dnode_info(tn);
}
+ D1(jffs2_sanitycheck_fragtree(f));
+
if (!fn) {
/* No data nodes for this inode. */
if (f->inocache->ino != 1) {
void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
{
struct jffs2_full_dirent *fd, *fds;
- /* I don't think we care about the potential race due to reading this
- without f->sem. It can never get undeleted. */
- int deleted = f->inocache && !f->inocache->nlink;
-
- /* If it's a deleted inode, grab the alloc_sem. This prevents
- jffs2_garbage_collect_pass() from deciding that it wants to
- garbage collect one of the nodes we're just about to mark
- obsolete -- by the time we drop alloc_sem and return, all
- the nodes are marked obsolete, and jffs2_g_c_pass() won't
- call iget() for the inode in question.
-
- We also used to do this to keep the temporary BUG() in
- jffs2_mark_node_obsolete() from triggering.
- */
- if(deleted)
- down(&c->alloc_sem);
+ int deleted;
down(&f->sem);
+ deleted = f->inocache && !f->inocache->nlink;
if (f->metadata) {
if (deleted)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
up(&f->sem);
-
- if(deleted)
- up(&c->alloc_sem);
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: scan.c,v 1.104 2003/10/11 14:52:48 dwmw2 Exp $
+ * $Id: scan.c,v 1.110 2004/06/17 17:15:31 gleixner Exp $
*
*/
#include <linux/kernel.h>
uint32_t hdr_crc, buf_ofs, buf_len;
int err;
int noise = 0;
- int wasempty = 0;
- uint32_t empty_start = 0;
#ifdef CONFIG_JFFS2_FS_NAND
int cleanmarkerfound = 0;
#endif
switch (ret) {
case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
case 1: return BLK_STATE_ALLDIRTY;
- case 2: return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */
- case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
default: return ret;
}
}
noise = 10;
+scan_more:
while(ofs < jeb->offset + c->sector_size) {
D1(ACCT_PARANOIA_CHECK(jeb));
node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
- uint32_t inbuf_ofs = ofs - buf_ofs + 4;
- uint32_t scanend;
+ uint32_t inbuf_ofs;
+ uint32_t empty_start;
empty_start = ofs;
ofs += 4;
- /* If scanning empty space after only a cleanmarker, don't
- bother scanning the whole block */
- if (unlikely(empty_start == jeb->offset + c->cleanmarker_size &&
- jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len))
- scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs;
- else
- scanend = buf_len;
-
D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
- while (inbuf_ofs < scanend) {
- if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
- goto emptyends;
+ more_empty:
+ inbuf_ofs = ofs - buf_ofs;
+ while (inbuf_ofs < buf_len) {
+ if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
+ printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
+ empty_start, ofs);
+ DIRTY_SPACE(ofs-empty_start);
+ goto scan_more;
+ }
inbuf_ofs+=4;
ofs += 4;
}
/* Ran off end. */
- D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
+ D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));
- if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
- c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size)
+ /* If we're only checking the beginning of a block with a cleanmarker,
+ bail now */
+ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
+ c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
+ D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
return BLK_STATE_CLEANMARKER;
- wasempty = 1;
- continue;
- } else if (wasempty) {
- emptyends:
- printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
- DIRTY_SPACE(ofs-empty_start);
- wasempty = 0;
- continue;
+ }
+
+ /* See how much more there is to read in this eraseblock... */
+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+ if (!buf_len) {
+ /* No more to read. Break out of main loop without marking
+ this range of empty space as dirty (because it's not) */
+ D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
+ empty_start));
+ break;
+ }
+ D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+ if (err)
+ return err;
+ buf_ofs = ofs;
+ goto more_empty;
}
if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
marker_ref->next_in_ino = NULL;
marker_ref->next_phys = NULL;
marker_ref->flash_offset = ofs | REF_NORMAL;
- marker_ref->totlen = c->cleanmarker_size;
+ marker_ref->__totlen = c->cleanmarker_size;
jeb->first_node = jeb->last_node = marker_ref;
USED_SPACE(PAD(c->cleanmarker_size));
}
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
- && (!jeb->first_node || jeb->first_node->next_in_ino) )
+ && (!jeb->first_node || !jeb->first_node->next_in_ino) )
return BLK_STATE_CLEANMARKER;
/* move blocks with max 4 byte dirty space to cleanlist */
if (ic)
return ic;
+ if (ino > c->highest_ino)
+ c->highest_ino = ino;
+
ic = jffs2_alloc_inode_cache();
if (!ic) {
printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n");
ic->nodes = (void *)ic;
jffs2_add_ino_cache(c, ic);
if (ino == 1)
- ic->nlink=1;
+ ic->nlink = 1;
return ic;
}
/* Wheee. It worked */
raw->flash_offset = ofs | REF_UNCHECKED;
- raw->totlen = PAD(je32_to_cpu(ri->totlen));
+ raw->__totlen = PAD(je32_to_cpu(ri->totlen));
raw->next_phys = NULL;
raw->next_in_ino = ic->nodes;
return -ENOMEM;
}
- raw->totlen = PAD(je32_to_cpu(rd->totlen));
+ raw->__totlen = PAD(je32_to_cpu(rd->totlen));
raw->flash_offset = ofs | REF_PRISTINE;
raw->next_phys = NULL;
raw->next_in_ino = ic->nodes;
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: super.c,v 1.96 2004/07/13 08:57:30 dwmw2 Exp $
*
*/
#include <linux/mtd/mtd.h>
#include <linux/ctype.h>
#include <linux/namei.h>
+#include "compr.h"
#include "nodelist.h"
static void jffs2_put_super(struct super_block *);
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
kfree(c->blocks);
- jffs2_nand_flash_cleanup(c);
+ jffs2_flash_cleanup(c);
kfree(c->inocache_list);
if (c->mtd->sync)
c->mtd->sync(c->mtd);
int ret;
printk(KERN_INFO "JFFS2 version 2.2."
-#ifdef CONFIG_FS_JFFS2_NAND
+#ifdef CONFIG_JFFS2_FS_NAND
" (NAND)"
#endif
" (C) 2001-2003 Red Hat, Inc.\n");
printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
return -ENOMEM;
}
- ret = jffs2_zlib_init();
+#ifdef CONFIG_JFFS2_PROC
+ ret = jffs2_proc_init();
if (ret) {
- printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+ printk(KERN_ERR "JFFS2 error: Failed to initialise proc interface\n");
+ goto out;
+ }
+#endif
+ ret = jffs2_compressors_init();
+ if (ret) {
+ printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
goto out;
}
ret = jffs2_create_slab_caches();
if (ret) {
printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
- goto out_zlib;
+ goto out_compressors;
}
ret = register_filesystem(&jffs2_fs_type);
if (ret) {
out_slab:
jffs2_destroy_slab_caches();
- out_zlib:
- jffs2_zlib_exit();
+ out_compressors:
+ jffs2_compressors_exit();
+#ifdef CONFIG_JFFS2_PROC
+ jffs2_proc_exit();
+#endif
out:
return ret;
}
{
unregister_filesystem(&jffs2_fs_type);
jffs2_destroy_slab_caches();
- jffs2_zlib_exit();
+ jffs2_compressors_exit();
+#ifdef CONFIG_JFFS2_PROC
+ jffs2_proc_exit();
+#endif
kmem_cache_destroy(jffs2_inode_cachep);
}
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $
+ * $Id: symlink.c,v 1.13 2004/07/13 08:59:04 dwmw2 Exp $
*
*/
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
*
* Created by David Woodhouse <dwmw2@redhat.com>
+ * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: wbuf.c,v 1.53 2003/10/11 11:46:09 dwmw2 Exp $
+ * $Id: wbuf.c,v 1.70 2004/07/13 08:58:25 dwmw2 Exp $
*
*/
#endif
/* max. erase failures before we mark a block bad */
-#define MAX_ERASE_FAILURES 5
+#define MAX_ERASE_FAILURES 2
/* two seconds timeout for timed wbuf-flushing */
#define WBUF_FLUSH_TIMEOUT 2 * HZ
first_raw = &jeb->first_node;
while (*first_raw &&
(ref_obsolete(*first_raw) ||
- (ref_offset(*first_raw) + (*first_raw)->totlen) < c->wbuf_ofs)) {
+ (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
ref_offset(*first_raw), ref_flags(*first_raw),
- (ref_offset(*first_raw) + (*first_raw)->totlen),
+ (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)),
c->wbuf_ofs));
first_raw = &(*first_raw)->next_phys;
}
}
start = ref_offset(*first_raw);
- end = ref_offset(*first_raw) + (*first_raw)->totlen;
+ end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw);
/* Find the last node to be recovered */
raw = first_raw;
while ((*raw)) {
if (!ref_obsolete(*raw))
- end = ref_offset(*raw) + (*raw)->totlen;
+ end = ref_offset(*raw) + ref_totlen(c, jeb, *raw);
raw = &(*raw)->next_phys;
}
return;
raw2->flash_offset = ofs | REF_OBSOLETE;
- raw2->totlen = (*first_raw)->totlen;
+ raw2->__totlen = ref_totlen(c, jeb, *first_raw);
raw2->next_phys = NULL;
raw2->next_in_ino = NULL;
raw = first_raw;
while (*raw) {
+ uint32_t rawlen = ref_totlen(c, jeb, *raw);
+
D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
- (*raw)->totlen, ref_offset(*raw), ref_flags(*raw), ofs));
+ rawlen, ref_offset(*raw), ref_flags(*raw), ofs));
if (ref_obsolete(*raw)) {
/* Shouldn't really happen much */
- new_jeb->dirty_size += (*raw)->totlen;
- new_jeb->free_size -= (*raw)->totlen;
- c->dirty_size += (*raw)->totlen;
+ new_jeb->dirty_size += rawlen;
+ new_jeb->free_size -= rawlen;
+ c->dirty_size += rawlen;
} else {
- new_jeb->used_size += (*raw)->totlen;
- new_jeb->free_size -= (*raw)->totlen;
- jeb->dirty_size += (*raw)->totlen;
- jeb->used_size -= (*raw)->totlen;
- c->dirty_size += (*raw)->totlen;
+ new_jeb->used_size += rawlen;
+ new_jeb->free_size -= rawlen;
+ jeb->dirty_size += rawlen;
+ jeb->used_size -= rawlen;
+ c->dirty_size += rawlen;
}
- c->free_size -= (*raw)->totlen;
+ c->free_size -= rawlen;
(*raw)->flash_offset = ofs | ref_flags(*raw);
- ofs += (*raw)->totlen;
+ ofs += rawlen;
new_jeb->last_node = *raw;
raw = &(*raw)->next_phys;
padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
+ } else {
+ /* Pad with JFFS2_DIRTY_BITMASK */
+ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
}
}
/* else jffs2_flash_writev has actually filled in the rest of the
return ret;
}
- /* Adjusting free size of next block only, if it's called from fsync ! */
- if (pad == 2) {
- D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n"));
- spin_lock(&c->erase_completion_lock);
- if (!c->nextblock)
- BUG();
+ spin_lock(&c->erase_completion_lock);
+
+ /* Adjust free size of the block if we padded. */
+ if (pad) {
+ struct jffs2_eraseblock *jeb;
+
+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
+ (jeb==c->nextblock)?"next":"", jeb->offset));
+
/* wbuf_pagesize - wbuf_len is the amount of space that's to be
padded. If there is less free space in the block than that,
something screwed up */
- if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
+ if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
- c->nextblock->offset, c->nextblock->free_size);
+ jeb->offset, jeb->free_size);
BUG();
}
- c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len);
+ jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len);
c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
- c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
+ jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
- spin_unlock(&c->erase_completion_lock);
}
/* Stick any now-obsoleted blocks on the erase_pending_list */
- spin_lock(&c->erase_completion_lock);
jffs2_refile_wbuf_blocks(c);
jffs2_clear_wbuf_ino_list(c);
spin_unlock(&c->erase_completion_lock);
old_wbuf_ofs = c->wbuf_ofs;
old_wbuf_len = c->wbuf_len;
- while (old_wbuf_len &&
- old_wbuf_ofs == c->wbuf_ofs) {
+ if (c->unchecked_size) {
+ /* GC won't make any progress for a while */
+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
+ ret = __jffs2_flush_wbuf(c, 2);
+ } else while (old_wbuf_len &&
+ old_wbuf_ofs == c->wbuf_ofs) {
up(&c->alloc_sem);
size_t retlen;
int oob_size;
- oob_size = c->mtd->oobsize;
-
/* allocate a buffer for all oob data in this sector */
+ oob_size = c->mtd->oobsize;
len = 4 * oob_size;
buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
goto out;
}
- /* Special check for first two pages */
- for (page = 0; page < 2 * oob_size; page += oob_size) {
- /* Check for bad block marker */
- if (buf[page+c->badblock_pos] != 0xff) {
- D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
- /* Return 2 for bad and 3 for failed block
- bad goes to list_bad and failed to list_erase */
- ret = (!page) ? 2 : 3;
+ /* Special check for first page */
+ for(i = 0; i < oob_size ; i++) {
+ /* Yeah, we know about the cleanmarker. */
+ if (mode && i >= c->fsdata_pos &&
+ i < c->fsdata_pos + c->fsdata_len)
+ continue;
+
+ if (buf[i] != 0xFF) {
+ D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
+ buf[page+i], page+i, jeb->offset));
+ ret = 1;
goto out;
}
- for(i = 0; i < oob_size ; i++) {
- /* Yeah, we know about the cleanmarker. */
- if (mode && i >= c->fsdata_pos &&
- i < c->fsdata_pos+c->fsdata_len)
- continue;
-
- if (buf[page+i] != 0xFF) {
- D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
- buf[page+i], page+i, jeb->offset));
- ret = 1;
- goto out;
- }
- }
- /* only the first page can contain a cleanmarker !*/
- mode = 0;
- }
+ }
/* we know, we are aligned :) */
- for (; page < len; page += sizeof(long)) {
+ for (page = oob_size; page < len; page += sizeof(long)) {
unsigned long dat = *(unsigned long *)(&buf[page]);
if(dat != -1) {
ret = 1;
int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
struct jffs2_unknown_node n;
- unsigned char buf[32];
+ unsigned char buf[2 * NAND_MAX_OOBSIZE];
unsigned char *p;
int ret, i, cnt, retval = 0;
size_t retlen, offset;
/* Loop through the physical blocks */
for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
+ /* Check first if the block is bad. */
+ if (c->mtd->block_isbad (c->mtd, offset)) {
+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+ return 2;
+ }
/*
* We read oob data from page 0 and 1 of the block.
* page 0 contains cleanmarker and badblock info
return -EIO;
}
- /* Check for bad block marker */
- if (buf[c->badblock_pos] != 0xff) {
- D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n",
- jeb->offset, buf[c->badblock_pos], buf[c->badblock_pos + oob_size], c->badblock_pos));
- return 2;
- }
-
- /* Check for failure counter in the second page */
- if (buf[c->badblock_pos + oob_size] != 0xff) {
- D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size]));
- return 3;
- }
-
/* Check cleanmarker only on the first physical block */
if (!cnt) {
n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
}
/*
- * We try to get the failure count of this block.
- */
-int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-
- unsigned char buf[16];
- int ret;
- size_t retlen;
- int oob_size;
-
- oob_size = c->mtd->oobsize;
-
- ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf);
-
- if (ret) {
- D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
- return ret;
- }
-
- if (retlen < oob_size) {
- D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset));
- return -EIO;
- }
-
- jeb->bad_count = buf[c->badblock_pos];
- return 0;
-}
-
-/*
- * On NAND we try to mark this block bad. We try to write how often
- * the block was erased and mark it finaly bad, if the count
- * is > MAX_ERASE_FAILURES. We read this information on mount !
- * jeb->bad_count contains the count before this erase.
+ * On NAND we try to mark this block bad. If the block was erased more
+ * than MAX_ERASE_FAILURES we mark it finaly bad.
* Don't care about failures. This block remains on the erase-pending
* or badblock list as long as nobody manipulates the flash with
* a bootloader or something like that.
*/
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
{
- unsigned char buf = 0x0;
int ret;
- size_t retlen;
/* if the count is < max, we try to write the counter to the 2nd page oob area */
- if( ++jeb->bad_count < MAX_ERASE_FAILURES) {
- buf = (unsigned char)jeb->bad_count;
- c->badblock_pos += c->mtd->oobblock;
- }
-
- ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf);
+ if( ++jeb->bad_count < MAX_ERASE_FAILURES)
+ return 0;
+
+ if (!c->mtd->block_markbad)
+ return 1; // What else can we do?
+
+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
+ ret = c->mtd->block_markbad(c->mtd, bad_offset);
if (ret) {
D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
return ret;
}
- if (retlen != 1) {
- D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen));
- return ret;
- }
- return 0;
+ return 1;
}
-#define JFFS2_OOB_ECCPOS0 0
-#define JFFS2_OOB_ECCPOS1 1
-#define JFFS2_OOB_ECCPOS2 2
-#define JFFS2_OOB_ECCPOS3 3
-#define JFFS2_OOB_ECCPOS4 6
-#define JFFS2_OOB_ECCPOS5 7
-
-#define NAND_JFFS2_OOB8_FSDAPOS 6
-#define NAND_JFFS2_OOB16_FSDAPOS 8
-#define NAND_JFFS2_OOB8_FSDALEN 2
#define NAND_JFFS2_OOB16_FSDALEN 8
-static struct nand_oobinfo jffs2_oobinfo_swecc = {
- .useecc = 1,
- .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2,
- JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
-};
-
static struct nand_oobinfo jffs2_oobinfo_docecc = {
- .useecc = 1,
+ .useecc = MTD_NANDECC_PLACE,
+ .eccbytes = 6,
.eccpos = {0,1,2,3,4,5}
};
-
-int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
{
+ struct nand_oobinfo *oinfo = &c->mtd->oobinfo;
+
+ /* Do this only, if we have an oob buffer */
+ if (!c->mtd->oobsize)
+ return 0;
+
/* Cleanmarker is out-of-band, so inline size zero */
c->cleanmarker_size = 0;
- /* Initialise write buffer */
- c->wbuf_pagesize = c->mtd->oobblock;
- c->wbuf_ofs = 0xFFFFFFFF;
-
- /* FIXME: If we had a generic way of describing the hardware's
- use of OOB area, we could perhaps make this generic too. */
- switch(c->mtd->ecctype) {
- case MTD_ECC_SW:
- D1(printk(KERN_DEBUG "JFFS2 using software ECC\n"));
- c->oobinfo = &jffs2_oobinfo_swecc;
- if (c->mtd->oobsize == 8) {
- c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS;
- c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN;
- } else {
- c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS;
+ /* Should we use autoplacement ? */
+ if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) {
+ D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n"));
+ /* Get the position of the free bytes */
+ if (!oinfo->oobfree[0][0]) {
+ printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n");
+ return -ENOSPC;
+ }
+ c->fsdata_pos = oinfo->oobfree[0][0];
+ c->fsdata_len = oinfo->oobfree[0][1];
+ if (c->fsdata_len > 8)
+ c->fsdata_len = 8;
+ } else {
+ /* This is just a legacy fallback and should go away soon */
+ switch(c->mtd->ecctype) {
+ case MTD_ECC_RS_DiskOnChip:
+ printk(KERN_WARNING "JFFS2 using DiskOnChip hardware ECC without autoplacement. Fix it!\n");
+ c->oobinfo = &jffs2_oobinfo_docecc;
+ c->fsdata_pos = 6;
c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+ c->badblock_pos = 15;
+ break;
+
+ default:
+ D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
+ return -EINVAL;
}
- c->badblock_pos = NAND_BADBLOCK_POS;
- break;
-
- case MTD_ECC_RS_DiskOnChip:
- D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n"));
- c->oobinfo = &jffs2_oobinfo_docecc;
- c->fsdata_pos = 6;
- c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
- c->badblock_pos = 15;
- break;
-
- default:
- printk("JFFS2 doesn't yet know how to handle ECC type %d\n",
- c->mtd->ecctype);
- return -EINVAL;
}
+ return 0;
+}
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+{
+ int res;
+
+ /* Initialise write buffer */
+ c->wbuf_pagesize = c->mtd->oobblock;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+
c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
if (!c->wbuf)
return -ENOMEM;
+ res = jffs2_nand_set_oobinfo(c);
+
#ifdef BREAKME
if (!brokenbuf)
brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
}
memset(brokenbuf, 0xdb, c->wbuf_pagesize);
#endif
- return 0;
+ return res;
}
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: write.c,v 1.75 2003/10/08 11:45:11 dwmw2 Exp $
+ * $Id: write.c,v 1.85 2004/07/13 08:58:25 dwmw2 Exp $
*
*/
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
+#include "compr.h"
int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
memset(ic, 0, sizeof(*ic));
- init_MUTEX_LOCKED(&f->sem);
f->inocache = ic;
f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
fn->raw = raw;
raw->flash_offset = flash_ofs;
- raw->totlen = PAD(sizeof(*ri)+datalen);
+ raw->__totlen = PAD(sizeof(*ri)+datalen);
raw->next_phys = NULL;
ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
fd->raw = raw;
raw->flash_offset = flash_ofs;
- raw->totlen = PAD(sizeof(*rd)+namelen);
+ raw->__totlen = PAD(sizeof(*rd)+namelen);
raw->next_phys = NULL;
ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
- (alloc_mode==ALLOC_GC)?0:fd->ino);
+ (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
if (ret || (retlen != sizeof(*rd) + namelen)) {
printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
sizeof(*rd)+namelen, flash_ofs, ret, retlen);
while(writelen) {
struct jffs2_full_dnode *fn;
unsigned char *comprbuf = NULL;
- unsigned char comprtype = JFFS2_COMPR_NONE;
+ uint16_t comprtype = JFFS2_COMPR_NONE;
uint32_t phys_ofs, alloclen;
uint32_t datalen, cdatalen;
int retried = 0;
break;
}
down(&f->sem);
- datalen = writelen;
- cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen);
+ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
+ cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
- comprbuf = kmalloc(cdatalen, GFP_KERNEL);
- if (comprbuf) {
- comprtype = jffs2_compress(buf, comprbuf, &datalen, &cdatalen);
- }
- if (comprtype == JFFS2_COMPR_NONE) {
- /* Either compression failed, or the allocation of comprbuf failed */
- if (comprbuf)
- kfree(comprbuf);
- comprbuf = buf;
- datalen = cdatalen;
- }
- /* Now comprbuf points to the data to be written, be it compressed or not.
- comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means
- that the comprbuf doesn't need to be kfree()d.
- */
+ comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri->offset = cpu_to_je32(offset);
ri->csize = cpu_to_je32(cdatalen);
ri->dsize = cpu_to_je32(datalen);
- ri->compr = comprtype;
+ ri->compr = comprtype & 0xff;
+ ri->usercompr = (comprtype >> 8 ) & 0xff;
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
- if (comprtype != JFFS2_COMPR_NONE)
- kfree(comprbuf);
+ jffs2_free_comprbuf(comprbuf, buf);
if (IS_ERR(fn)) {
ret = PTR_ERR(fn);
uint32_t alloclen, phys_ofs;
int ret;
- rd = jffs2_alloc_raw_dirent();
- if (!rd)
- return -ENOMEM;
+ if (1 /* alternative branch needs testing */ ||
+ !jffs2_can_mark_obsolete(c)) {
+ /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
- if (ret) {
+ rd = jffs2_alloc_raw_dirent();
+ if (!rd)
+ return -ENOMEM;
+
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
+ if (ret) {
+ jffs2_free_raw_dirent(rd);
+ return ret;
+ }
+
+ down(&dir_f->sem);
+
+ /* Build a deletion node */
+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+
+ rd->pino = cpu_to_je32(dir_f->inocache->ino);
+ rd->version = cpu_to_je32(++dir_f->highest_version);
+ rd->ino = cpu_to_je32(0);
+ rd->mctime = cpu_to_je32(get_seconds());
+ rd->nsize = namelen;
+ rd->type = DT_UNKNOWN;
+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
+
+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
+
jffs2_free_raw_dirent(rd);
- return ret;
- }
- down(&dir_f->sem);
+ if (IS_ERR(fd)) {
+ jffs2_complete_reservation(c);
+ up(&dir_f->sem);
+ return PTR_ERR(fd);
+ }
- /* Build a deletion node */
- rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
- rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
- rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
- rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+ /* File it. This will mark the old one obsolete. */
+ jffs2_add_fd_to_list(c, fd, &dir_f->dents);
+ up(&dir_f->sem);
+ } else {
+ struct jffs2_full_dirent **prev = &dir_f->dents;
+ uint32_t nhash = full_name_hash(name, namelen);
- rd->pino = cpu_to_je32(dir_f->inocache->ino);
- rd->version = cpu_to_je32(++dir_f->highest_version);
- rd->ino = cpu_to_je32(0);
- rd->mctime = cpu_to_je32(get_seconds());
- rd->nsize = namelen;
- rd->type = DT_UNKNOWN;
- rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
- rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
+ down(&dir_f->sem);
- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-
- jffs2_free_raw_dirent(rd);
+ while ((*prev) && (*prev)->nhash <= nhash) {
+ if ((*prev)->nhash == nhash &&
+ !memcmp((*prev)->name, name, namelen) &&
+ !(*prev)->name[namelen]) {
+ struct jffs2_full_dirent *this = *prev;
- if (IS_ERR(fd)) {
- jffs2_complete_reservation(c);
+ D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
+ this->ino, ref_offset(this->raw)));
+
+ *prev = this->next;
+ jffs2_mark_node_obsolete(c, (this->raw));
+ jffs2_free_full_dirent(this);
+ break;
+ }
+ prev = &((*prev)->next);
+ }
up(&dir_f->sem);
- return PTR_ERR(fd);
}
- /* File it. This will mark the old one obsolete. */
- jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-
- up(&dir_f->sem);
-
/* dead_f is NULL if this was a rename not a real unlink */
/* Also catch the !f->inocache case, where there was a dirent
pointing to an inode which didn't exist. */
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: writev.c,v 1.4 2003/10/04 08:33:07 dwmw2 Exp $
+ * $Id: writev.c,v 1.5 2004/07/13 08:58:25 dwmw2 Exp $
*
*/
int error;
int open_flags = 0;
- dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id,
+ dfprintk(VFS, "NFS: create(%s/%ld, %s)\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
attr.ia_mode = mode;
*/
lock_kernel();
nfs_begin_data_update(dir);
+ dfprintk(VFS, "NFS: attr %d.%d #%d\n", attr.ia_uid, attr.ia_gid, attr.ia_xid);
inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);
nfs_end_data_update(dir);
if (!IS_ERR(inode)) {
+ dfprintk(VFS, "NFS: inode=%p %d.%d #%d\n", inode,
+ inode->i_uid, inode->i_gid, inode->i_xid);
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
+#include <linux/vserver/xid.h>
#include <asm/system.h>
#include <asm/uaccess.h>
printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
+// DLIMIT_FREE_INODE(inode->i_sb, inode->i_xid);
clear_inode(inode);
}
}
server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
+ if (server->flags & NFS_MOUNT_TAGXID)
+ sb->s_flags |= MS_TAGXID;
+
sb->s_maxbytes = fsinfo.maxfilesize;
if (sb->s_maxbytes > MAX_LFS_FILESIZE)
sb->s_maxbytes = MAX_LFS_FILESIZE;
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+ { NFS_MOUNT_TAGXID, ",tagxid", "" },
{ 0, NULL, NULL }
};
struct proc_nfs_info *nfs_infop;
if (inode->i_state & I_NEW) {
struct nfs_inode *nfsi = NFS_I(inode);
+/* if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+ err = -ENOSPC;
+ goto fail_dlim;
+ }
+*/
/* We set i_ino for the few things that still rely on it,
* such as stat(2) */
inode->i_ino = hash;
nfsi->change_attr = fattr->change_attr;
inode->i_size = nfs_size_to_loff_t(fattr->size);
inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ inode->i_uid = INOXID_UID(fattr->uid, fattr->gid);
+ inode->i_gid = INOXID_GID(fattr->uid, fattr->gid);
+ if (inode->i_sb->s_flags & MS_TAGXID)
+ inode->i_xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+ /* maybe fattr->xid someday */
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
* report the blocks in 512byte units
out:
return inode;
-
+/*
+fail_dlim:
+ make_bad_inode(inode);
+ iput(inode);
+ inode = NULL;
+*/
out_no_inode:
printk("nfs_fhget: iget failed\n");
goto out;
}
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_XID|ATTR_SIZE|\
+ ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
int
nfs_setattr(struct dentry *dentry, struct iattr *attr)
inode->i_uid = attr->ia_uid;
if ((attr->ia_valid & ATTR_GID) != 0)
inode->i_gid = attr->ia_gid;
+ if ((attr->ia_valid & ATTR_XID) != 0)
+ inode->i_xid = attr->ia_xid;
if ((attr->ia_valid & ATTR_SIZE) != 0) {
inode->i_size = attr->ia_size;
vmtruncate(inode, attr->ia_size);
struct nfs_inode *nfsi = NFS_I(inode);
loff_t cur_size, new_isize;
int data_unstable;
+ uid_t uid;
+ gid_t gid;
+ xid_t xid = 0;
/* Are we in the process of updating data on the server? */
data_unstable = nfs_caches_unstable(inode);
} else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
nfsi->flags |= NFS_INO_INVALID_ATTR;
+ uid = INOXID_UID(fattr->uid, fattr->gid);
+ gid = INOXID_GID(fattr->uid, fattr->gid);
+ if (inode->i_sb->s_flags & MS_TAGXID)
+ xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+
/* Have any file permissions changed? */
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
- || inode->i_uid != fattr->uid
- || inode->i_gid != fattr->gid)
+ || inode->i_uid != uid
+ || inode->i_gid != gid
+ || inode->i_xid != xid)
nfsi->flags |= NFS_INO_INVALID_ATTR;
/* Has the link count changed? */
unsigned int invalid = 0;
loff_t cur_isize;
int data_unstable;
+ uid_t uid;
+ gid_t gid;
+ xid_t xid = 0;
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
__FUNCTION__, inode->i_sb->s_id, inode->i_ino,
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
+ uid = INOXID_UID(fattr->uid, fattr->gid);
+ gid = INOXID_GID(fattr->uid, fattr->gid);
+ if (inode->i_sb->s_flags & MS_TAGXID)
+ xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
- inode->i_uid != fattr->uid ||
- inode->i_gid != fattr->gid) {
+ inode->i_uid != uid ||
+ inode->i_gid != gid ||
+ inode->i_xid != xid) {
struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
if (*cred) {
put_rpccred(*cred);
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ inode->i_uid = uid;
+ inode->i_gid = gid;
+ inode->i_xid = xid;
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
+#include <linux/vserver/xid.h>
#define NFSDBG_FACILITY NFSDBG_XDR
} else {
*p++ = xdr_zero;
}
- if (attr->ia_valid & ATTR_UID) {
+ if (attr->ia_valid & ATTR_UID || attr->ia_valid & ATTR_XID) {
*p++ = xdr_one;
- *p++ = htonl(attr->ia_uid);
+ *p++ = htonl(XIDINO_UID(attr->ia_uid, attr->ia_xid));
} else {
*p++ = xdr_zero;
}
- if (attr->ia_valid & ATTR_GID) {
+ if (attr->ia_valid & ATTR_GID || attr->ia_valid & ATTR_XID) {
*p++ = xdr_one;
- *p++ = htonl(attr->ia_gid);
+ *p++ = htonl(XIDINO_GID(attr->ia_gid, attr->ia_xid));
} else {
*p++ = xdr_zero;
}
#include <linux/root_dev.h>
#include <net/ipconfig.h>
#include <linux/parser.h>
+#include <linux/vs_cvirt.h>
/* Define this to allow debugging output */
#undef NFSROOT_DEBUG
Opt_soft, Opt_hard, Opt_intr,
Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
- Opt_broken_suid,
+ Opt_broken_suid, Opt_tagxid,
/* Error token */
Opt_err
};
{Opt_tcp, "proto=tcp"},
{Opt_tcp, "tcp"},
{Opt_broken_suid, "broken_suid"},
+ {Opt_tagxid, "tagxid"},
{Opt_err, NULL}
};
case Opt_broken_suid:
nfs_data.flags |= NFS_MOUNT_BROKEN_SUID;
break;
+ case Opt_tagxid:
+ nfs_data.flags |= NFS_MOUNT_TAGXID;
+ break;
default :
return 0;
}
int status;
fattr.valid = 0;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
+
dprintk("NFS call create %s\n", name->name);
status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
dprintk("NFS reply create: %d\n", status);
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/nfsd/nfsd.h>
+#include <linux/vserver/xid.h>
#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
}
if (cred->cr_uid != (uid_t) -1)
- current->fsuid = cred->cr_uid;
+ current->fsuid = INOXID_UID(cred->cr_uid, cred->cr_gid);
else
current->fsuid = exp->ex_anon_uid;
if (cred->cr_gid != (gid_t) -1)
- current->fsgid = cred->cr_gid;
+ current->fsgid = INOXID_GID(cred->cr_uid, cred->cr_gid);
else
current->fsgid = exp->ex_anon_gid;
+
+ current->xid = INOXID_XID(cred->cr_uid, cred->cr_gid, 0);
if (!cred->cr_group_info)
return -ENOMEM;
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr3.h>
+#include <linux/vserver/xid.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
*p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
*p++ = htonl((u32) stat.mode);
*p++ = htonl((u32) stat.nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+ *p++ = htonl((u32) nfsd_ruid(rqstp,
+ XIDINO_UID(stat.uid, stat.xid)));
+ *p++ = htonl((u32) nfsd_rgid(rqstp,
+ XIDINO_GID(stat.gid, stat.xid)));
if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
} else {
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
#include <linux/nfsd_idmap.h>
+#include <linux/vserver/xid.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
WRITE32(stat.nlink);
}
if (bmval1 & FATTR4_WORD1_OWNER) {
- status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
+ status = nfsd4_encode_user(rqstp,
+ XIDINO_UID(stat.uid, stat.xid), &p, &buflen);
if (status == nfserr_resource)
goto out_resource;
if (status)
goto out;
}
if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
+ status = nfsd4_encode_group(rqstp,
+ XIDINO_GID(stat.gid, stat.xid), &p, &buflen);
if (status == nfserr_resource)
goto out_resource;
if (status)
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr.h>
#include <linux/mm.h>
+#include <linux/vserver/xid.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
*p++ = htonl(nfs_ftypes[type >> 12]);
*p++ = htonl((u32) stat.mode);
*p++ = htonl((u32) stat.nlink);
- *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
- *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+ *p++ = htonl((u32) nfsd_ruid(rqstp,
+ XIDINO_UID(stat.uid, stat.xid)));
+ *p++ = htonl((u32) nfsd_rgid(rqstp,
+ XIDINO_GID(stat.gid, stat.xid)));
if (S_ISLNK(type) && stat.size > NFS_MAXPATHLEN) {
*p++ = htonl(NFS_MAXPATHLEN);
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
{
int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+
if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
err = nfserr_io;
return err;
if (acc == MAY_NOP)
return 0;
#if 0
- dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
+ printk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
acc,
(acc & MAY_READ)? " read" : "",
(acc & MAY_WRITE)? " write" : "",
IS_IMMUTABLE(inode)? " immut" : "",
IS_APPEND(inode)? " append" : "",
IS_RDONLY(inode)? " ro" : "");
- dprintk(" owner %d/%d user %d/%d\n",
+ printk(" owner %d/%d user %d/%d\n",
inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
#endif
if (retval == 0 && buf->f_frsize == 0)
buf->f_frsize = buf->f_bsize;
}
+ if (!vx_check(0, VX_ADMIN|VX_WATCH))
+ vx_vsi_statfs(sb, buf);
}
return retval;
}
__FD_CLR(fd, files->open_fds);
if (fd < files->next_fd)
files->next_fd = fd;
+ vx_openfd_dec(fd);
}
void fastcall put_unused_fd(unsigned int fd)
FD_CLR(fd, files->close_on_exec);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
- vx_openfd_dec(fd);
return filp_close(filp, files);
out_unlock:
res = sprintf(buffer,"%u %llu %llu %u %llu %u %llu\n",
get_delay(task,runs),
- get_delay(task,runcpu_total),
- get_delay(task,waitcpu_total),
+ (unsigned long long)get_delay(task,runcpu_total),
+ (unsigned long long)get_delay(task,waitcpu_total),
get_delay(task,num_iowaits),
- get_delay(task,iowait_total),
+ (unsigned long long)get_delay(task,iowait_total),
get_delay(task,num_memwaits),
- get_delay(task,mem_iowait_total)
+ (unsigned long long)get_delay(task,mem_iowait_total)
);
return res;
}
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
-#include <linux/vs_context.h>
#include <linux/vs_network.h>
#include <linux/vs_cvirt.h>
-
/*
* For hysterical raisins we keep the same inumbers as in the old procfs.
* Feel free to change the macro below - just keep the range distinct from
{"commit", .arg_required = 'c', .values = NULL},
{"usrquota",},
{"grpquota",},
+ {"tagxid", .setmask = 1<<REISERFS_TAGXID},
{NULL,}
};
stat->nlink = inode->i_nlink;
stat->uid = inode->i_uid;
stat->gid = inode->i_gid;
+ stat->xid = inode->i_xid;
stat->rdev = inode->i_rdev;
stat->atime = inode->i_atime;
stat->mtime = inode->i_mtime;
#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */
#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */
#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */
+#define LINUX_XFLAG_BARRIER 0x00004000 /* chroot() barrier */
+#define LINUX_XFLAG_IUNLINK 0x00008000 /* Immutable unlink */
STATIC unsigned int
xfs_merge_ioc_xflags(
if (di_flags & XFS_DIFLAG_IMMUTABLE)
flags |= LINUX_XFLAG_IMMUTABLE;
+ if (di_flags & XFS_DIFLAG_IUNLINK)
+ flags |= LINUX_XFLAG_IUNLINK;
if (di_flags & XFS_DIFLAG_APPEND)
flags |= LINUX_XFLAG_APPEND;
if (di_flags & XFS_DIFLAG_SYNC)
int error;
int attr_flags;
unsigned int flags;
+ unsigned int old_flags;
switch (cmd) {
case XFS_IOC_FSGETXATTR: {
attr_flags = 0;
if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
attr_flags |= ATTR_NONBLOCK;
-
+
va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
va.va_xflags = fa.fsx_xflags;
va.va_extsize = fa.fsx_extsize;
#include "xfs_utils.h"
#include <linux/xattr.h>
+#include <linux/namei.h>
/*
ASSERT(nd);
link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL);
- if (!link)
- return -ENOMEM;
+ if (!link) {
+ nd_set_link(nd, ERR_PTR(-ENOMEM));
+ return 0;
+ }
uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
if (!uio) {
kfree(link);
- return -ENOMEM;
+ nd_set_link(nd, ERR_PTR(-ENOMEM));
+ return 0;
}
vp = LINVFS_GET_VP(dentry->d_inode);
VOP_READLINK(vp, uio, 0, NULL, error);
if (error) {
- kfree(uio);
kfree(link);
- return -error;
+ link = ERR_PTR(-error);
+ } else {
+ link[MAXNAMELEN - uio->uio_resid] = '\0';
}
-
- link[MAXNAMELEN - uio->uio_resid] = '\0';
kfree(uio);
- /* vfs_follow_link returns (-) errors */
- error = vfs_follow_link(nd, link);
- kfree(link);
- return error;
+ nd_set_link(nd, link);
+ return 0;
+}
+
+static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char *s = nd_get_link(nd);
+ if (!IS_ERR(s))
+ kfree(s);
}
#ifdef CONFIG_XFS_POSIX_ACL
return 0;
}
+STATIC int
+linvfs_setattr_flags(
+ vattr_t *vap,
+ unsigned int flags)
+{
+ unsigned int oldflags, newflags;
+
+ oldflags = vap->va_xflags;
+ newflags = oldflags & ~(XFS_XFLAG_IMMUTABLE |
+ XFS_XFLAG_IUNLINK | XFS_XFLAG_BARRIER);
+ if (flags & ATTR_FLAG_IMMUTABLE)
+ newflags |= XFS_XFLAG_IMMUTABLE;
+ if (flags & ATTR_FLAG_IUNLINK)
+ newflags |= XFS_XFLAG_IUNLINK;
+ if (flags & ATTR_FLAG_BARRIER)
+ newflags |= XFS_XFLAG_BARRIER;
+
+ if (oldflags ^ newflags)
+ vap->va_xflags = newflags;
+ return 0;
+}
+
STATIC int
linvfs_setattr(
struct dentry *dentry,
flags |= ATTR_NONBLOCK;
#endif
+ if (ia_valid & ATTR_ATTR_FLAG) {
+ vattr.va_mask |= XFS_AT_XFLAGS;
+ linvfs_setattr_flags(&vattr, attr->ia_attr_flags);
+ }
+
VOP_SETATTR(vp, &vattr, flags, NULL, error);
if (error)
return -error;
struct inode_operations linvfs_symlink_inode_operations = {
.readlink = linvfs_readlink,
.follow_link = linvfs_follow_link,
+ .put_link = linvfs_put_link,
.permission = linvfs_permission,
.getattr = linvfs_getattr,
.setattr = linvfs_setattr,
STATIC struct quotactl_ops linvfs_qops;
STATIC struct super_operations linvfs_sops;
STATIC struct export_operations linvfs_export_ops;
-STATIC kmem_cache_t * linvfs_inode_cachep;
+STATIC kmem_zone_t *linvfs_inode_zone;
+STATIC kmem_shaker_t xfs_inode_shaker;
STATIC struct xfs_mount_args *
xfs_args_allocate(
inode->i_flags |= S_IMMUTABLE;
else
inode->i_flags &= ~S_IMMUTABLE;
+ if (ip->i_d.di_flags & XFS_DIFLAG_IUNLINK)
+ inode->i_flags |= S_IUNLINK;
+ else
+ inode->i_flags &= ~S_IUNLINK;
+ if (ip->i_d.di_flags & XFS_DIFLAG_BARRIER)
+ inode->i_flags |= S_BARRIER;
+ else
+ inode->i_flags &= ~S_BARRIER;
if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
inode->i_flags |= S_APPEND;
else
{
vnode_t *vp;
- vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep,
+ vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_zone,
kmem_flags_convert(KM_SLEEP));
if (!vp)
return NULL;
linvfs_destroy_inode(
struct inode *inode)
{
- kmem_cache_free(linvfs_inode_cachep, LINVFS_GET_VP(inode));
+ kmem_cache_free(linvfs_inode_zone, LINVFS_GET_VP(inode));
+}
+
+int
+xfs_inode_shake(
+ int priority,
+ unsigned int gfp_mask)
+{
+ int pages;
+
+
+ pages = kmem_zone_shrink(linvfs_inode_zone);
+ pages += kmem_zone_shrink(xfs_inode_zone);
+ return pages;
}
STATIC void
STATIC int
init_inodecache( void )
{
- linvfs_inode_cachep = kmem_cache_create("linvfs_icache",
+ linvfs_inode_zone = kmem_cache_create("linvfs_icache",
sizeof(vnode_t), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
init_once, NULL);
- if (linvfs_inode_cachep == NULL)
+ if (linvfs_inode_zone == NULL)
return -ENOMEM;
return 0;
}
STATIC void
destroy_inodecache( void )
{
- if (kmem_cache_destroy(linvfs_inode_cachep))
+ if (kmem_cache_destroy(linvfs_inode_zone))
printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__);
}
vn_init();
xfs_init();
uuid_init();
- vfs_initdmapi();
vfs_initquota();
+ xfs_inode_shaker = kmem_shake_register(xfs_inode_shake);
+ if (!xfs_inode_shaker) {
+ error = -ENOMEM;
+ goto undo_shaker;
+ }
+
error = register_filesystem(&xfs_fs_type);
if (error)
goto undo_register;
+ XFS_DM_INIT(&xfs_fs_type);
return 0;
undo_register:
+ kmem_shake_deregister(xfs_inode_shaker);
+
+undo_shaker:
pagebuf_terminate();
undo_pagebuf:
exit_xfs_fs( void )
{
vfs_exitquota();
- vfs_exitdmapi();
+ XFS_DM_EXIT(&xfs_fs_type);
unregister_filesystem(&xfs_fs_type);
+ kmem_shake_deregister(xfs_inode_shaker);
xfs_cleanup();
pagebuf_terminate();
destroy_inodecache();
inode->i_flags |= S_IMMUTABLE;
else
inode->i_flags &= ~S_IMMUTABLE;
+ if (va.va_xflags & XFS_XFLAG_IUNLINK)
+ inode->i_flags |= S_IUNLINK;
+ else
+ inode->i_flags &= ~S_IUNLINK;
+ if (va.va_xflags & XFS_XFLAG_BARRIER)
+ inode->i_flags |= S_BARRIER;
+ else
+ inode->i_flags &= ~S_BARRIER;
if (va.va_xflags & XFS_XFLAG_APPEND)
inode->i_flags |= S_APPEND;
else
#include <linux/config.h>
#include <linux/swap.h>
+#include <linux/vs_memory.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
-#include <linux/vs_memory.h>
/*
* For UP we don't need to worry about TLB flush
+++ /dev/null
-/*
- * include/asm-ppc/gt64260.h
- *
- * Prototypes, etc. for the Marvell/Galileo GT64260 host bridge routines.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASMPPC_GT64260_H
-#define __ASMPPC_GT64260_H
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/gt64260_defs.h>
-
-
-extern u32 gt64260_base;
-extern u32 gt64260_irq_base; /* We handle the next 96 IRQs from here */
-extern u32 gt64260_revision;
-extern u8 gt64260_pci_exclude_bridge;
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/* IRQs defined by the 64260 */
-#define GT64260_IRQ_MPSC0 40
-#define GT64260_IRQ_MPSC1 42
-#define GT64260_IRQ_SDMA 36
-
-/*
- * Define a default physical memory map to be set up on the bridge.
- * Also define a struct to pass that info from board-specific routines to
- * GT64260 generic set up routines. By passing this info in, the board
- * support developer can modify it at will.
- */
-
-/*
- * This is the default memory map:
- * CPU PCI
- * --- ---
- * PCI 0 I/O: 0xfa000000-0xfaffffff 0x00000000-0x00ffffff
- * PCI 1 I/O: 0xfb000000-0xfbffffff 0x01000000-0x01ffffff
- * PCI 0 MEM: 0x80000000-0x8fffffff 0x80000000-0x8fffffff
- * PCI 1 MEM: 0x90000000-0x9fffffff 0x90000000-0x9fffffff
- */
-
-/* Default physical memory map for the GT64260 bridge */
-
-/*
- * PCI Bus 0 Definitions
- */
-#define GT64260_PCI_0_IO_SIZE 0x01000000U
-#define GT64260_PCI_0_MEM_SIZE 0x10000000U
-
-/* Processor Physical addresses */
-#define GT64260_PCI_0_IO_START_PROC 0xfa000000U
-#define GT64260_PCI_0_IO_END_PROC (GT64260_PCI_0_IO_START_PROC + \
- GT64260_PCI_0_IO_SIZE - 1)
-
-/* PCI 0 addresses */
-#define GT64260_PCI_0_IO_START 0x00000000U
-#define GT64260_PCI_0_IO_END (GT64260_PCI_0_IO_START + \
- GT64260_PCI_0_IO_SIZE - 1)
-
-/* Processor Physical addresses */
-#define GT64260_PCI_0_MEM_START_PROC 0x80000000U
-#define GT64260_PCI_0_MEM_END_PROC (GT64260_PCI_0_MEM_START_PROC + \
- GT64260_PCI_0_MEM_SIZE - 1)
-
-/* PCI 0 addresses */
-#define GT64260_PCI_0_MEM_START 0x80000000U
-#define GT64260_PCI_0_MEM_END (GT64260_PCI_0_MEM_START + \
- GT64260_PCI_0_MEM_SIZE - 1)
-
-/*
- * PCI Bus 1 Definitions
- */
-#define GT64260_PCI_1_IO_SIZE 0x01000000U
-#define GT64260_PCI_1_MEM_SIZE 0x10000000U
-
-/* PCI 1 addresses */
-#define GT64260_PCI_1_IO_START 0x01000000U
-#define GT64260_PCI_1_IO_END (GT64260_PCI_1_IO_START + \
- GT64260_PCI_1_IO_SIZE - 1)
-
-/* Processor Physical addresses */
-#define GT64260_PCI_1_IO_START_PROC 0xfb000000U
-#define GT64260_PCI_1_IO_END_PROC (GT64260_PCI_1_IO_START_PROC + \
- GT64260_PCI_1_IO_SIZE - 1)
-
-/* PCI 1 addresses */
-#define GT64260_PCI_1_MEM_START 0x90000000U
-#define GT64260_PCI_1_MEM_END (GT64260_PCI_1_MEM_START + \
- GT64260_PCI_1_MEM_SIZE - 1)
-
-/* Processor Physical addresses */
-#define GT64260_PCI_1_MEM_START_PROC 0x90000000U
-#define GT64260_PCI_1_MEM_END_PROC (GT64260_PCI_1_MEM_START_PROC + \
- GT64260_PCI_1_MEM_SIZE - 1)
-
-/* Define struct to pass mem-map info into gt64260_common.c code */
-typedef struct {
- struct pci_controller *hose_a;
- struct pci_controller *hose_b;
-
- u32 mem_size;
-
- u32 pci_0_io_start_proc;
- u32 pci_0_io_start_pci;
- u32 pci_0_io_size;
- u32 pci_0_io_swap;
-
- u32 pci_0_mem_start_proc;
- u32 pci_0_mem_start_pci_hi;
- u32 pci_0_mem_start_pci_lo;
- u32 pci_0_mem_size;
- u32 pci_0_mem_swap;
-
- u32 pci_1_io_start_proc;
- u32 pci_1_io_start_pci;
- u32 pci_1_io_size;
- u32 pci_1_io_swap;
-
- u32 pci_1_mem_start_proc;
- u32 pci_1_mem_start_pci_hi;
- u32 pci_1_mem_start_pci_lo;
- u32 pci_1_mem_size;
- u32 pci_1_mem_swap;
-} gt64260_bridge_info_t;
-
-#define GT64260_BRIDGE_INFO_DEFAULT(ip, ms) { \
- (ip)->mem_size = (ms); \
- \
- (ip)->pci_0_io_start_proc = GT64260_PCI_0_IO_START_PROC; \
- (ip)->pci_0_io_start_pci = GT64260_PCI_0_IO_START; \
- (ip)->pci_0_io_size = GT64260_PCI_0_IO_SIZE; \
- (ip)->pci_0_io_swap = GT64260_CPU_PCI_SWAP_NONE; \
- \
- (ip)->pci_0_mem_start_proc = GT64260_PCI_0_MEM_START_PROC; \
- (ip)->pci_0_mem_start_pci_hi = 0x00000000; \
- (ip)->pci_0_mem_start_pci_lo = GT64260_PCI_0_MEM_START; \
- (ip)->pci_0_mem_size = GT64260_PCI_0_MEM_SIZE; \
- (ip)->pci_0_mem_swap = GT64260_CPU_PCI_SWAP_NONE; \
- \
- (ip)->pci_1_io_start_proc = GT64260_PCI_1_IO_START_PROC; \
- (ip)->pci_1_io_start_pci = GT64260_PCI_1_IO_START; \
- (ip)->pci_1_io_size = GT64260_PCI_1_IO_SIZE; \
- (ip)->pci_1_io_swap = GT64260_CPU_PCI_SWAP_NONE; \
- \
- (ip)->pci_1_mem_start_proc = GT64260_PCI_1_MEM_START_PROC; \
- (ip)->pci_1_mem_start_pci_hi = 0x00000000; \
- (ip)->pci_1_mem_start_pci_lo = GT64260_PCI_1_MEM_START; \
- (ip)->pci_1_mem_size = GT64260_PCI_1_MEM_SIZE; \
- (ip)->pci_1_mem_swap = GT64260_CPU_PCI_SWAP_NONE; \
-}
-
-/*
- *****************************************************************************
- *
- * I/O macros to access the 64260's registers
- *
- *****************************************************************************
- */
-
-extern inline uint32_t gt_read(uint32_t offs){
- return (in_le32((volatile uint *)(gt64260_base + offs)));
-}
-extern inline void gt_write(uint32_t offs, uint32_t d){
- out_le32((volatile uint *)(gt64260_base + offs), d);
-}
-
-#if 0 /* paranoid SMP version */
-extern inline void gt_modify(u32 offs, u32 data, u32 mask) \
-{
- uint32_t reg;
- spin_lock(>64260_lock);
- reg = gt_read(offs) & (~mask); /* zero any bits we care about*/
- reg |= data & mask; /* set bits from the data */
- gt_write(offs, reg);
- spin_unlock(>64260_lock);
-}
-#else
-extern inline void gt_modify(uint32_t offs, uint32_t data, uint32_t mask)
-{
- uint32_t reg;
- reg = gt_read(offs) & (~(mask)); /* zero any bits we care about*/
- reg |= (data) & (mask); /* set bits from the data */
- gt_write(offs, reg);
-}
-#endif
-#define gt_set_bits(offs, bits) gt_modify(offs, ~0, bits)
-
-#define gt_clr_bits(offs, bits) gt_modify(offs, 0, bits)
-
-
-/*
- *****************************************************************************
- *
- * Function Prototypes
- *
- *****************************************************************************
- */
-
-int gt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info,
- int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char)));
-int gt64260_bridge_init(gt64260_bridge_info_t *info);
-int gt64260_cpu_scs_set_window(u32 window,
- u32 base_addr,
- u32 size);
-int gt64260_cpu_cs_set_window(u32 window,
- u32 base_addr,
- u32 size);
-int gt64260_cpu_boot_set_window(u32 base_addr,
- u32 size);
-int gt64260_cpu_set_pci_io_window(u32 pci_bus,
- u32 cpu_base_addr,
- u32 pci_base_addr,
- u32 size,
- u32 swap);
-int gt64260_cpu_set_pci_mem_window(u32 pci_bus,
- u32 window,
- u32 cpu_base_addr,
- u32 pci_base_addr_hi,
- u32 pci_base_addr_lo,
- u32 size,
- u32 swap_64bit);
-int gt64260_cpu_prot_set_window(u32 window,
- u32 base_addr,
- u32 size,
- u32 access_bits);
-int gt64260_cpu_snoop_set_window(u32 window,
- u32 base_addr,
- u32 size,
- u32 snoop_type);
-void gt64260_cpu_disable_all_windows(void);
-int gt64260_pci_bar_enable(u32 pci_bus, u32 enable_bits);
-int gt64260_pci_slave_scs_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_cs_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_boot_set_window(struct pci_controller *hose,
- u32 pci_base_addr,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_p2p_mem_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr,
- u32 other_bus_base_addr,
- u32 size);
-int gt64260_pci_slave_p2p_io_set_window(struct pci_controller *hose,
- u32 pci_base_addr,
- u32 other_bus_base_addr,
- u32 size);
-int gt64260_pci_slave_dac_scs_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr_hi,
- u32 pci_base_addr_lo,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_dac_cs_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr_hi,
- u32 pci_base_addr_lo,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_dac_boot_set_window(struct pci_controller *hose,
- u32 pci_base_addr_hi,
- u32 pci_base_addr_lo,
- u32 cpu_base_addr,
- u32 size);
-int gt64260_pci_slave_dac_p2p_mem_set_window(struct pci_controller *hose,
- u32 window,
- u32 pci_base_addr_hi,
- u32 pci_base_addr_lo,
- u32 other_bus_base_addr,
- u32 size);
-int gt64260_pci_acc_cntl_set_window(u32 pci_bus,
- u32 window,
- u32 base_addr_hi,
- u32 base_addr_lo,
- u32 size,
- u32 features);
-int gt64260_pci_snoop_set_window(u32 pci_bus,
- u32 window,
- u32 base_addr_hi,
- u32 base_addr_lo,
- u32 size,
- u32 snoop_type);
-int gt64260_set_base(u32 new_base);
-int gt64260_get_base(u32 *base);
-int gt64260_pci_exclude_device(u8 bus, u8 devfn);
-
-void gt64260_init_irq(void);
-int gt64260_get_irq(struct pt_regs *regs);
-
-void gt64260_mpsc_progress(char *s, unsigned short hex);
-
-#endif /* __ASMPPC_GT64260_H */
+++ /dev/null
-/*
- * include/asm-ppc/gt64260_defs.h
- *
- * Register definitions for the Marvell/Galileo GT64260 host bridge.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#ifndef __ASMPPC_GT64260_DEFS_H
-#define __ASMPPC_GT64260_DEFS_H
-
-/*
- * Define a macro to represent the supported version of the 64260.
- */
-#define GT64260 0x01
-#define GT64260A 0x10
-
-/*
- *****************************************************************************
- *
- * CPU Interface Registers
- *
- *****************************************************************************
- */
-
-/* CPU physical address of 64260's registers */
-#define GT64260_INTERNAL_SPACE_DECODE 0x0068
-#define GT64260_INTERNAL_SPACE_SIZE 0x10000
-#define GT64260_INTERNAL_SPACE_DEFAULT_ADDR 0x14000000
-
-/* CPU Memory Controller Window Registers (4 windows) */
-#define GT64260_CPU_SCS_DECODE_WINDOWS 4
-
-#define GT64260_CPU_SCS_DECODE_0_BOT 0x0008
-#define GT64260_CPU_SCS_DECODE_0_TOP 0x0010
-#define GT64260_CPU_SCS_DECODE_1_BOT 0x0208
-#define GT64260_CPU_SCS_DECODE_1_TOP 0x0210
-#define GT64260_CPU_SCS_DECODE_2_BOT 0x0018
-#define GT64260_CPU_SCS_DECODE_2_TOP 0x0020
-#define GT64260_CPU_SCS_DECODE_3_BOT 0x0218
-#define GT64260_CPU_SCS_DECODE_3_TOP 0x0220
-
-/* CPU Device Controller Window Registers (4 windows) */
-#define GT64260_CPU_CS_DECODE_WINDOWS 4
-
-#define GT64260_CPU_CS_DECODE_0_BOT 0x0028
-#define GT64260_CPU_CS_DECODE_0_TOP 0x0030
-#define GT64260_CPU_CS_DECODE_1_BOT 0x0228
-#define GT64260_CPU_CS_DECODE_1_TOP 0x0230
-#define GT64260_CPU_CS_DECODE_2_BOT 0x0248
-#define GT64260_CPU_CS_DECODE_2_TOP 0x0250
-#define GT64260_CPU_CS_DECODE_3_BOT 0x0038
-#define GT64260_CPU_CS_DECODE_3_TOP 0x0040
-
-#define GT64260_CPU_BOOT_CS_DECODE_0_BOT 0x0238
-#define GT64260_CPU_BOOT_CS_DECODE_0_TOP 0x0240
-
-/* CPU Windows to PCI space (2 PCI buses each w/ 1 I/O & 4 MEM windows) */
-#define GT64260_PCI_BUSES 2
-#define GT64260_PCI_IO_WINDOWS_PER_BUS 1
-#define GT64260_PCI_MEM_WINDOWS_PER_BUS 4
-
-#define GT64260_CPU_PCI_SWAP_BYTE 0x00000000
-#define GT64260_CPU_PCI_SWAP_NONE 0x01000000
-#define GT64260_CPU_PCI_SWAP_BYTE_WORD 0x02000000
-#define GT64260_CPU_PCI_SWAP_WORD 0x03000000
-#define GT64260_CPU_PCI_SWAP_MASK 0x07000000
-
-#define GT64260_CPU_PCI_MEM_REQ64 (1<<27)
-
-#define GT64260_CPU_PCI_0_IO_DECODE_BOT 0x0048
-#define GT64260_CPU_PCI_0_IO_DECODE_TOP 0x0050
-#define GT64260_CPU_PCI_0_MEM_0_DECODE_BOT 0x0058
-#define GT64260_CPU_PCI_0_MEM_0_DECODE_TOP 0x0060
-#define GT64260_CPU_PCI_0_MEM_1_DECODE_BOT 0x0080
-#define GT64260_CPU_PCI_0_MEM_1_DECODE_TOP 0x0088
-#define GT64260_CPU_PCI_0_MEM_2_DECODE_BOT 0x0258
-#define GT64260_CPU_PCI_0_MEM_2_DECODE_TOP 0x0260
-#define GT64260_CPU_PCI_0_MEM_3_DECODE_BOT 0x0280
-#define GT64260_CPU_PCI_0_MEM_3_DECODE_TOP 0x0288
-
-#define GT64260_CPU_PCI_0_IO_REMAP 0x00f0
-#define GT64260_CPU_PCI_0_MEM_0_REMAP_LO 0x00f8
-#define GT64260_CPU_PCI_0_MEM_0_REMAP_HI 0x0320
-#define GT64260_CPU_PCI_0_MEM_1_REMAP_LO 0x0100
-#define GT64260_CPU_PCI_0_MEM_1_REMAP_HI 0x0328
-#define GT64260_CPU_PCI_0_MEM_2_REMAP_LO 0x02f8
-#define GT64260_CPU_PCI_0_MEM_2_REMAP_HI 0x0330
-#define GT64260_CPU_PCI_0_MEM_3_REMAP_LO 0x0300
-#define GT64260_CPU_PCI_0_MEM_3_REMAP_HI 0x0338
-
-#define GT64260_CPU_PCI_1_IO_DECODE_BOT 0x0090
-#define GT64260_CPU_PCI_1_IO_DECODE_TOP 0x0098
-#define GT64260_CPU_PCI_1_MEM_0_DECODE_BOT 0x00a0
-#define GT64260_CPU_PCI_1_MEM_0_DECODE_TOP 0x00a8
-#define GT64260_CPU_PCI_1_MEM_1_DECODE_BOT 0x00b0
-#define GT64260_CPU_PCI_1_MEM_1_DECODE_TOP 0x00b8
-#define GT64260_CPU_PCI_1_MEM_2_DECODE_BOT 0x02a0
-#define GT64260_CPU_PCI_1_MEM_2_DECODE_TOP 0x02a8
-#define GT64260_CPU_PCI_1_MEM_3_DECODE_BOT 0x02b0
-#define GT64260_CPU_PCI_1_MEM_3_DECODE_TOP 0x02b8
-
-#define GT64260_CPU_PCI_1_IO_REMAP 0x0108
-#define GT64260_CPU_PCI_1_MEM_0_REMAP_LO 0x0110
-#define GT64260_CPU_PCI_1_MEM_0_REMAP_HI 0x0340
-#define GT64260_CPU_PCI_1_MEM_1_REMAP_LO 0x0118
-#define GT64260_CPU_PCI_1_MEM_1_REMAP_HI 0x0348
-#define GT64260_CPU_PCI_1_MEM_2_REMAP_LO 0x0310
-#define GT64260_CPU_PCI_1_MEM_2_REMAP_HI 0x0350
-#define GT64260_CPU_PCI_1_MEM_3_REMAP_LO 0x0318
-#define GT64260_CPU_PCI_1_MEM_3_REMAP_HI 0x0358
-
-/* CPU Control Registers */
-#define GT64260_CPU_CONFIG 0x0000
-#define GT64260_CPU_MODE 0x0120
-#define GT64260_CPU_MASTER_CNTL 0x0160
-#define GT64260_CPU_XBAR_CNTL_LO 0x0150
-#define GT64260_CPU_XBAR_CNTL_HI 0x0158
-#define GT64260_CPU_XBAR_TO 0x0168
-#define GT64260_CPU_RR_XBAR_CNTL_LO 0x0170
-#define GT64260_CPU_RR_XBAR_CNTL_HI 0x0178
-
-/* CPU Sync Barrier Registers */
-#define GT64260_CPU_SYNC_BARRIER_PCI_0 0x00c0
-#define GT64260_CPU_SYNC_BARRIER_PCI_1 0x00c8
-
-/* CPU Access Protection Registers */
-#define GT64260_CPU_PROT_WINDOWS 8
-
-#define GT64260_CPU_PROT_ACCPROTECT (1<<16)
-#define GT64260_CPU_PROT_WRPROTECT (1<<17)
-#define GT64260_CPU_PROT_CACHEPROTECT (1<<18)
-
-#define GT64260_CPU_PROT_BASE_0 0x0180
-#define GT64260_CPU_PROT_TOP_0 0x0188
-#define GT64260_CPU_PROT_BASE_1 0x0190
-#define GT64260_CPU_PROT_TOP_1 0x0198
-#define GT64260_CPU_PROT_BASE_2 0x01a0
-#define GT64260_CPU_PROT_TOP_2 0x01a8
-#define GT64260_CPU_PROT_BASE_3 0x01b0
-#define GT64260_CPU_PROT_TOP_3 0x01b8
-#define GT64260_CPU_PROT_BASE_4 0x01c0
-#define GT64260_CPU_PROT_TOP_4 0x01c8
-#define GT64260_CPU_PROT_BASE_5 0x01d0
-#define GT64260_CPU_PROT_TOP_5 0x01d8
-#define GT64260_CPU_PROT_BASE_6 0x01e0
-#define GT64260_CPU_PROT_TOP_6 0x01e8
-#define GT64260_CPU_PROT_BASE_7 0x01f0
-#define GT64260_CPU_PROT_TOP_7 0x01f8
-
-/* CPU Snoop Control Registers */
-#define GT64260_CPU_SNOOP_WINDOWS 4
-
-#define GT64260_CPU_SNOOP_NONE 0x00000000
-#define GT64260_CPU_SNOOP_WT 0x00010000
-#define GT64260_CPU_SNOOP_WB 0x00020000
-#define GT64260_CPU_SNOOP_MASK 0x00030000
-#define GT64260_CPU_SNOOP_ALL_BITS GT64260_CPU_SNOOP_MASK
-
-#define GT64260_CPU_SNOOP_BASE_0 0x0380
-#define GT64260_CPU_SNOOP_TOP_0 0x0388
-#define GT64260_CPU_SNOOP_BASE_1 0x0390
-#define GT64260_CPU_SNOOP_TOP_1 0x0398
-#define GT64260_CPU_SNOOP_BASE_2 0x03a0
-#define GT64260_CPU_SNOOP_TOP_2 0x03a8
-#define GT64260_CPU_SNOOP_BASE_3 0x03b0
-#define GT64260_CPU_SNOOP_TOP_3 0x03b8
-
-/* CPU Error Report Registers */
-#define GT64260_CPU_ERR_ADDR_LO 0x0070
-#define GT64260_CPU_ERR_ADDR_HI 0x0078
-#define GT64260_CPU_ERR_DATA_LO 0x0128
-#define GT64260_CPU_ERR_DATA_HI 0x0130
-#define GT64260_CPU_ERR_PARITY 0x0138
-#define GT64260_CPU_ERR_CAUSE 0x0140
-#define GT64260_CPU_ERR_MASK 0x0148
-
-
-/*
- *****************************************************************************
- *
- * SDRAM Cotnroller Registers
- *
- *****************************************************************************
- */
-
-/* SDRAM Config Registers */
-#define GT64260_SDRAM_CONFIG 0x0448
-#define GT64260_SDRAM_OPERATION_MODE 0x0474
-#define GT64260_SDRAM_ADDR_CNTL 0x047c
-#define GT64260_SDRAM_TIMING_PARAMS 0x04b4
-#define GT64260_SDRAM_UMA_CNTL 0x04a4
-#define GT64260_SDRAM_XBAR_CNTL_LO 0x04a8
-#define GT64260_SDRAM_XBAR_CNTL_HI 0x04ac
-#define GT64260_SDRAM_XBAR_CNTL_TO 0x04b0
-
-/* SDRAM Banks Parameters Registers */
-#define GT64260_SDRAM_BANK_PARAMS_0 0x044c
-#define GT64260_SDRAM_BANK_PARAMS_1 0x0450
-#define GT64260_SDRAM_BANK_PARAMS_2 0x0454
-#define GT64260_SDRAM_BANK_PARAMS_3 0x0458
-
-/* SDRAM Error Report Registers */
-#define GT64260_SDRAM_ERR_DATA_LO 0x0484
-#define GT64260_SDRAM_ERR_DATA_HI 0x0480
-#define GT64260_SDRAM_ERR_ADDR 0x0490
-#define GT64260_SDRAM_ERR_ECC_RCVD 0x0488
-#define GT64260_SDRAM_ERR_ECC_CALC 0x048c
-#define GT64260_SDRAM_ERR_ECC_CNTL 0x0494
-#define GT64260_SDRAM_ERR_ECC_ERR_CNT 0x0498
-
-
-/*
- *****************************************************************************
- *
- * Device/BOOT Cotnroller Registers
- *
- *****************************************************************************
- */
-
-/* Device Control Registers */
-#define GT64260_DEV_BANK_PARAMS_0 0x045c
-#define GT64260_DEV_BANK_PARAMS_1 0x0460
-#define GT64260_DEV_BANK_PARAMS_2 0x0464
-#define GT64260_DEV_BANK_PARAMS_3 0x0468
-#define GT64260_DEV_BOOT_PARAMS 0x046c
-#define GT64260_DEV_IF_CNTL 0x04c0
-#define GT64260_DEV_IF_XBAR_CNTL_LO 0x04c8
-#define GT64260_DEV_IF_XBAR_CNTL_HI 0x04cc
-#define GT64260_DEV_IF_XBAR_CNTL_TO 0x04c4
-
-/* Device Interrupt Registers */
-#define GT64260_DEV_INTR_CAUSE 0x04d0
-#define GT64260_DEV_INTR_MASK 0x04d4
-#define GT64260_DEV_INTR_ERR_ADDR 0x04d8
-
-
-/*
- *****************************************************************************
- *
- * PCI Bridge Interface Registers
- *
- *****************************************************************************
- */
-
-/* PCI Configuration Access Registers */
-#define GT64260_PCI_0_CONFIG_ADDR 0x0cf8
-#define GT64260_PCI_0_CONFIG_DATA 0x0cfc
-#define GT64260_PCI_0_IACK 0x0c34
-
-#define GT64260_PCI_1_CONFIG_ADDR 0x0c78
-#define GT64260_PCI_1_CONFIG_DATA 0x0c7c
-#define GT64260_PCI_1_IACK 0x0cb4
-
-/* PCI Control Registers */
-#define GT64260_PCI_0_CMD 0x0c00
-#define GT64260_PCI_0_MODE 0x0d00
-#define GT64260_PCI_0_TO_RETRY 0x0c04
-#define GT64260_PCI_0_RD_BUF_DISCARD_TIMER 0x0d04
-#define GT64260_PCI_0_MSI_TRIGGER_TIMER 0x0c38
-#define GT64260_PCI_0_ARBITER_CNTL 0x1d00
-#define GT64260_PCI_0_XBAR_CNTL_LO 0x1d08
-#define GT64260_PCI_0_XBAR_CNTL_HI 0x1d0c
-#define GT64260_PCI_0_XBAR_CNTL_TO 0x1d04
-#define GT64260_PCI_0_RD_RESP_XBAR_CNTL_LO 0x1d18
-#define GT64260_PCI_0_RD_RESP_XBAR_CNTL_HI 0x1d1c
-#define GT64260_PCI_0_SYNC_BARRIER 0x1d10
-#define GT64260_PCI_0_P2P_CONFIG 0x1d14
-#define GT64260_PCI_0_P2P_SWAP_CNTL 0x1d54
-
-#define GT64260_PCI_1_CMD 0x0c80
-#define GT64260_PCI_1_MODE 0x0d80
-#define GT64260_PCI_1_TO_RETRY 0x0c84
-#define GT64260_PCI_1_RD_BUF_DISCARD_TIMER 0x0d84
-#define GT64260_PCI_1_MSI_TRIGGER_TIMER 0x0cb8
-#define GT64260_PCI_1_ARBITER_CNTL 0x1d80
-#define GT64260_PCI_1_XBAR_CNTL_LO 0x1d88
-#define GT64260_PCI_1_XBAR_CNTL_HI 0x1d8c
-#define GT64260_PCI_1_XBAR_CNTL_TO 0x1d84
-#define GT64260_PCI_1_RD_RESP_XBAR_CNTL_LO 0x1d98
-#define GT64260_PCI_1_RD_RESP_XBAR_CNTL_HI 0x1d9c
-#define GT64260_PCI_1_SYNC_BARRIER 0x1d90
-#define GT64260_PCI_1_P2P_CONFIG 0x1d94
-#define GT64260_PCI_1_P2P_SWAP_CNTL 0x1dd4
-
-/* PCI Access Control Regions Registers */
-#define GT64260_PCI_ACC_CNTL_WINDOWS 8
-
-#define GT64260_PCI_ACC_CNTL_PREFETCHEN (1<<12)
-#define GT64260_PCI_ACC_CNTL_DREADEN (1<<13)
-#define GT64260_PCI_ACC_CNTL_RDPREFETCH (1<<16)
-#define GT64260_PCI_ACC_CNTL_RDLINEPREFETCH (1<<17)
-#define GT64260_PCI_ACC_CNTL_RDMULPREFETCH (1<<18)
-#define GT64260_PCI_ACC_CNTL_MBURST_4_WORDS 0x00000000
-#define GT64260_PCI_ACC_CNTL_MBURST_8_WORDS 0x00100000
-#define GT64260_PCI_ACC_CNTL_MBURST_16_WORDS 0x00200000
-#define GT64260_PCI_ACC_CNTL_MBURST_MASK 0x00300000
-#define GT64260_PCI_ACC_CNTL_SWAP_BYTE 0x00000000
-#define GT64260_PCI_ACC_CNTL_SWAP_NONE 0x01000000
-#define GT64260_PCI_ACC_CNTL_SWAP_BYTE_WORD 0x02000000
-#define GT64260_PCI_ACC_CNTL_SWAP_WORD 0x03000000
-#define GT64260_PCI_ACC_CNTL_SWAP_MASK 0x03000000
-#define GT64260_PCI_ACC_CNTL_ACCPROT (1<<28)
-#define GT64260_PCI_ACC_CNTL_WRPROT (1<<29)
-
-#define GT64260_PCI_ACC_CNTL_ALL_BITS (GT64260_PCI_ACC_CNTL_PREFETCHEN | \
- GT64260_PCI_ACC_CNTL_DREADEN | \
- GT64260_PCI_ACC_CNTL_RDPREFETCH | \
- GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |\
- GT64260_PCI_ACC_CNTL_RDMULPREFETCH | \
- GT64260_PCI_ACC_CNTL_MBURST_MASK | \
- GT64260_PCI_ACC_CNTL_SWAP_MASK | \
- GT64260_PCI_ACC_CNTL_ACCPROT| \
- GT64260_PCI_ACC_CNTL_WRPROT)
-
-#define GT64260_PCI_0_ACC_CNTL_0_BASE_LO 0x1e00
-#define GT64260_PCI_0_ACC_CNTL_0_BASE_HI 0x1e04
-#define GT64260_PCI_0_ACC_CNTL_0_TOP 0x1e08
-#define GT64260_PCI_0_ACC_CNTL_1_BASE_LO 0x1e10
-#define GT64260_PCI_0_ACC_CNTL_1_BASE_HI 0x1e14
-#define GT64260_PCI_0_ACC_CNTL_1_TOP 0x1e18
-#define GT64260_PCI_0_ACC_CNTL_2_BASE_LO 0x1e20
-#define GT64260_PCI_0_ACC_CNTL_2_BASE_HI 0x1e24
-#define GT64260_PCI_0_ACC_CNTL_2_TOP 0x1e28
-#define GT64260_PCI_0_ACC_CNTL_3_BASE_LO 0x1e30
-#define GT64260_PCI_0_ACC_CNTL_3_BASE_HI 0x1e34
-#define GT64260_PCI_0_ACC_CNTL_3_TOP 0x1e38
-#define GT64260_PCI_0_ACC_CNTL_4_BASE_LO 0x1e40
-#define GT64260_PCI_0_ACC_CNTL_4_BASE_HI 0x1e44
-#define GT64260_PCI_0_ACC_CNTL_4_TOP 0x1e48
-#define GT64260_PCI_0_ACC_CNTL_5_BASE_LO 0x1e50
-#define GT64260_PCI_0_ACC_CNTL_5_BASE_HI 0x1e54
-#define GT64260_PCI_0_ACC_CNTL_5_TOP 0x1e58
-#define GT64260_PCI_0_ACC_CNTL_6_BASE_LO 0x1e60
-#define GT64260_PCI_0_ACC_CNTL_6_BASE_HI 0x1e64
-#define GT64260_PCI_0_ACC_CNTL_6_TOP 0x1e68
-#define GT64260_PCI_0_ACC_CNTL_7_BASE_LO 0x1e70
-#define GT64260_PCI_0_ACC_CNTL_7_BASE_HI 0x1e74
-#define GT64260_PCI_0_ACC_CNTL_7_TOP 0x1e78
-
-#define GT64260_PCI_1_ACC_CNTL_0_BASE_LO 0x1e80
-#define GT64260_PCI_1_ACC_CNTL_0_BASE_HI 0x1e84
-#define GT64260_PCI_1_ACC_CNTL_0_TOP 0x1e88
-#define GT64260_PCI_1_ACC_CNTL_1_BASE_LO 0x1e90
-#define GT64260_PCI_1_ACC_CNTL_1_BASE_HI 0x1e94
-#define GT64260_PCI_1_ACC_CNTL_1_TOP 0x1e98
-#define GT64260_PCI_1_ACC_CNTL_2_BASE_LO 0x1ea0
-#define GT64260_PCI_1_ACC_CNTL_2_BASE_HI 0x1ea4
-#define GT64260_PCI_1_ACC_CNTL_2_TOP 0x1ea8
-#define GT64260_PCI_1_ACC_CNTL_3_BASE_LO 0x1eb0
-#define GT64260_PCI_1_ACC_CNTL_3_BASE_HI 0x1eb4
-#define GT64260_PCI_1_ACC_CNTL_3_TOP 0x1eb8
-#define GT64260_PCI_1_ACC_CNTL_4_BASE_LO 0x1ec0
-#define GT64260_PCI_1_ACC_CNTL_4_BASE_HI 0x1ec4
-#define GT64260_PCI_1_ACC_CNTL_4_TOP 0x1ec8
-#define GT64260_PCI_1_ACC_CNTL_5_BASE_LO 0x1ed0
-#define GT64260_PCI_1_ACC_CNTL_5_BASE_HI 0x1ed4
-#define GT64260_PCI_1_ACC_CNTL_5_TOP 0x1ed8
-#define GT64260_PCI_1_ACC_CNTL_6_BASE_LO 0x1ee0
-#define GT64260_PCI_1_ACC_CNTL_6_BASE_HI 0x1ee4
-#define GT64260_PCI_1_ACC_CNTL_6_TOP 0x1ee8
-#define GT64260_PCI_1_ACC_CNTL_7_BASE_LO 0x1ef0
-#define GT64260_PCI_1_ACC_CNTL_7_BASE_HI 0x1ef4
-#define GT64260_PCI_1_ACC_CNTL_7_TOP 0x1ef8
-
-/* PCI Snoop Control Registers */
-#define GT64260_PCI_SNOOP_WINDOWS 4
-
-#define GT64260_PCI_SNOOP_NONE 0x00000000
-#define GT64260_PCI_SNOOP_WT 0x00001000
-#define GT64260_PCI_SNOOP_WB 0x00002000
-
-#define GT64260_PCI_0_SNOOP_0_BASE_LO 0x1f00
-#define GT64260_PCI_0_SNOOP_0_BASE_HI 0x1f04
-#define GT64260_PCI_0_SNOOP_0_TOP 0x1f08
-#define GT64260_PCI_0_SNOOP_1_BASE_LO 0x1f10
-#define GT64260_PCI_0_SNOOP_1_BASE_HI 0x1f14
-#define GT64260_PCI_0_SNOOP_1_TOP 0x1f18
-#define GT64260_PCI_0_SNOOP_2_BASE_LO 0x1f20
-#define GT64260_PCI_0_SNOOP_2_BASE_HI 0x1f24
-#define GT64260_PCI_0_SNOOP_2_TOP 0x1f28
-#define GT64260_PCI_0_SNOOP_3_BASE_LO 0x1f30
-#define GT64260_PCI_0_SNOOP_3_BASE_HI 0x1f34
-#define GT64260_PCI_0_SNOOP_3_TOP 0x1f38
-
-#define GT64260_PCI_1_SNOOP_0_BASE_LO 0x1f80
-#define GT64260_PCI_1_SNOOP_0_BASE_HI 0x1f84
-#define GT64260_PCI_1_SNOOP_0_TOP 0x1f88
-#define GT64260_PCI_1_SNOOP_1_BASE_LO 0x1f90
-#define GT64260_PCI_1_SNOOP_1_BASE_HI 0x1f94
-#define GT64260_PCI_1_SNOOP_1_TOP 0x1f98
-#define GT64260_PCI_1_SNOOP_2_BASE_LO 0x1fa0
-#define GT64260_PCI_1_SNOOP_2_BASE_HI 0x1fa4
-#define GT64260_PCI_1_SNOOP_2_TOP 0x1fa8
-#define GT64260_PCI_1_SNOOP_3_BASE_LO 0x1fb0
-#define GT64260_PCI_1_SNOOP_3_BASE_HI 0x1fb4
-#define GT64260_PCI_1_SNOOP_3_TOP 0x1fb8
-
-/* PCI Error Report Registers */
-#define GT64260_PCI_0_ERR_SERR_MASK 0x0c28
-#define GT64260_PCI_0_ERR_ADDR_LO 0x1d40
-#define GT64260_PCI_0_ERR_ADDR_HI 0x1d44
-#define GT64260_PCI_0_ERR_DATA_LO 0x1d48
-#define GT64260_PCI_0_ERR_DATA_HI 0x1d4c
-#define GT64260_PCI_0_ERR_CMD 0x1d50
-#define GT64260_PCI_0_ERR_CAUSE 0x1d58
-#define GT64260_PCI_0_ERR_MASK 0x1d5c
-
-#define GT64260_PCI_1_ERR_SERR_MASK 0x0ca8
-#define GT64260_PCI_1_ERR_ADDR_LO 0x1dc0
-#define GT64260_PCI_1_ERR_ADDR_HI 0x1dc4
-#define GT64260_PCI_1_ERR_DATA_LO 0x1dc8
-#define GT64260_PCI_1_ERR_DATA_HI 0x1dcc
-#define GT64260_PCI_1_ERR_CMD 0x1dd0
-#define GT64260_PCI_1_ERR_CAUSE 0x1dd8
-#define GT64260_PCI_1_ERR_MASK 0x1ddc
-
-/* PCI Slave Address Decoding Registers */
-#define GT64260_PCI_SCS_WINDOWS 4
-#define GT64260_PCI_CS_WINDOWS 4
-#define GT64260_PCI_BOOT_WINDOWS 1
-#define GT64260_PCI_P2P_MEM_WINDOWS 2
-#define GT64260_PCI_P2P_IO_WINDOWS 1
-#define GT64260_PCI_DAC_SCS_WINDOWS 4
-#define GT64260_PCI_DAC_CS_WINDOWS 4
-#define GT64260_PCI_DAC_BOOT_WINDOWS 1
-#define GT64260_PCI_DAC_P2P_MEM_WINDOWS 2
-
-#define GT64260_PCI_0_SLAVE_SCS_0_SIZE 0x0c08
-#define GT64260_PCI_0_SLAVE_SCS_1_SIZE 0x0d08
-#define GT64260_PCI_0_SLAVE_SCS_2_SIZE 0x0c0c
-#define GT64260_PCI_0_SLAVE_SCS_3_SIZE 0x0d0c
-#define GT64260_PCI_0_SLAVE_CS_0_SIZE 0x0c10
-#define GT64260_PCI_0_SLAVE_CS_1_SIZE 0x0d10
-#define GT64260_PCI_0_SLAVE_CS_2_SIZE 0x0d18
-#define GT64260_PCI_0_SLAVE_CS_3_SIZE 0x0c14
-#define GT64260_PCI_0_SLAVE_BOOT_SIZE 0x0d14
-#define GT64260_PCI_0_SLAVE_P2P_MEM_0_SIZE 0x0d1c
-#define GT64260_PCI_0_SLAVE_P2P_MEM_1_SIZE 0x0d20
-#define GT64260_PCI_0_SLAVE_P2P_IO_SIZE 0x0d24
-#define GT64260_PCI_0_SLAVE_CPU_SIZE 0x0d28
-
-#define GT64260_PCI_0_SLAVE_DAC_SCS_0_SIZE 0x0e00
-#define GT64260_PCI_0_SLAVE_DAC_SCS_1_SIZE 0x0e04
-#define GT64260_PCI_0_SLAVE_DAC_SCS_2_SIZE 0x0e08
-#define GT64260_PCI_0_SLAVE_DAC_SCS_3_SIZE 0x0e0c
-#define GT64260_PCI_0_SLAVE_DAC_CS_0_SIZE 0x0e10
-#define GT64260_PCI_0_SLAVE_DAC_CS_1_SIZE 0x0e14
-#define GT64260_PCI_0_SLAVE_DAC_CS_2_SIZE 0x0e18
-#define GT64260_PCI_0_SLAVE_DAC_CS_3_SIZE 0x0e1c
-#define GT64260_PCI_0_SLAVE_DAC_BOOT_SIZE 0x0e20
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE 0x0e24
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE 0x0e28
-#define GT64260_PCI_0_SLAVE_DAC_CPU_SIZE 0x0e2c
-
-#define GT64260_PCI_0_SLAVE_EXP_ROM_SIZE 0x0d2c
-
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0 (1<<0)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_1 (1<<1)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_2 (1<<2)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_3 (1<<3)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_0 (1<<4)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_1 (1<<5)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_2 (1<<6)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_3 (1<<7)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_BOOT (1<<8)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_REG_MEM (1<<9)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_REG_IO (1<<10)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_MEM_0 (1<<11)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_MEM_1 (1<<12)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_IO (1<<13)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_CPU (1<<14)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_0 (1<<15)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_1 (1<<16)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_2 (1<<17)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_3 (1<<18)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_0 (1<<19)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_1 (1<<20)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_2 (1<<21)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_3 (1<<22)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_BOOT (1<<23)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_P2P_MEM_0 (1<<24)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_P2P_MEM_1 (1<<25)
-#define GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CPU (1<<26)
-
-#define GT64260_PCI_0_SLAVE_BAR_REG_ENABLES 0x0c3c
-#define GT64260_PCI_0_SLAVE_SCS_0_REMAP 0x0c48
-#define GT64260_PCI_0_SLAVE_SCS_1_REMAP 0x0d48
-#define GT64260_PCI_0_SLAVE_SCS_2_REMAP 0x0c4c
-#define GT64260_PCI_0_SLAVE_SCS_3_REMAP 0x0d4c
-#define GT64260_PCI_0_SLAVE_CS_0_REMAP 0x0c50
-#define GT64260_PCI_0_SLAVE_CS_1_REMAP 0x0d50
-#define GT64260_PCI_0_SLAVE_CS_2_REMAP 0x0d58
-#define GT64260_PCI_0_SLAVE_CS_3_REMAP 0x0c54
-#define GT64260_PCI_0_SLAVE_BOOT_REMAP 0x0d54
-#define GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_LO 0x0d5c
-#define GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_HI 0x0d60
-#define GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_LO 0x0d64
-#define GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_HI 0x0d68
-#define GT64260_PCI_0_SLAVE_P2P_IO_REMAP 0x0d6c
-#define GT64260_PCI_0_SLAVE_CPU_REMAP 0x0d70
-
-#define GT64260_PCI_0_SLAVE_DAC_SCS_0_REMAP 0x0f00
-#define GT64260_PCI_0_SLAVE_DAC_SCS_1_REMAP 0x0f04
-#define GT64260_PCI_0_SLAVE_DAC_SCS_2_REMAP 0x0f08
-#define GT64260_PCI_0_SLAVE_DAC_SCS_3_REMAP 0x0f0c
-#define GT64260_PCI_0_SLAVE_DAC_CS_0_REMAP 0x0f10
-#define GT64260_PCI_0_SLAVE_DAC_CS_1_REMAP 0x0f14
-#define GT64260_PCI_0_SLAVE_DAC_CS_2_REMAP 0x0f18
-#define GT64260_PCI_0_SLAVE_DAC_CS_3_REMAP 0x0f1c
-#define GT64260_PCI_0_SLAVE_DAC_BOOT_REMAP 0x0f20
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO 0x0f24
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_HI 0x0f28
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO 0x0f2c
-#define GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_HI 0x0f30
-#define GT64260_PCI_0_SLAVE_DAC_CPU_REMAP 0x0f34
-
-#define GT64260_PCI_0_SLAVE_EXP_ROM_REMAP 0x0f38
-#define GT64260_PCI_0_SLAVE_PCI_DECODE_CNTL 0x0d3c
-
-#define GT64260_PCI_1_SLAVE_SCS_0_SIZE 0x0c88
-#define GT64260_PCI_1_SLAVE_SCS_1_SIZE 0x0d88
-#define GT64260_PCI_1_SLAVE_SCS_2_SIZE 0x0c8c
-#define GT64260_PCI_1_SLAVE_SCS_3_SIZE 0x0d8c
-#define GT64260_PCI_1_SLAVE_CS_0_SIZE 0x0c90
-#define GT64260_PCI_1_SLAVE_CS_1_SIZE 0x0d90
-#define GT64260_PCI_1_SLAVE_CS_2_SIZE 0x0d98
-#define GT64260_PCI_1_SLAVE_CS_3_SIZE 0x0c94
-#define GT64260_PCI_1_SLAVE_BOOT_SIZE 0x0d94
-#define GT64260_PCI_1_SLAVE_P2P_MEM_0_SIZE 0x0d9c
-#define GT64260_PCI_1_SLAVE_P2P_MEM_1_SIZE 0x0da0
-#define GT64260_PCI_1_SLAVE_P2P_IO_SIZE 0x0da4
-#define GT64260_PCI_1_SLAVE_CPU_SIZE 0x0da8
-
-#define GT64260_PCI_1_SLAVE_DAC_SCS_0_SIZE 0x0e80
-#define GT64260_PCI_1_SLAVE_DAC_SCS_1_SIZE 0x0e84
-#define GT64260_PCI_1_SLAVE_DAC_SCS_2_SIZE 0x0e88
-#define GT64260_PCI_1_SLAVE_DAC_SCS_3_SIZE 0x0e8c
-#define GT64260_PCI_1_SLAVE_DAC_CS_0_SIZE 0x0e90
-#define GT64260_PCI_1_SLAVE_DAC_CS_1_SIZE 0x0e94
-#define GT64260_PCI_1_SLAVE_DAC_CS_2_SIZE 0x0e98
-#define GT64260_PCI_1_SLAVE_DAC_CS_3_SIZE 0x0e9c
-#define GT64260_PCI_1_SLAVE_DAC_BOOT_SIZE 0x0ea0
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_SIZE 0x0ea4
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_SIZE 0x0ea8
-#define GT64260_PCI_1_SLAVE_DAC_CPU_SIZE 0x0eac
-
-#define GT64260_PCI_1_SLAVE_EXP_ROM_SIZE 0x0dac
-
-#define GT64260_PCI_1_SLAVE_BAR_REG_ENABLES 0x0cbc
-#define GT64260_PCI_1_SLAVE_SCS_0_REMAP 0x0cc8
-#define GT64260_PCI_1_SLAVE_SCS_1_REMAP 0x0dc8
-#define GT64260_PCI_1_SLAVE_SCS_2_REMAP 0x0ccc
-#define GT64260_PCI_1_SLAVE_SCS_3_REMAP 0x0dcc
-#define GT64260_PCI_1_SLAVE_CS_0_REMAP 0x0cd0
-#define GT64260_PCI_1_SLAVE_CS_1_REMAP 0x0dd0
-#define GT64260_PCI_1_SLAVE_CS_2_REMAP 0x0dd8
-#define GT64260_PCI_1_SLAVE_CS_3_REMAP 0x0cd4
-#define GT64260_PCI_1_SLAVE_BOOT_REMAP 0x0dd4
-#define GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_LO 0x0ddc
-#define GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_HI 0x0de0
-#define GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_LO 0x0de4
-#define GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_HI 0x0de8
-#define GT64260_PCI_1_SLAVE_P2P_IO_REMAP 0x0dec
-#define GT64260_PCI_1_SLAVE_CPU_REMAP 0x0df0
-
-#define GT64260_PCI_1_SLAVE_DAC_SCS_0_REMAP 0x0f80
-#define GT64260_PCI_1_SLAVE_DAC_SCS_1_REMAP 0x0f84
-#define GT64260_PCI_1_SLAVE_DAC_SCS_2_REMAP 0x0f88
-#define GT64260_PCI_1_SLAVE_DAC_SCS_3_REMAP 0x0f8c
-#define GT64260_PCI_1_SLAVE_DAC_CS_0_REMAP 0x0f90
-#define GT64260_PCI_1_SLAVE_DAC_CS_1_REMAP 0x0f94
-#define GT64260_PCI_1_SLAVE_DAC_CS_2_REMAP 0x0f98
-#define GT64260_PCI_1_SLAVE_DAC_CS_3_REMAP 0x0f9c
-#define GT64260_PCI_1_SLAVE_DAC_BOOT_REMAP 0x0fa0
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_REMAP_LO 0x0fa4
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_REMAP_HI 0x0fa8
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_REMAP_LO 0x0fac
-#define GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_REMAP_HI 0x0fb0
-#define GT64260_PCI_1_SLAVE_DAC_CPU_REMAP 0x0fb4
-
-#define GT64260_PCI_1_SLAVE_EXP_ROM_REMAP 0x0fb8
-#define GT64260_PCI_1_SLAVE_PCI_DECODE_CNTL 0x0dbc
-
-
-/*
- *****************************************************************************
- *
- * I2O Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-
-/*
- *****************************************************************************
- *
- * DMA Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- * Timer/Counter Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- * Communications Controller (Enet, Serial, etc.) Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_ENET_0_CNTL_LO 0xf200
-#define GT64260_ENET_0_CNTL_HI 0xf204
-#define GT64260_ENET_0_RX_BUF_PCI_ADDR_HI 0xf208
-#define GT64260_ENET_0_TX_BUF_PCI_ADDR_HI 0xf20c
-#define GT64260_ENET_0_RX_DESC_ADDR_HI 0xf210
-#define GT64260_ENET_0_TX_DESC_ADDR_HI 0xf214
-#define GT64260_ENET_0_HASH_TAB_PCI_ADDR_HI 0xf218
-#define GT64260_ENET_1_CNTL_LO 0xf220
-#define GT64260_ENET_1_CNTL_HI 0xf224
-#define GT64260_ENET_1_RX_BUF_PCI_ADDR_HI 0xf228
-#define GT64260_ENET_1_TX_BUF_PCI_ADDR_HI 0xf22c
-#define GT64260_ENET_1_RX_DESC_ADDR_HI 0xf230
-#define GT64260_ENET_1_TX_DESC_ADDR_HI 0xf234
-#define GT64260_ENET_1_HASH_TAB_PCI_ADDR_HI 0xf238
-#define GT64260_ENET_2_CNTL_LO 0xf240
-#define GT64260_ENET_2_CNTL_HI 0xf244
-#define GT64260_ENET_2_RX_BUF_PCI_ADDR_HI 0xf248
-#define GT64260_ENET_2_TX_BUF_PCI_ADDR_HI 0xf24c
-#define GT64260_ENET_2_RX_DESC_ADDR_HI 0xf250
-#define GT64260_ENET_2_TX_DESC_ADDR_HI 0xf254
-#define GT64260_ENET_2_HASH_TAB_PCI_ADDR_HI 0xf258
-
-#define GT64260_MPSC_0_CNTL_LO 0xf280
-#define GT64260_MPSC_0_CNTL_HI 0xf284
-#define GT64260_MPSC_0_RX_BUF_PCI_ADDR_HI 0xf288
-#define GT64260_MPSC_0_TX_BUF_PCI_ADDR_HI 0xf28c
-#define GT64260_MPSC_0_RX_DESC_ADDR_HI 0xf290
-#define GT64260_MPSC_0_TX_DESC_ADDR_HI 0xf294
-#define GT64260_MPSC_1_CNTL_LO 0xf2c0
-#define GT64260_MPSC_1_CNTL_HI 0xf2c4
-#define GT64260_MPSC_1_RX_BUF_PCI_ADDR_HI 0xf2c8
-#define GT64260_MPSC_1_TX_BUF_PCI_ADDR_HI 0xf2cc
-#define GT64260_MPSC_1_RX_DESC_ADDR_HI 0xf2d0
-#define GT64260_MPSC_1_TX_DESC_ADDR_HI 0xf2d4
-
-#define GT64260_SER_INIT_PCI_ADDR_HI 0xf320
-#define GT64260_SER_INIT_LAST_DATA 0xf324
-#define GT64260_SER_INIT_CONTROL 0xf328
-#define GT64260_SER_INIT_STATUS 0xf32c
-
-#define GT64260_COMM_ARBITER_CNTL 0xf300
-#define GT64260_COMM_CONFIG 0xb40c
-#define GT64260_COMM_XBAR_TO 0xf304
-#define GT64260_COMM_INTR_CAUSE 0xf310
-#define GT64260_COMM_INTR_MASK 0xf314
-#define GT64260_COMM_ERR_ADDR 0xf318
-
-
-/*
- *****************************************************************************
- *
- * Fast Ethernet Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_ENET_PHY_ADDR 0x2000
-#define GT64260_ENET_ESMIR 0x2010
-
-#define GT64260_ENET_E0PCR 0x2400
-#define GT64260_ENET_E0PCXR 0x2408
-#define GT64260_ENET_E0PCMR 0x2410
-#define GT64260_ENET_E0PSR 0x2418
-#define GT64260_ENET_E0SPR 0x2420
-#define GT64260_ENET_E0HTPR 0x2428
-#define GT64260_ENET_E0FCSAL 0x2430
-#define GT64260_ENET_E0FCSAH 0x2438
-#define GT64260_ENET_E0SDCR 0x2440
-#define GT64260_ENET_E0SDCMR 0x2448
-#define GT64260_ENET_E0ICR 0x2450
-#define GT64260_ENET_E0IMR 0x2458
-#define GT64260_ENET_E0FRDP0 0x2480
-#define GT64260_ENET_E0FRDP1 0x2484
-#define GT64260_ENET_E0FRDP2 0x2488
-#define GT64260_ENET_E0FRDP3 0x248c
-#define GT64260_ENET_E0CRDP0 0x24a0
-#define GT64260_ENET_E0CRDP1 0x24a4
-#define GT64260_ENET_E0CRDP2 0x24a8
-#define GT64260_ENET_E0CRDP3 0x24ac
-#define GT64260_ENET_E0CTDP0 0x24e0
-#define GT64260_ENET_E0CTDP1 0x24e4
-#define GT64260_ENET_0_DSCP2P0L 0x2460
-#define GT64260_ENET_0_DSCP2P0H 0x2464
-#define GT64260_ENET_0_DSCP2P1L 0x2468
-#define GT64260_ENET_0_DSCP2P1H 0x246c
-#define GT64260_ENET_0_VPT2P 0x2470
-#define GT64260_ENET_0_MIB_CTRS 0x2500
-
-#define GT64260_ENET_E1PCR 0x2800
-#define GT64260_ENET_E1PCXR 0x2808
-#define GT64260_ENET_E1PCMR 0x2810
-#define GT64260_ENET_E1PSR 0x2818
-#define GT64260_ENET_E1SPR 0x2820
-#define GT64260_ENET_E1HTPR 0x2828
-#define GT64260_ENET_E1FCSAL 0x2830
-#define GT64260_ENET_E1FCSAH 0x2838
-#define GT64260_ENET_E1SDCR 0x2840
-#define GT64260_ENET_E1SDCMR 0x2848
-#define GT64260_ENET_E1ICR 0x2850
-#define GT64260_ENET_E1IMR 0x2858
-#define GT64260_ENET_E1FRDP0 0x2880
-#define GT64260_ENET_E1FRDP1 0x2884
-#define GT64260_ENET_E1FRDP2 0x2888
-#define GT64260_ENET_E1FRDP3 0x288c
-#define GT64260_ENET_E1CRDP0 0x28a0
-#define GT64260_ENET_E1CRDP1 0x28a4
-#define GT64260_ENET_E1CRDP2 0x28a8
-#define GT64260_ENET_E1CRDP3 0x28ac
-#define GT64260_ENET_E1CTDP0 0x28e0
-#define GT64260_ENET_E1CTDP1 0x28e4
-#define GT64260_ENET_1_DSCP2P0L 0x2860
-#define GT64260_ENET_1_DSCP2P0H 0x2864
-#define GT64260_ENET_1_DSCP2P1L 0x2868
-#define GT64260_ENET_1_DSCP2P1H 0x286c
-#define GT64260_ENET_1_VPT2P 0x2870
-#define GT64260_ENET_1_MIB_CTRS 0x2900
-
-#define GT64260_ENET_E2PCR 0x2c00
-#define GT64260_ENET_E2PCXR 0x2c08
-#define GT64260_ENET_E2PCMR 0x2c10
-#define GT64260_ENET_E2PSR 0x2c18
-#define GT64260_ENET_E2SPR 0x2c20
-#define GT64260_ENET_E2HTPR 0x2c28
-#define GT64260_ENET_E2FCSAL 0x2c30
-#define GT64260_ENET_E2FCSAH 0x2c38
-#define GT64260_ENET_E2SDCR 0x2c40
-#define GT64260_ENET_E2SDCMR 0x2c48
-#define GT64260_ENET_E2ICR 0x2c50
-#define GT64260_ENET_E2IMR 0x2c58
-#define GT64260_ENET_E2FRDP0 0x2c80
-#define GT64260_ENET_E2FRDP1 0x2c84
-#define GT64260_ENET_E2FRDP2 0x2c88
-#define GT64260_ENET_E2FRDP3 0x2c8c
-#define GT64260_ENET_E2CRDP0 0x2ca0
-#define GT64260_ENET_E2CRDP1 0x2ca4
-#define GT64260_ENET_E2CRDP2 0x2ca8
-#define GT64260_ENET_E2CRDP3 0x2cac
-#define GT64260_ENET_E2CTDP0 0x2ce0
-#define GT64260_ENET_E2CTDP1 0x2ce4
-#define GT64260_ENET_2_DSCP2P0L 0x2c60
-#define GT64260_ENET_2_DSCP2P0H 0x2c64
-#define GT64260_ENET_2_DSCP2P1L 0x2c68
-#define GT64260_ENET_2_DSCP2P1H 0x2c6c
-#define GT64260_ENET_2_VPT2P 0x2c70
-#define GT64260_ENET_2_MIB_CTRS 0x2d00
-
-
-/*
- *****************************************************************************
- *
- * Multi-Protocol Serial Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* Signal Routing */
-#define GT64260_MPSC_MRR 0xb400
-#define GT64260_MPSC_RCRR 0xb404
-#define GT64260_MPSC_TCRR 0xb408
-
-/* Main Configuratino Registers */
-#define GT64260_MPSC_0_MMCRL 0x8000
-#define GT64260_MPSC_0_MMCRH 0x8004
-#define GT64260_MPSC_0_MPCR 0x8008
-#define GT64260_MPSC_0_CHR_1 0x800c
-#define GT64260_MPSC_0_CHR_2 0x8010
-#define GT64260_MPSC_0_CHR_3 0x8014
-#define GT64260_MPSC_0_CHR_4 0x8018
-#define GT64260_MPSC_0_CHR_5 0x801c
-#define GT64260_MPSC_0_CHR_6 0x8020
-#define GT64260_MPSC_0_CHR_7 0x8024
-#define GT64260_MPSC_0_CHR_8 0x8028
-#define GT64260_MPSC_0_CHR_9 0x802c
-#define GT64260_MPSC_0_CHR_10 0x8030
-#define GT64260_MPSC_0_CHR_11 0x8034
-
-#define GT64260_MPSC_1_MMCRL 0x9000
-#define GT64260_MPSC_1_MMCRH 0x9004
-#define GT64260_MPSC_1_MPCR 0x9008
-#define GT64260_MPSC_1_CHR_1 0x900c
-#define GT64260_MPSC_1_CHR_2 0x9010
-#define GT64260_MPSC_1_CHR_3 0x9014
-#define GT64260_MPSC_1_CHR_4 0x9018
-#define GT64260_MPSC_1_CHR_5 0x901c
-#define GT64260_MPSC_1_CHR_6 0x9020
-#define GT64260_MPSC_1_CHR_7 0x9024
-#define GT64260_MPSC_1_CHR_8 0x9028
-#define GT64260_MPSC_1_CHR_9 0x902c
-#define GT64260_MPSC_1_CHR_10 0x9030
-#define GT64260_MPSC_1_CHR_11 0x9034
-
-#define GT64260_MPSC_0_INTR_CAUSE 0xb804
-#define GT64260_MPSC_0_INTR_MASK 0xb884
-#define GT64260_MPSC_1_INTR_CAUSE 0xb80c
-#define GT64260_MPSC_1_INTR_MASK 0xb88c
-
-#define GT64260_MPSC_UART_CR_TEV (1<<1)
-#define GT64260_MPSC_UART_CR_TA (1<<7)
-#define GT64260_MPSC_UART_CR_TTCS (1<<9)
-#define GT64260_MPSC_UART_CR_REV (1<<17)
-#define GT64260_MPSC_UART_CR_RA (1<<23)
-#define GT64260_MPSC_UART_CR_CRD (1<<25)
-#define GT64260_MPSC_UART_CR_EH (1<<31)
-
-#define GT64260_MPSC_UART_ESR_CTS (1<<0)
-#define GT64260_MPSC_UART_ESR_CD (1<<1)
-#define GT64260_MPSC_UART_ESR_TIDLE (1<<3)
-#define GT64260_MPSC_UART_ESR_RHS (1<<5)
-#define GT64260_MPSC_UART_ESR_RLS (1<<7)
-#define GT64260_MPSC_UART_ESR_RLIDL (1<<11)
-
-
-/*
- *****************************************************************************
- *
- * Serial DMA Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_SDMA_0_SDC 0x4000
-#define GT64260_SDMA_0_SDCM 0x4008
-#define GT64260_SDMA_0_RX_DESC 0x4800
-#define GT64260_SDMA_0_RX_BUF_PTR 0x4808
-#define GT64260_SDMA_0_SCRDP 0x4810
-#define GT64260_SDMA_0_TX_DESC 0x4c00
-#define GT64260_SDMA_0_SCTDP 0x4c10
-#define GT64260_SDMA_0_SFTDP 0x4c14
-
-#define GT64260_SDMA_1_SDC 0x6000
-#define GT64260_SDMA_1_SDCM 0x6008
-#define GT64260_SDMA_1_RX_DESC 0x6800
-#define GT64260_SDMA_1_RX_BUF_PTR 0x6808
-#define GT64260_SDMA_1_SCRDP 0x6810
-#define GT64260_SDMA_1_TX_DESC 0x6c00
-#define GT64260_SDMA_1_SCTDP 0x6c10
-#define GT64260_SDMA_1_SFTDP 0x6c14
-
-#define GT64260_SDMA_INTR_CAUSE 0xb800
-#define GT64260_SDMA_INTR_MASK 0xb880
-
-#define GT64260_SDMA_DESC_CMDSTAT_PE (1<<0)
-#define GT64260_SDMA_DESC_CMDSTAT_CDL (1<<1)
-#define GT64260_SDMA_DESC_CMDSTAT_FR (1<<3)
-#define GT64260_SDMA_DESC_CMDSTAT_OR (1<<6)
-#define GT64260_SDMA_DESC_CMDSTAT_BR (1<<9)
-#define GT64260_SDMA_DESC_CMDSTAT_MI (1<<10)
-#define GT64260_SDMA_DESC_CMDSTAT_A (1<<11)
-#define GT64260_SDMA_DESC_CMDSTAT_AM (1<<12)
-#define GT64260_SDMA_DESC_CMDSTAT_CT (1<<13)
-#define GT64260_SDMA_DESC_CMDSTAT_C (1<<14)
-#define GT64260_SDMA_DESC_CMDSTAT_ES (1<<15)
-#define GT64260_SDMA_DESC_CMDSTAT_L (1<<16)
-#define GT64260_SDMA_DESC_CMDSTAT_F (1<<17)
-#define GT64260_SDMA_DESC_CMDSTAT_P (1<<18)
-#define GT64260_SDMA_DESC_CMDSTAT_EI (1<<23)
-#define GT64260_SDMA_DESC_CMDSTAT_O (1<<31)
-
-#define GT64260_SDMA_SDC_RFT (1<<0)
-#define GT64260_SDMA_SDC_SFM (1<<1)
-#define GT64260_SDMA_SDC_BLMR (1<<6)
-#define GT64260_SDMA_SDC_BLMT (1<<7)
-#define GT64260_SDMA_SDC_POVR (1<<8)
-#define GT64260_SDMA_SDC_RIFB (1<<9)
-
-#define GT64260_SDMA_SDCM_ERD (1<<7)
-#define GT64260_SDMA_SDCM_AR (1<<15)
-#define GT64260_SDMA_SDCM_STD (1<<16)
-#define GT64260_SDMA_SDCM_TXD (1<<23)
-#define GT64260_SDMA_SDCM_AT (1<<31)
-
-#define GT64260_SDMA_0_CAUSE_RXBUF (1<<0)
-#define GT64260_SDMA_0_CAUSE_RXERR (1<<1)
-#define GT64260_SDMA_0_CAUSE_TXBUF (1<<2)
-#define GT64260_SDMA_0_CAUSE_TXEND (1<<3)
-#define GT64260_SDMA_1_CAUSE_RXBUF (1<<8)
-#define GT64260_SDMA_1_CAUSE_RXERR (1<<9)
-#define GT64260_SDMA_1_CAUSE_TXBUF (1<<10)
-#define GT64260_SDMA_1_CAUSE_TXEND (1<<11)
-
-
-/*
- *****************************************************************************
- *
- * Baud Rate Generator Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_BRG_0_BCR 0xb200
-#define GT64260_BRG_0_BTR 0xb204
-#define GT64260_BRG_1_BCR 0xb208
-#define GT64260_BRG_1_BTR 0xb20c
-#define GT64260_BRG_2_BCR 0xb210
-#define GT64260_BRG_2_BTR 0xb214
-
-#define GT64260_BRG_INTR_CAUSE 0xb834
-#define GT64260_BRG_INTR_MASK 0xb8b4
-
-
-/*
- *****************************************************************************
- *
- * Watchdog Timer Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_WDT_WDC 0xb410
-#define GT64260_WDT_WDV 0xb414
-
-
-/*
- *****************************************************************************
- *
- * General Purpose Pins Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_GPP_IO_CNTL 0xf100
-#define GT64260_GPP_LEVEL_CNTL 0xf110
-#define GT64260_GPP_VALUE 0xf104
-#define GT64260_GPP_INTR_CAUSE 0xf108
-#define GT64260_GPP_INTR_MASK 0xf10c
-
-
-/*
- *****************************************************************************
- *
- * Multi-Purpose Pins Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_MPP_CNTL_0 0xf000
-#define GT64260_MPP_CNTL_1 0xf004
-#define GT64260_MPP_CNTL_2 0xf008
-#define GT64260_MPP_CNTL_3 0xf00c
-#define GT64260_MPP_SERIAL_PORTS_MULTIPLEX 0xf010
-
-
-/*
- *****************************************************************************
- *
- * I2C Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- * Interrupt Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define GT64260_IC_MAIN_CAUSE_LO 0x0c18
-#define GT64260_IC_MAIN_CAUSE_HI 0x0c68
-#define GT64260_IC_CPU_INTR_MASK_LO 0x0c1c
-#define GT64260_IC_CPU_INTR_MASK_HI 0x0c6c
-#define GT64260_IC_CPU_SELECT_CAUSE 0x0c70
-#define GT64260_IC_PCI_0_INTR_MASK_LO 0x0c24
-#define GT64260_IC_PCI_0_INTR_MASK_HI 0x0c64
-#define GT64260_IC_PCI_0_SELECT_CAUSE 0x0c74
-#define GT64260_IC_PCI_1_INTR_MASK_LO 0x0ca4
-#define GT64260_IC_PCI_1_INTR_MASK_HI 0x0ce4
-#define GT64260_IC_PCI_1_SELECT_CAUSE 0x0cf4
-#define GT64260_IC_CPU_INT_0_MASK 0x0e60
-#define GT64260_IC_CPU_INT_1_MASK 0x0e64
-#define GT64260_IC_CPU_INT_2_MASK 0x0e68
-#define GT64260_IC_CPU_INT_3_MASK 0x0e6c
-
-
-#endif /* __ASMPPC_GT64260_DEFS_H */
#define OCP_VENDOR_ARM 0x0004
#define OCP_VENDOR_FREESCALE 0x1057
#define OCP_VENDOR_IBM 0x1014
+#define OCP_VENDOR_MARVELL 0x11ab
#define OCP_VENDOR_MOTOROLA OCP_VENDOR_FREESCALE
#define OCP_VENDOR_XILINX 0x10ee
#define OCP_VENDOR_UNKNOWN 0xFFFF
#define OCP_FUNC_16550 0x0031
#define OCP_FUNC_IIC 0x0032
#define OCP_FUNC_USB 0x0033
+#define OCP_FUNC_MPSC 0x0034
+#define OCP_FUNC_COMM_MPSC 0x0035
+#define OCP_FUNC_SDMA 0x0036
/* Memory devices 0x0090 - 0x009F */
#define OCP_FUNC_MAL 0x0090
#define OCP_FUNC_PERFMON 0x00D2 /* Performance Monitor */
#define OCP_FUNC_RGMII 0x00D3
#define OCP_FUNC_TAH 0x00D4
+#define OCP_FUNC_I2C 0x00D5 /* I2C Controller */
+#define OCP_FUNC_BRG 0x00D6 /* Baud Rate Generator */
+#define OCP_FUNC_PIC 0x00D7 /* Programmable Interrupt Controller */
/* Network 0x0200 - 0x02FF */
#define OCP_FUNC_EMAC 0x0200
-#define OCP_FUNC_GFAR 0x0201 /* TSEC & FEC */
+#define OCP_FUNC_ENET 0x0201 /* TSEC & FEC */
+#define OCP_FUNC_COMM_EMAC 0x0202
+#define OCP_FUNC_GFAR 0x0203 /* TSEC & FEC */
/* Bridge devices 0xE00 - 0xEFF */
#define OCP_FUNC_OPB 0x0E00
+#define OCP_FUNC_HB 0x0E01 /* Host bridge */
#define OCP_FUNC_UNKNOWN 0xFFFF
#if defined(CONFIG_EV64260)
#include <platforms/ev64260.h>
+#elif defined(CONFIG_DMV182)
+#include <platforms/dmv182_serial.h>
#elif defined(CONFIG_GEMINI)
#include <platforms/gemini_serial.h>
#elif defined(CONFIG_POWERPMC250)
unsigned cpu = smp_processor_id();
if(prev != next){
- clear_bit(cpu, &prev->cpu_vm_mask);
- set_bit(cpu, &next->cpu_vm_mask);
+ cpu_clear(cpu, prev->cpu_vm_mask);
+ cpu_set(cpu, next->cpu_vm_mask);
if(next != &init_mm)
CHOOSE_MODE((void) 0,
switch_mm_skas(next->context.skas.mm_fd));
#define __NR_utimes 235
__SYSCALL(__NR_utimes, sys_utimes)
#define __NR_vserver 236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
-#define __NR_vserver 236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
+__SYSCALL(__NR_vserver, sys_vserver)
#define __NR_mbind 237
__SYSCALL(__NR_mbind, sys_mbind)
#define __NR_set_mempolicy 238
#define _LINUX_BINFMTS_H
#include <linux/capability.h>
+#include <linux/vs_memory.h>
struct pt_regs;
[0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \
} })
+#define CPU_MASK_CPU0 \
+((cpumask_t) { { \
+ [0] = 1UL \
+} })
+
#define cpus_addr(src) ((src).bits)
#define cpumask_scnprintf(buf, len, src) \
#ifdef CONFIG_JBD_DEBUG
#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
#endif
-#define EXT3_IOC_GETRSVSZ _IOR('r', 1, long)
-#define EXT3_IOC_SETRSVSZ _IOW('r', 2, long)
#ifdef CONFIG_VSERVER_LEGACY
#define EXT3_IOC_SETXID FIOC_SETXIDJ
#endif
/*
* Mount flags
*/
-#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */
-#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */
-#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */
-#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */
-#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
-#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */
-#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */
-#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */
-#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/
-#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */
-#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */
-#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */
-#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */
-#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */
-#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
-#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
-#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
-#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
-#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
+#define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+#define EXT3_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */
+#define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD 0x0100 /* Don't use existing journal*/
+#define EXT3_MOUNT_ABORT 0x0200 /* Fatal error detected */
+#define EXT3_MOUNT_DATA_FLAGS 0x0C00 /* Mode for data writes: */
+ #define EXT3_MOUNT_JOURNAL_DATA 0x0400 /* Write data to journal */
+ #define EXT3_MOUNT_ORDERED_DATA 0x0800 /* Flush data before commit */
+ #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */
+#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
+#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_TAG_XID 0x20000 /* Enable Context Tags */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#define ATTR_ATTR_FLAG 1024
#define ATTR_KILL_SUID 2048
#define ATTR_KILL_SGID 4096
+#define ATTR_XID 8192
/*
* This is the Inode Attributes structure, used for notify_change(). It
umode_t ia_mode;
uid_t ia_uid;
gid_t ia_gid;
+ xid_t ia_xid;
loff_t ia_size;
struct timespec ia_atime;
struct timespec ia_mtime;
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
- * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.33 2004/05/25 11:31:55 havasi Exp $
*
*/
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
+#define JFFS2_COMPR_LZO 0x07
+#define JFFS2_COMPR_LZARI 0x08
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
uint16_t v16;
} __attribute__((packed)) jint16_t;
-#define JFFS2_NATIVE_ENDIAN
-
-/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
- whatever OS we're actually running on here too. */
-
-#if defined(JFFS2_NATIVE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){x})
-#define cpu_to_je32(x) ((jint32_t){x})
-#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
-
-#define je16_to_cpu(x) ((x).v16)
-#define je32_to_cpu(x) ((x).v32)
-#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
-#elif defined(JFFS2_BIG_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (be16_to_cpu(x.v16))
-#define je32_to_cpu(x) (be32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
-#elif defined(JFFS2_LITTLE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (le16_to_cpu(x.v16))
-#define je32_to_cpu(x) (le32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-#else
-#error wibble
-#endif
-
struct jffs2_unknown_node
{
/* All start like this */
-/* $Id: jffs2_fs_i.h,v 1.15 2002/11/12 09:42:49 dwmw2 Exp $ */
+/* $Id: jffs2_fs_i.h,v 1.16 2003/01/09 14:03:21 dwmw2 Exp $ */
#ifndef _JFFS2_FS_I
#define _JFFS2_FS_I
uint16_t flags;
uint8_t usercompr;
+#if !defined (__ECOS)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
struct inode vfs_inode;
#endif
+#endif
};
#endif /* _JFFS2_FS_I */
/* defines only for the constants which don't work well as enums */
#define ATA_TAG_POISON 0xfafbfcfdU
+#undef PORT_UNKNOWN
enum {
/* various global constants */
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
/* Common Flash Interface structures
* See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.35 2003/05/28 15:37:32 dwmw2 Exp $
+ * $Id: cfi.h,v 1.44 2004/07/13 22:32:52 dwmw2 Exp $
*/
#ifndef __MTD_CFI_H__
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/mtd/flashchip.h>
+#include <linux/mtd/map.h>
#include <linux/mtd/cfi_endian.h>
-/*
- * You can optimize the code size and performance by defining only
- * the geometry(ies) available on your hardware.
- * CFIDEV_INTERLEAVE_n, where represents the interleave (number of chips to fill the bus width)
- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
- *
- * By default, all (known) geometries are supported.
- */
-
-#ifndef CONFIG_MTD_CFI_GEOMETRY
-
-/* The default case - support all but 64-bit, which has
- a performance penalty */
-
-#define CFIDEV_INTERLEAVE_1 (1)
-#define CFIDEV_INTERLEAVE_2 (2)
-#define CFIDEV_INTERLEAVE_4 (4)
-
-#define CFIDEV_BUSWIDTH_1 (1)
-#define CFIDEV_BUSWIDTH_2 (2)
-#define CFIDEV_BUSWIDTH_4 (4)
-
-typedef __u32 cfi_word;
-
-#else
-
-/* Explicitly configured buswidth/interleave support */
-
#ifdef CONFIG_MTD_CFI_I1
-#define CFIDEV_INTERLEAVE_1 (1)
-#endif
-#ifdef CONFIG_MTD_CFI_I2
-#define CFIDEV_INTERLEAVE_2 (2)
-#endif
-#ifdef CONFIG_MTD_CFI_I4
-#define CFIDEV_INTERLEAVE_4 (4)
-#endif
-#ifdef CONFIG_MTD_CFI_I8
-#define CFIDEV_INTERLEAVE_8 (8)
-#endif
-
-#ifdef CONFIG_MTD_CFI_B1
-#define CFIDEV_BUSWIDTH_1 (1)
-#endif
-#ifdef CONFIG_MTD_CFI_B2
-#define CFIDEV_BUSWIDTH_2 (2)
-#endif
-#ifdef CONFIG_MTD_CFI_B4
-#define CFIDEV_BUSWIDTH_4 (4)
-#endif
-#ifdef CONFIG_MTD_CFI_B8
-#define CFIDEV_BUSWIDTH_8 (8)
-#endif
-
-/* pick the largest necessary */
-#ifdef CONFIG_MTD_CFI_B8
-typedef __u64 cfi_word;
-
-/* This only works if asm/io.h is included first */
-#ifndef __raw_readll
-#define __raw_readll(addr) (*(volatile __u64 *)(addr))
-#endif
-#ifndef __raw_writell
-#define __raw_writell(v, addr) (*(volatile __u64 *)(addr) = (v))
-#endif
-#define CFI_WORD_64
-#else /* CONFIG_MTD_CFI_B8 */
-/* All others can use 32-bits. It's probably more efficient than
- the smaller types anyway */
-typedef __u32 cfi_word;
-#endif /* CONFIG_MTD_CFI_B8 */
-
-#endif
-
-/*
- * The following macros are used to select the code to execute:
- * cfi_buswidth_is_*()
- * cfi_interleave_is_*()
- * [where * is either 1, 2, 4, or 8]
- * Those macros should be used with 'if' statements. If only one of few
- * geometry arrangements are selected, they expand to constants thus allowing
- * the compiler (most of them being 0) to optimize away all the unneeded code,
- * while still validating the syntax (which is not possible with embedded
- * #if ... #endif constructs).
- * The exception to this is the 64-bit versions, which need an extension
- * to the cfi_word type, and cause compiler warnings about shifts being
- * out of range.
- */
-
-#ifdef CFIDEV_INTERLEAVE_1
-# ifdef CFIDEV_INTERLEAVE
-# undef CFIDEV_INTERLEAVE
-# define CFIDEV_INTERLEAVE (cfi->interleave)
-# else
-# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
-# endif
-# define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
+#define cfi_interleave(cfi) 1
+#define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1)
#else
-# define cfi_interleave_is_1() (0)
+#define cfi_interleave_is_1(cfi) (0)
#endif
-#ifdef CFIDEV_INTERLEAVE_2
-# ifdef CFIDEV_INTERLEAVE
-# undef CFIDEV_INTERLEAVE
-# define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I2
+# ifdef cfi_interleave
+# undef cfi_interleave
+# define cfi_interleave(cfi) ((cfi)->interleave)
# else
-# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
+# define cfi_interleave(cfi) 2
# endif
-# define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
+#define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2)
#else
-# define cfi_interleave_is_2() (0)
+#define cfi_interleave_is_2(cfi) (0)
#endif
-#ifdef CFIDEV_INTERLEAVE_4
-# ifdef CFIDEV_INTERLEAVE
-# undef CFIDEV_INTERLEAVE
-# define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I4
+# ifdef cfi_interleave
+# undef cfi_interleave
+# define cfi_interleave(cfi) ((cfi)->interleave)
# else
-# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
+# define cfi_interleave(cfi) 4
# endif
-# define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
+#define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4)
#else
-# define cfi_interleave_is_4() (0)
+#define cfi_interleave_is_4(cfi) (0)
#endif
-#ifdef CFIDEV_INTERLEAVE_8
-# ifdef CFIDEV_INTERLEAVE
-# undef CFIDEV_INTERLEAVE
-# define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I8
+# ifdef cfi_interleave
+# undef cfi_interleave
+# define cfi_interleave(cfi) ((cfi)->interleave)
# else
-# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+# define cfi_interleave(cfi) 8
# endif
-# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8)
#else
-# define cfi_interleave_is_8() (0)
+#define cfi_interleave_is_8(cfi) (0)
#endif
-#ifndef CFIDEV_INTERLEAVE
-#error You must define at least one interleave to support!
+static inline int cfi_interleave_supported(int i)
+{
+ switch (i) {
+#ifdef CONFIG_MTD_CFI_I1
+ case 1:
#endif
-
-#ifdef CFIDEV_BUSWIDTH_1
-# ifdef CFIDEV_BUSWIDTH
-# undef CFIDEV_BUSWIDTH
-# define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
-# endif
-# define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
-#else
-# define cfi_buswidth_is_1() (0)
+#ifdef CONFIG_MTD_CFI_I2
+ case 2:
#endif
-
-#ifdef CFIDEV_BUSWIDTH_2
-# ifdef CFIDEV_BUSWIDTH
-# undef CFIDEV_BUSWIDTH
-# define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
-# endif
-# define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
-#else
-# define cfi_buswidth_is_2() (0)
+#ifdef CONFIG_MTD_CFI_I4
+ case 4:
#endif
-
-#ifdef CFIDEV_BUSWIDTH_4
-# ifdef CFIDEV_BUSWIDTH
-# undef CFIDEV_BUSWIDTH
-# define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
-# endif
-# define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
-#else
-# define cfi_buswidth_is_4() (0)
+#ifdef CONFIG_MTD_CFI_I8
+ case 8:
#endif
+ return 1;
-#ifdef CFIDEV_BUSWIDTH_8
-# ifdef CFIDEV_BUSWIDTH
-# undef CFIDEV_BUSWIDTH
-# define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
-# endif
-# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
-#else
-# define cfi_buswidth_is_8() (0)
-#endif
+ default:
+ return 0;
+ }
+}
-#ifndef CFIDEV_BUSWIDTH
-#error You must define at least one bus width to support!
-#endif
/* NB: these values must represents the number of bytes needed to meet the
* device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes.
/* Basic Query Structure */
struct cfi_ident {
- __u8 qry[3];
- __u16 P_ID;
- __u16 P_ADR;
- __u16 A_ID;
- __u16 A_ADR;
- __u8 VccMin;
- __u8 VccMax;
- __u8 VppMin;
- __u8 VppMax;
- __u8 WordWriteTimeoutTyp;
- __u8 BufWriteTimeoutTyp;
- __u8 BlockEraseTimeoutTyp;
- __u8 ChipEraseTimeoutTyp;
- __u8 WordWriteTimeoutMax;
- __u8 BufWriteTimeoutMax;
- __u8 BlockEraseTimeoutMax;
- __u8 ChipEraseTimeoutMax;
- __u8 DevSize;
- __u16 InterfaceDesc;
- __u16 MaxBufWriteSize;
- __u8 NumEraseRegions;
- __u32 EraseRegionInfo[0]; /* Not host ordered */
+ uint8_t qry[3];
+ uint16_t P_ID;
+ uint16_t P_ADR;
+ uint16_t A_ID;
+ uint16_t A_ADR;
+ uint8_t VccMin;
+ uint8_t VccMax;
+ uint8_t VppMin;
+ uint8_t VppMax;
+ uint8_t WordWriteTimeoutTyp;
+ uint8_t BufWriteTimeoutTyp;
+ uint8_t BlockEraseTimeoutTyp;
+ uint8_t ChipEraseTimeoutTyp;
+ uint8_t WordWriteTimeoutMax;
+ uint8_t BufWriteTimeoutMax;
+ uint8_t BlockEraseTimeoutMax;
+ uint8_t ChipEraseTimeoutMax;
+ uint8_t DevSize;
+ uint16_t InterfaceDesc;
+ uint16_t MaxBufWriteSize;
+ uint8_t NumEraseRegions;
+ uint32_t EraseRegionInfo[0]; /* Not host ordered */
} __attribute__((packed));
/* Extended Query Structure for both PRI and ALT */
struct cfi_extquery {
- __u8 pri[3];
- __u8 MajorVersion;
- __u8 MinorVersion;
+ uint8_t pri[3];
+ uint8_t MajorVersion;
+ uint8_t MinorVersion;
} __attribute__((packed));
/* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
struct cfi_pri_intelext {
- __u8 pri[3];
- __u8 MajorVersion;
- __u8 MinorVersion;
- __u32 FeatureSupport;
- __u8 SuspendCmdSupport;
- __u16 BlkStatusRegMask;
- __u8 VccOptimal;
- __u8 VppOptimal;
- __u8 NumProtectionFields;
- __u16 ProtRegAddr;
- __u8 FactProtRegSize;
- __u8 UserProtRegSize;
+ uint8_t pri[3];
+ uint8_t MajorVersion;
+ uint8_t MinorVersion;
+ uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature
+ block follows - FIXME - not currently supported */
+ uint8_t SuspendCmdSupport;
+ uint16_t BlkStatusRegMask;
+ uint8_t VccOptimal;
+ uint8_t VppOptimal;
+ uint8_t NumProtectionFields;
+ uint16_t ProtRegAddr;
+ uint8_t FactProtRegSize;
+ uint8_t UserProtRegSize;
+} __attribute__((packed));
+
+/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
+
+struct cfi_pri_amdstd {
+ uint8_t pri[3];
+ uint8_t MajorVersion;
+ uint8_t MinorVersion;
+ uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
+ uint8_t EraseSuspend;
+ uint8_t BlkProt;
+ uint8_t TmpBlkUnprotect;
+ uint8_t BlkProtUnprot;
+ uint8_t SimultaneousOps;
+ uint8_t BurstMode;
+ uint8_t PageMode;
+ uint8_t VppMin;
+ uint8_t VppMax;
+ uint8_t TopBottom;
} __attribute__((packed));
struct cfi_pri_query {
- __u8 NumFields;
- __u32 ProtField[1]; /* Not host ordered */
+ uint8_t NumFields;
+ uint32_t ProtField[1]; /* Not host ordered */
} __attribute__((packed));
struct cfi_bri_query {
- __u8 PageModeReadCap;
- __u8 NumFields;
- __u32 ConfField[1]; /* Not host ordered */
+ uint8_t PageModeReadCap;
+ uint8_t NumFields;
+ uint32_t ConfField[1]; /* Not host ordered */
} __attribute__((packed));
#define P_ID_NONE 0
#define P_ID_AMD_STD 2
#define P_ID_INTEL_STD 3
#define P_ID_AMD_EXT 4
+#define P_ID_ST_ADV 32
#define P_ID_MITSUBISHI_STD 256
#define P_ID_MITSUBISHI_EXT 257
+#define P_ID_SST_PAGE 258
#define P_ID_RESERVED 65535
#define CFI_MODE_JEDEC 0
struct cfi_private {
- __u16 cmdset;
+ uint16_t cmdset;
void *cmdset_priv;
int interleave;
int device_type;
int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */
int addr_unlock1;
int addr_unlock2;
- int fast_prog;
struct mtd_info *(*cmdset_setup)(struct map_info *);
struct cfi_ident *cfiq; /* For now only one. We insist that all devs
must be of the same type. */
struct flchip chips[0]; /* per-chip data structure for each chip */
};
-#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
-
/*
* Returns the command address according to the given geometry.
*/
-static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
+static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type)
{
return (cmd_ofs * type) * interleave;
}
/*
- * Transforms the CFI command for the given geometry (bus width & interleave.
+ * Transforms the CFI command for the given geometry (bus width & interleave).
+ * It looks too long to be inline, but in the common case it should almost all
+ * get optimised away.
*/
-static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
{
- cfi_word val = 0;
-
- if (cfi_buswidth_is_1()) {
- /* 1 x8 device */
- val = cmd;
- } else if (cfi_buswidth_is_2()) {
- if (cfi_interleave_is_1()) {
- /* 1 x16 device in x16 mode */
- val = cpu_to_cfi16(cmd);
- } else if (cfi_interleave_is_2()) {
- /* 2 (x8, x16 or x32) devices in x8 mode */
- val = cpu_to_cfi16((cmd << 8) | cmd);
- }
- } else if (cfi_buswidth_is_4()) {
- if (cfi_interleave_is_1()) {
- /* 1 x32 device in x32 mode */
- val = cpu_to_cfi32(cmd);
- } else if (cfi_interleave_is_2()) {
- /* 2 x16 device in x16 mode */
- val = cpu_to_cfi32((cmd << 16) | cmd);
- } else if (cfi_interleave_is_4()) {
- /* 4 (x8, x16 or x32) devices in x8 mode */
- val = (cmd << 16) | cmd;
- val = cpu_to_cfi32((val << 8) | val);
- }
-#ifdef CFI_WORD_64
- } else if (cfi_buswidth_is_8()) {
- if (cfi_interleave_is_1()) {
- /* 1 x64 device in x64 mode */
- val = cpu_to_cfi64(cmd);
- } else if (cfi_interleave_is_2()) {
- /* 2 x32 device in x32 mode */
- val = cmd;
- val = cpu_to_cfi64((val << 32) | val);
- } else if (cfi_interleave_is_4()) {
- /* 4 (x16, x32 or x64) devices in x16 mode */
- val = (cmd << 16) | cmd;
- val = cpu_to_cfi64((val << 32) | val);
- } else if (cfi_interleave_is_8()) {
- /* 8 (x8, x16 or x32) devices in x8 mode */
- val = (cmd << 8) | cmd;
- val = (val << 16) | val;
- val = (val << 32) | val;
- val = cpu_to_cfi64(val);
- }
-#endif /* CFI_WORD_64 */
- }
- return val;
-}
-#define CMD(x) cfi_build_cmd((x), map, cfi)
-
-/*
- * Read a value according to the bus width.
- */
-
-static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
-{
- if (cfi_buswidth_is_1()) {
- return map_read8(map, addr);
- } else if (cfi_buswidth_is_2()) {
- return map_read16(map, addr);
- } else if (cfi_buswidth_is_4()) {
- return map_read32(map, addr);
- } else if (cfi_buswidth_is_8()) {
- return map_read64(map, addr);
+ map_word val = { {0} };
+ int wordwidth, words_per_bus, chip_mode, chips_per_word;
+ unsigned long onecmd;
+ int i;
+
+ /* We do it this way to give the compiler a fighting chance
+ of optimising away all the crap for 'bankwidth' larger than
+ an unsigned long, in the common case where that support is
+ disabled */
+ if (map_bankwidth_is_large(map)) {
+ wordwidth = sizeof(unsigned long);
+ words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
} else {
- return 0;
+ wordwidth = map_bankwidth(map);
+ words_per_bus = 1;
+ }
+
+ chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
+ chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
+
+ /* First, determine what the bit-pattern should be for a single
+ device, according to chip mode and endianness... */
+ switch (chip_mode) {
+ default: BUG();
+ case 1:
+ onecmd = cmd;
+ break;
+ case 2:
+ onecmd = cpu_to_cfi16(cmd);
+ break;
+ case 4:
+ onecmd = cpu_to_cfi32(cmd);
+ break;
}
-}
-/*
- * Write a value according to the bus width.
- */
+ /* Now replicate it across the size of an unsigned long, or
+ just to the bus width as appropriate */
+ switch (chips_per_word) {
+ default: BUG();
+#if BITS_PER_LONG >= 64
+ case 8:
+ onecmd |= (onecmd << (chip_mode * 32));
+#endif
+ case 4:
+ onecmd |= (onecmd << (chip_mode * 16));
+ case 2:
+ onecmd |= (onecmd << (chip_mode * 8));
+ case 1:
+ ;
+ }
-static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
-{
- if (cfi_buswidth_is_1()) {
- map_write8(map, val, addr);
- } else if (cfi_buswidth_is_2()) {
- map_write16(map, val, addr);
- } else if (cfi_buswidth_is_4()) {
- map_write32(map, val, addr);
- } else if (cfi_buswidth_is_8()) {
- map_write64(map, val, addr);
+ /* And finally, for the multi-word case, replicate it
+ in all words in the structure */
+ for (i=0; i < words_per_bus; i++) {
+ val.x[i] = onecmd;
}
+
+ return val;
}
+#define CMD(x) cfi_build_cmd((x), map, cfi)
/*
* Sends a CFI command to a bank of flash for the given geometry.
* If prev_val is non-null, it will be set to the value at the command address,
* before the command was written.
*/
-static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
+static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
struct map_info *map, struct cfi_private *cfi,
- int type, cfi_word *prev_val)
+ int type, map_word *prev_val)
{
- cfi_word val;
- __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
+ map_word val;
+ uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type);
val = cfi_build_cmd(cmd, map, cfi);
if (prev_val)
- *prev_val = cfi_read(map, addr);
+ *prev_val = map_read(map, addr);
- cfi_write(map, val, addr);
+ map_write(map, val, addr);
return addr - base;
}
-static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
+static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr)
{
- if (cfi_buswidth_is_1()) {
- return map_read8(map, addr);
- } else if (cfi_buswidth_is_2()) {
- return cfi16_to_cpu(map_read16(map, addr));
- } else if (cfi_buswidth_is_4()) {
- return cfi32_to_cpu(map_read32(map, addr));
- } else if (cfi_buswidth_is_8()) {
- return cfi64_to_cpu(map_read64(map, addr));
+ map_word val = map_read(map, addr);
+
+ if (map_bankwidth_is_1(map)) {
+ return val.x[0];
+ } else if (map_bankwidth_is_2(map)) {
+ return cfi16_to_cpu(val.x[0]);
} else {
- return 0;
+ /* No point in a 64-bit byteswap since that would just be
+ swapping the responses from different chips, and we are
+ only interested in one chip (a representative sample) */
+ return cfi32_to_cpu(val.x[0]);
}
}
spin_unlock_bh(mutex);
}
+struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
+ const char* name);
+
+struct cfi_fixup {
+ uint16_t mfr;
+ uint16_t id;
+ void (*fixup)(struct map_info *map, void* param);
+ void* param;
+};
+
+#define CFI_MFR_ANY 0xffff
+#define CFI_ID_ANY 0xffff
+
+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups);
+
#endif /* __MTD_CFI_H__ */
-
-/* Linux driver for Disk-On-Chip 2000 */
-/* (c) 1999 Machine Vision Holdings, Inc. */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.17 2003/06/12 01:20:46 gerg Exp $ */
+/*
+ * Linux driver for Disk-On-Chip devices
+ *
+ * Copyright (C) 1999 Machine Vision Holdings, Inc.
+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2002-2003 SnapGear Inc
+ *
+ * $Id: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $
+ *
+ * Released under GPL
+ */
#ifndef __MTD_DOC2000_H__
#define __MTD_DOC2000_H__
#include <linux/mtd/mtd.h>
+#include <asm/semaphore.h>
#define DoC_Sig1 0
#define DoC_Sig2 1
* Others use readb/writeb
*/
#if defined(__arm__)
-#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
-#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
+#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
#define DOC_IOREMAP_LEN 0x8000
#elif defined(__ppc__)
-#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
-#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
+#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
#define DOC_IOREMAP_LEN 0x4000
#else
#define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg))
#define DOC_MODE_MDWREN 0x04
#define DOC_ChipID_Doc2k 0x20
+#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */
#define DOC_ChipID_DocMil 0x30
#define DOC_ChipID_DocMilPlus32 0x40
#define DOC_ChipID_DocMilPlus16 0x41
#define MAX_FLOORS 4
#define MAX_CHIPS 4
-#define MAX_FLOORS_MIL 4
+#define MAX_FLOORS_MIL 1
#define MAX_CHIPS_MIL 1
-#define MAX_FLOORS_MPLUS 1
+#define MAX_FLOORS_MPLUS 2
#define MAX_CHIPS_MPLUS 1
#define ADDR_COLUMN 1
unsigned long physadr;
unsigned long virtadr;
unsigned long totlen;
- char ChipID; /* Type of DiskOnChip */
+ unsigned char ChipID; /* Type of DiskOnChip */
int ioreg;
unsigned long mfr; /* Flash IDs - only one type of flash per device */
*
* (C) 2000 Red Hat. GPLd.
*
- * $Id: flashchip.h,v 1.9 2003/04/30 11:15:22 dwmw2 Exp $
+ * $Id: flashchip.h,v 1.14 2004/06/15 16:44:59 nico Exp $
*
*/
/* NOTE: confusingly, this can be used to refer to more than one chip at a time,
- if they're interleaved. */
+ if they're interleaved. This can even refer to individual partitions on
+ the same physical chip when present. */
struct flchip {
unsigned long start; /* Offset within the map */
int write_suspended:1;
int erase_suspended:1;
+ unsigned long in_progress_block_addr;
spinlock_t *mutex;
spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */
int word_write_time;
int buffer_write_time;
int erase_time;
+
+ void *priv;
};
+/* This is used to handle contention on write/erase operations
+ between partitions of the same physical chip. */
+struct flchip_shared {
+ spinlock_t lock;
+ struct flchip *writing;
+ struct flchip *erasing;
+};
#endif /* __MTD_FLASHCHIP_H__ */
/*
- * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $
+ * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
*
* Derived from (and probably identical to):
* ftl.h 1.7 1999/10/25 20:23:17
/*
* (C) 2001, 2001 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $
+ * $Id: gen_probe.h,v 1.2 2003/11/08 00:51:21 dsaxena Exp $
*/
#ifndef __LINUX_MTD_GEN_PROBE_H__
#include <linux/mtd/flashchip.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
+#include <asm/bitops.h>
struct chip_probe {
char *name;
int (*probe_chip)(struct map_info *map, __u32 base,
- struct flchip *chips, struct cfi_private *cfi);
-
+ unsigned long *chip_map, struct cfi_private *cfi);
};
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp);
*
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
*
- * $Id: inftl.h,v 1.3 2003/05/23 11:35:34 dwmw2 Exp $
+ * $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $
*/
#ifndef __MTD_INFTL_H__
#define __MTD_INFTL_H__
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include nftl-user.h instead?
+#endif
+
#include <linux/mtd/blktrans.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h>
-#define OSAK_VERSION 0x5120
-#define PERCENTUSED 98
-
-#define SECTORSIZE 512
+#include <mtd/inftl-user.h>
#ifndef INFTL_MAJOR
-#define INFTL_MAJOR 93 /* FIXME */
+#define INFTL_MAJOR 94
#endif
#define INFTL_PARTN_BITS 4
-/* Block Control Information */
-
-struct inftl_bci {
- __u8 ECCsig[6];
- __u8 Status;
- __u8 Status1;
-} __attribute__((packed));
-
-struct inftl_unithead1 {
- __u16 virtualUnitNo;
- __u16 prevUnitNo;
- __u8 ANAC;
- __u8 NACs;
- __u8 parityPerField;
- __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unithead2 {
- __u8 parityPerField;
- __u8 ANAC;
- __u16 prevUnitNo;
- __u16 virtualUnitNo;
- __u8 NACs;
- __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unittail {
- __u8 Reserved[4];
- __u16 EraseMark;
- __u16 EraseMark1;
-} __attribute__((packed));
-
-union inftl_uci {
- struct inftl_unithead1 a;
- struct inftl_unithead2 b;
- struct inftl_unittail c;
-};
-
-struct inftl_oob {
- struct inftl_bci b;
- union inftl_uci u;
-};
-
-
-/* INFTL Media Header */
-
-struct INFTLPartition {
- __u32 virtualUnits;
- __u32 firstUnit;
- __u32 lastUnit;
- __u32 flags;
- __u32 spareUnits;
- __u32 Reserved0;
- __u32 Reserved1;
-} __attribute__((packed));
-
-struct INFTLMediaHeader {
- char bootRecordID[8];
- __u32 NoOfBootImageBlocks;
- __u32 NoOfBinaryPartitions;
- __u32 NoOfBDTLPartitions;
- __u32 BlockMultiplierBits;
- __u32 FormatFlags;
- __u32 OsakVersion;
- __u32 PercentUsed;
- struct INFTLPartition Partitions[4];
-} __attribute__((packed));
-
-/* Partition flag types */
-#define INFTL_BINARY 0x20000000
-#define INFTL_BDTL 0x40000000
-#define INFTL_LAST 0x80000000
-
-
#ifdef __KERNEL__
struct INFTLrecord {
struct mtd_blktrans_dev mbd;
- __u16 MediaUnit, SpareMediaUnit;
+ __u16 MediaUnit;
__u32 EraseSize;
struct INFTLMediaHeader MediaHdr;
int usecount;
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
+ struct nand_oobinfo oobinfo;
};
int INFTL_mount(struct INFTLrecord *s);
/* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */
+/* $Id: map.h,v 1.43 2004/07/14 13:30:27 dwmw2 Exp $ */
#ifndef __LINUX_MTD_MAP_H__
#define __LINUX_MTD_MAP_H__
#include <linux/config.h>
#include <linux/types.h>
#include <linux/list.h>
+#include <asm/unaligned.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/bug.h>
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
+#define map_bankwidth(map) 1
+#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
+#define map_bankwidth_is_large(map) (0)
+#define map_words(map) (1)
+#define MAX_MAP_BANKWIDTH 1
+#else
+#define map_bankwidth_is_1(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# else
+# define map_bankwidth(map) 2
+# define map_bankwidth_is_large(map) (0)
+# define map_words(map) (1)
+# endif
+#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 2
+#else
+#define map_bankwidth_is_2(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# else
+# define map_bankwidth(map) 4
+# define map_bankwidth_is_large(map) (0)
+# define map_words(map) (1)
+# endif
+#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 4
+#else
+#define map_bankwidth_is_4(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# if BITS_PER_LONG < 64
+# undef map_bankwidth_is_large
+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+# undef map_words
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+# else
+# define map_bankwidth(map) 8
+# define map_bankwidth_is_large(map) (BITS_PER_LONG < 64)
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 8
+#else
+#define map_bankwidth_is_8(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# undef map_bankwidth_is_large
+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+# undef map_words
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# else
+# define map_bankwidth(map) 16
+# define map_bankwidth_is_large(map) (1)
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 16
+#else
+#define map_bankwidth_is_16(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# undef map_bankwidth_is_large
+# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+# undef map_words
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# else
+# define map_bankwidth(map) 32
+# define map_bankwidth_is_large(map) (1)
+# define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 32
+#else
+#define map_bankwidth_is_32(map) (0)
+#endif
+
+#ifndef map_bankwidth
+#error "No bus width supported. What's the point?"
+#endif
+
+static inline int map_bankwidth_supported(int w)
+{
+ switch (w) {
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
+ case 1:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
+ case 2:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
+ case 4:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
+ case 8:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
+ case 16:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
+ case 32:
+#endif
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
+
+typedef union {
+ unsigned long x[MAX_MAP_LONGS];
+} map_word;
/* The map stuff is very simple. You fill in your struct map_info with
a handful of routines for accessing the device, making sure they handle
paging etc. correctly if your device needs it. Then you pass it off
- to a chip driver which deals with a mapped device - generally either
- do_cfi_probe() or do_ram_probe(), either of which will return a
- struct mtd_info if they liked what they saw. At which point, you
- fill in the mtd->module with your own module address, and register
- it.
+ to a chip probe routine -- either JEDEC or CFI probe or both -- via
+ do_map_probe(). If a chip is recognised, the probe code will invoke the
+ appropriate chip driver (if present) and return a struct mtd_info.
+ At which point, you fill in the mtd->module with your own module
+ address, and register it with the MTD core code. Or you could partition
+ it and register the partitions instead, or keep it for your own private
+ use; whatever.
The mtd->priv field will point to the struct map_info, and any further
private data required by the chip driver is linked from the
unsigned long virt;
void *cached;
- int buswidth; /* in octets */
+ int bankwidth; /* in octets. This isn't necessarily the width
+ of actual bus cycles -- it's the repeat interval
+ in bytes, before you are talking to the first chip again.
+ */
#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
- u8 (*read8)(struct map_info *, unsigned long);
- u16 (*read16)(struct map_info *, unsigned long);
- u32 (*read32)(struct map_info *, unsigned long);
- u64 (*read64)(struct map_info *, unsigned long);
- /* If it returned a 'long' I'd call it readl.
- * It doesn't.
- * I won't.
- * dwmw2 */
-
+ map_word (*read)(struct map_info *, unsigned long);
void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
- void (*write8)(struct map_info *, u8, unsigned long);
- void (*write16)(struct map_info *, u16, unsigned long);
- void (*write32)(struct map_info *, u32, unsigned long);
- void (*write64)(struct map_info *, u64, unsigned long);
+
+ void (*write)(struct map_info *, const map_word, unsigned long);
void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
/* We can perhaps put in 'point' and 'unpoint' methods, if we really
want to enable XIP for non-linear mappings. Not yet though. */
#endif
+ /* It's possible for the map driver to use cached memory in its
+ copy_from implementation (and _only_ with copy_from). However,
+ when the chip driver knows some flash area has changed contents,
+ it will signal it to the map driver through this routine to let
+ the map driver invalidate the corresponding cache as needed.
+ If there is no cache to care about this can be set to NULL. */
+ void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
+
/* set_vpp() must handle being reentered -- enable, enable, disable
must leave it enabled. */
void (*set_vpp)(struct map_info *, int);
#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
-#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-#define map_read8(map, ofs) (map)->read8(map, ofs)
-#define map_read16(map, ofs) (map)->read16(map, ofs)
-#define map_read32(map, ofs) (map)->read32(map, ofs)
-#define map_read64(map, ofs) (map)->read64(map, ofs)
-#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
-#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs)
-#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs)
-#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs)
-#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs)
-#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
+#define INVALIDATE_CACHED_RANGE(map, from, size) \
+ do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
-extern void simple_map_init(struct map_info *);
-#define map_is_linear(map) (map->phys != NO_XIP)
-#else
-static inline u8 map_read8(struct map_info *map, unsigned long ofs)
+static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
{
- return __raw_readb(map->virt + ofs);
+ int i;
+ for (i=0; i<map_words(map); i++) {
+ if (val1.x[i] != val2.x[i])
+ return 0;
+ }
+ return 1;
}
-static inline u16 map_read16(struct map_info *map, unsigned long ofs)
+static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
{
- return __raw_readw(map->virt + ofs);
+ map_word r;
+ int i;
+
+ for (i=0; i<map_words(map); i++) {
+ r.x[i] = val1.x[i] & val2.x[i];
+ }
+ return r;
}
-static inline u32 map_read32(struct map_info *map, unsigned long ofs)
+static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
{
- return __raw_readl(map->virt + ofs);
+ map_word r;
+ int i;
+
+ for (i=0; i<map_words(map); i++) {
+ r.x[i] = val1.x[i] | val2.x[i];
+ }
+ return r;
}
+#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
-static inline u64 map_read64(struct map_info *map, unsigned long ofs)
+static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
- BUG();
+ int i;
+
+ for (i=0; i<map_words(map); i++) {
+ if (val1.x[i] & val2.x[i])
+ return 1;
+ }
return 0;
-#else
- return __raw_readll(map->virt + ofs);
-#endif
}
-static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs)
+static inline map_word map_word_load(struct map_info *map, const void *ptr)
{
- __raw_writeb(datum, map->virt + ofs);
- mb();
+ map_word r;
+
+ if (map_bankwidth_is_1(map))
+ r.x[0] = *(unsigned char *)ptr;
+ else if (map_bankwidth_is_2(map))
+ r.x[0] = get_unaligned((uint16_t *)ptr);
+ else if (map_bankwidth_is_4(map))
+ r.x[0] = get_unaligned((uint32_t *)ptr);
+#if BITS_PER_LONG >= 64
+ else if (map_bankwidth_is_8(map))
+ r.x[0] = get_unaligned((uint64_t *)ptr);
+#endif
+ else if (map_bankwidth_is_large(map))
+ memcpy(r.x, ptr, map->bankwidth);
+
+ return r;
}
-static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs)
+static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len)
{
- __raw_writew(datum, map->virt + ofs);
- mb();
+ int i;
+
+ if (map_bankwidth_is_large(map)) {
+ char *dest = (char *)&orig;
+ memcpy(dest+start, buf, len);
+ } else {
+ for (i=start; i < start+len; i++) {
+ int bitpos;
+#ifdef __LITTLE_ENDIAN
+ bitpos = i*8;
+#else /* __BIG_ENDIAN */
+ bitpos = (map_bankwidth(map)-1-i)*8;
+#endif
+ orig.x[0] &= ~(0xff << bitpos);
+ orig.x[0] |= buf[i] << bitpos;
+ }
+ }
+ return orig;
}
-static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs)
+static inline map_word map_word_ff(struct map_info *map)
{
- __raw_writel(datum, map->virt + ofs);
- mb();
+ map_word r;
+ int i;
+
+ for (i=0; i<map_words(map); i++) {
+ r.x[i] = ~0UL;
+ }
+ return r;
+}
+static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
+{
+ map_word r;
+
+ if (map_bankwidth_is_1(map))
+ r.x[0] = __raw_readb(map->virt + ofs);
+ else if (map_bankwidth_is_2(map))
+ r.x[0] = __raw_readw(map->virt + ofs);
+ else if (map_bankwidth_is_4(map))
+ r.x[0] = __raw_readl(map->virt + ofs);
+#if BITS_PER_LONG >= 64
+ else if (map_bankwidth_is_8(map))
+ r.x[0] = __raw_readq(map->virt + ofs);
+#endif
+ else if (map_bankwidth_is_large(map))
+ memcpy_fromio(r.x, map->virt+ofs, map->bankwidth);
+
+ return r;
}
-static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs)
+static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
- BUG();
-#else
- __raw_writell(datum, map->virt + ofs);
+ if (map_bankwidth_is_1(map))
+ __raw_writeb(datum.x[0], map->virt + ofs);
+ else if (map_bankwidth_is_2(map))
+ __raw_writew(datum.x[0], map->virt + ofs);
+ else if (map_bankwidth_is_4(map))
+ __raw_writel(datum.x[0], map->virt + ofs);
+#if BITS_PER_LONG >= 64
+ else if (map_bankwidth_is_8(map))
+ __raw_writeq(datum.x[0], map->virt + ofs);
+#endif
+ else if (map_bankwidth_is_large(map))
+ memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
mb();
-#endif /* CFI_B8 */
}
-static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
- memcpy_fromio(to, map->virt + from, len);
+ if (map->cached)
+ memcpy(to, (char *)map->cached + from, len);
+ else
+ memcpy_fromio(to, map->virt + from, len);
}
-static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
memcpy_toio(map->virt + to, from, len);
}
-#define simple_map_init(map) do { } while (0)
+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
+#define map_read(map, ofs) (map)->read(map, ofs)
+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
+#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
+
+extern void simple_map_init(struct map_info *);
+#define map_is_linear(map) (map->phys != NO_XIP)
+
+#else
+#define map_read(map, ofs) inline_map_read(map, ofs)
+#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len)
+#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs)
+#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len)
+
+
+#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
#define map_is_linear(map) (1)
#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
-
-/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */
+/*
+ * $Id: mtd.h,v 1.54 2004/07/15 01:13:12 dwmw2 Exp $
+ *
+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
+ *
+ * Released under GPL
+ */
#ifndef __MTD_MTD_H__
#define __MTD_MTD_H__
-#ifdef __KERNEL__
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include mtd-user.h instead?
+#endif
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/uio.h>
-#endif /* __KERNEL__ */
-
-struct erase_info_user {
- u_int32_t start;
- u_int32_t length;
-};
-
-struct mtd_oob_buf {
- u_int32_t start;
- u_int32_t length;
- unsigned char __user *ptr;
-};
+#include <mtd/mtd-abi.h>
#define MTD_CHAR_MAJOR 90
#define MTD_BLOCK_MAJOR 31
#define MAX_MTD_DEVICES 16
-
-
-#define MTD_ABSENT 0
-#define MTD_RAM 1
-#define MTD_ROM 2
-#define MTD_NORFLASH 3
-#define MTD_NANDFLASH 4
-#define MTD_PEROM 5
-#define MTD_OTHER 14
-#define MTD_UNKNOWN 15
-
-
-
-#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash)
-#define MTD_SET_BITS 2 // Bits can be set
-#define MTD_ERASEABLE 4 // Has an erase function
-#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible
-#define MTD_VOLATILE 16 // Set for RAMs
-#define MTD_XIP 32 // eXecute-In-Place possible
-#define MTD_OOB 64 // Out-of-band data (NAND flash)
-#define MTD_ECC 128 // Device capable of automatic ECC
-
-// Some common devices / combinations of capabilities
-#define MTD_CAP_ROM 0
-#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
-#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE)
-#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
-#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS)
-
-
-// Types of automatic ECC/Checksum available
-#define MTD_ECC_NONE 0 // No automatic ECC available
-#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip
-#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices
-
-struct mtd_info_user {
- u_char type;
- u_int32_t flags;
- u_int32_t size; // Total size of the MTD
- u_int32_t erasesize;
- u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
- u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
- u_int32_t ecctype;
- u_int32_t eccsize;
-};
-
-struct region_info_user {
- u_int32_t offset; /* At which this region starts,
- * from the beginning of the MTD */
- u_int32_t erasesize; /* For this region */
- u_int32_t numblocks; /* Number of blocks in this region */
- u_int32_t regionindex;
-};
-
-#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
-#define MEMERASE _IOW('M', 2, struct erase_info_user)
-#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
-#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
-#define MEMLOCK _IOW('M', 5, struct erase_info_user)
-#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
-#define MEMGETREGIONCOUNT _IOR('M', 7, int)
-#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
-#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
-
-struct nand_oobinfo {
- int useecc;
- int eccpos[6];
-};
-
-
-#ifndef __KERNEL__
-
-typedef struct mtd_info_user mtd_info_t;
-typedef struct erase_info_user erase_info_t;
-typedef struct region_info_user region_info_t;
-typedef struct nand_oobinfo nand_oobinfo_t;
-
- /* User-space ioctl definitions */
-
-#else /* __KERNEL__ */
-
-
#define MTD_ERASE_PENDING 0x01
#define MTD_ERASING 0x02
#define MTD_ERASE_SUSPEND 0x04
#define MTD_ERASE_DONE 0x08
#define MTD_ERASE_FAILED 0x10
+/* If the erase fails, fail_addr might indicate exactly which block failed. If
+ fail_addr = 0xffffffff, the failure was not at the device level or was not
+ specific to any particular block. */
struct erase_info {
struct mtd_info *mtd;
u_int32_t addr;
u_int32_t len;
+ u_int32_t fail_addr;
u_long time;
u_long retries;
u_int dev;
u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
+ u_int32_t oobavail; // Number of bytes in OOB area available for fs
u_int32_t ecctype;
u_int32_t eccsize;
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
+ /* Bad block management functions */
+ int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
+ int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+
void *priv;
struct module *owner;
#endif /* CONFIG_MTD_DEBUG */
-#endif /* __KERNEL__ */
-
#endif /* __MTD_MTD_H__ */
* Steven J. Hill <sjhill@realitydiluted.com>
* Thomas Gleixner <tglx@linutronix.de>
*
- * $Id: nand.h,v 1.25 2003/05/21 15:15:02 dwmw2 Exp $
+ * $Id: nand.h,v 1.63 2004/07/07 16:29:43 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* NAND_YAFFS_OOB
* 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL
* Split manufacturer and device ID structures
+ *
+ * 02-08-2004 tglx added option field to nand structure for chip anomalities
+ * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
+ * update of nand_chip structure description
*/
#ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H
#include <linux/config.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
+#include <linux/mtd/mtd.h>
struct mtd_info;
-/*
- * Searches for a NAND device
+/* Scan and identify a NAND device */
+extern int nand_scan (struct mtd_info *mtd, int max_chips);
+/* Free resources held by the NAND device */
+extern void nand_release (struct mtd_info *mtd);
+
+/* Read raw data from the device without ECC */
+extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
+
+
+/* The maximum number of NAND chips in an array */
+#define NAND_MAX_CHIPS 8
+
+/* This constant declares the max. oobsize / page, which
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
*/
-extern int nand_scan (struct mtd_info *mtd);
+#define NAND_MAX_OOBSIZE 64
/*
* Constants for hardware specific CLE/ALE/NCE function
*/
+/* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE 1
+/* Deselect the chip by setting nCE to high */
#define NAND_CTL_CLRNCE 2
+/* Select the command latch by setting CLE to high */
#define NAND_CTL_SETCLE 3
+/* Deselect the command latch by setting CLE to low */
#define NAND_CTL_CLRCLE 4
+/* Select the address latch by setting ALE to high */
#define NAND_CTL_SETALE 5
+/* Deselect the address latch by setting ALE to low */
#define NAND_CTL_CLRALE 6
+/* Set write protection by setting WP to high. Not used! */
+#define NAND_CTL_SETWP 7
+/* Clear write protection by setting WP to low. Not used! */
+#define NAND_CTL_CLRWP 8
/*
* Standard NAND flash commands
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
+#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART 0x30
+#define NAND_CMD_CACHEDPROG 0x15
+
+/* Status bits */
+#define NAND_STATUS_FAIL 0x01
+#define NAND_STATUS_FAIL_N1 0x02
+#define NAND_STATUS_TRUE_READY 0x20
+#define NAND_STATUS_READY 0x40
+#define NAND_STATUS_WP 0x80
+
/*
* Constants for ECC_MODES
- *
- * NONE: No ECC
- * SOFT: Software ECC 3 byte ECC per 256 Byte data
- * HW3_256: Hardware ECC 3 byte ECC per 256 Byte data
- * HW3_512: Hardware ECC 3 byte ECC per 512 Byte data
- *
- *
-*/
+ */
+
+/* No ECC. Usage is not recommended ! */
#define NAND_ECC_NONE 0
+/* Software ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_SOFT 1
+/* Hardware ECC 3 byte ECC per 256 Byte data */
#define NAND_ECC_HW3_256 2
+/* Hardware ECC 3 byte ECC per 512 Byte data */
#define NAND_ECC_HW3_512 3
+/* Hardware ECC 3 byte ECC per 512 Byte data */
#define NAND_ECC_HW6_512 4
-#define NAND_ECC_DISKONCHIP 5
+/* Hardware ECC 8 byte ECC per 512 Byte data */
+#define NAND_ECC_HW8_512 6
/*
* Constants for Hardware ECC
*/
+/* Reset Hardware ECC for read */
#define NAND_ECC_READ 0
+/* Reset Hardware ECC for write */
#define NAND_ECC_WRITE 1
-
+/* Enable Hardware ECC before syndrom is read back from flash */
+#define NAND_ECC_READSYN 2
+
+/* Option constants for bizarre disfunctionality and real
+* features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR 0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16 0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING 0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG 0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK 0x00000010
+/* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND 0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY 0x00000040
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+ (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+/* Macros to identify the above */
+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
+
+/* Mask to zero out the chip options, which come from the id table */
+#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
+
+/* Non chip related options */
+/* Use a flash based bad block table. This option is passed to the
+ * default bad block table function. */
+#define NAND_USE_FLASH_BBT 0x00010000
+/* The hw ecc generator provides a syndrome instead a ecc value on read
+ * This can only work if we have the ecc bytes directly behind the
+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
+#define NAND_HWECC_SYNDROME 0x00020000
+
+
+/* Options set by nand scan */
+/* Nand scan has allocated oob_buf */
+#define NAND_OOBBUF_ALLOC 0x40000000
+/* Nand scan has allocated data_buf */
+#define NAND_DATABUF_ALLOC 0x80000000
+
+
/*
+ * nand_state_t - chip states
* Enumeration for NAND flash chip state
*/
typedef enum {
FL_READING,
FL_WRITING,
FL_ERASING,
- FL_SYNCING
+ FL_SYNCING,
+ FL_CACHEDPRG,
} nand_state_t;
-/*
- * NAND Private Flash Chip Data
- *
- * Structure overview:
- *
- * IO_ADDR_R - address to read the 8 I/O lines of the flash device
- *
- * IO_ADDR_W - address to write the 8 I/O lines of the flash device
- *
- * hwcontrol - hardwarespecific function for accesing control-lines
- *
- * dev_ready - hardwarespecific function for accesing device ready/busy line
- *
- * waitfunc - hardwarespecific function for wait on ready
- *
- * calculate_ecc - function for ecc calculation or readback from ecc hardware
- *
- * correct_data - function for ecc correction, matching to ecc generator (sw/hw)
- *
- * enable_hwecc - function to enable (reset) hardware ecc generator
- *
- * eccmod - mode of ecc: see constants
- *
- * eccsize - databytes used per ecc-calculation
- *
- * chip_delay - chip dependent delay for transfering data from array to read regs (tR)
- *
- * chip_lock - spinlock used to protect access to this structure
- *
- * wq - wait queue to sleep on if a NAND operation is in progress
- *
- * state - give the current state of the NAND device
- *
- * page_shift - number of address bits in a page (column address bits)
- *
- * data_buf - data buffer passed to/from MTD user modules
- *
- * data_cache - data cache for redundant page access and shadow for
- * ECC failure
- *
- * cache_page - number of last valid page in page_cache
+/**
+ * struct nand_chip - NAND Private Flash Chip Data
+ * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
+ * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
+ * @read_byte: [REPLACEABLE] read one byte from the chip
+ * @write_byte: [REPLACEABLE] write one byte to the chip
+ * @read_word: [REPLACEABLE] read one word from the chip
+ * @write_word: [REPLACEABLE] write one word to the chip
+ * @write_buf: [REPLACEABLE] write data from the buffer to the chip
+ * @read_buf: [REPLACEABLE] read data from the chip into the buffer
+ * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
+ * @select_chip: [REPLACEABLE] select chip nr
+ * @block_bad: [REPLACEABLE] check, if the block is bad
+ * @block_markbad: [REPLACEABLE] mark the block bad
+ * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
+ * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
+ * If set to NULL no access to ready/busy is available and the ready/busy information
+ * is read from the chip status register
+ * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
+ * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
+ * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware
+ * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
+ * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
+ * be provided if a hardware ECC is available
+ * @erase_cmd: [INTERN] erase command write function, selectable due to AND support
+ * @scan_bbt: [REPLACEABLE] function to scan bad block table
+ * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines
+ * @eccsize: [INTERN] databytes used per ecc-calculation
+ * @eccsteps: [INTERN] number of ecc calculation steps per page
+ * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
+ * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip
+ * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
+ * @state: [INTERN] the current state of the NAND device
+ * @page_shift: [INTERN] number of address bits in a page (column address bits)
+ * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
+ * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
+ * @chip_shift: [INTERN] number of address bits in one chip
+ * @data_buf: [INTERN] internal buffer for one page + oob
+ * @oob_buf: [INTERN] oob buffer for one eraseblock
+ * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
+ * @data_poi: [INTERN] pointer to a data buffer
+ * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
+ * special functionality. See the defines for further explanation
+ * @badblockpos: [INTERN] position of the bad block marker in the oob area
+ * @numchips: [INTERN] number of physical chips
+ * @chipsize: [INTERN] the size of one chip for multichip arrays
+ * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
+ * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
+ * @autooob: [REPLACEABLE] the default (auto)placement scheme
+ * @bbt: [INTERN] bad block table pointer
+ * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
+ * @bbt_md: [REPLACEABLE] bad block table mirror descriptor
+ * @priv: [OPTIONAL] pointer to private chip date
*/
+
struct nand_chip {
unsigned long IO_ADDR_R;
unsigned long IO_ADDR_W;
- void (*hwcontrol)(int cmd);
- int (*dev_ready)(void);
+
+ u_char (*read_byte)(struct mtd_info *mtd);
+ void (*write_byte)(struct mtd_info *mtd, u_char byte);
+ u16 (*read_word)(struct mtd_info *mtd);
+ void (*write_word)(struct mtd_info *mtd, u16 word);
+
+ void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+ void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
+ int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+ void (*select_chip)(struct mtd_info *mtd, int chip);
+ int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ void (*hwcontrol)(struct mtd_info *mtd, int cmd);
+ int (*dev_ready)(struct mtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
- void (*calculate_ecc)(const u_char *dat, u_char *ecc_code);
- int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
- void (*enable_hwecc)(int mode);
+ int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
+ int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+ void (*enable_hwecc)(struct mtd_info *mtd, int mode);
+ void (*erase_cmd)(struct mtd_info *mtd, int page);
+ int (*scan_bbt)(struct mtd_info *mtd);
int eccmode;
int eccsize;
+ int eccsteps;
int chip_delay;
- spinlock_t chip_lock;
+ spinlock_t chip_lock;
wait_queue_head_t wq;
nand_state_t state;
int page_shift;
+ int phys_erase_shift;
+ int bbt_erase_shift;
+ int chip_shift;
u_char *data_buf;
+ u_char *oob_buf;
+ int oobdirty;
u_char *data_poi;
+ unsigned int options;
+ int badblockpos;
+ int numchips;
+ unsigned long chipsize;
+ int pagemask;
+ int pagebuf;
+ struct nand_oobinfo *autooob;
+ uint8_t *bbt;
+ struct nand_bbt_descr *bbt_td;
+ struct nand_bbt_descr *bbt_md;
+ void *priv;
};
/*
#define NAND_MFR_SAMSUNG 0xec
#define NAND_MFR_FUJITSU 0x04
#define NAND_MFR_NATIONAL 0x8f
+#define NAND_MFR_RENESAS 0x07
+#define NAND_MFR_STMICRO 0x20
-/*
- * NAND Flash Device ID Structure
- *
- * Structure overview:
- *
- * name - Identify the device type
- *
- * id - device ID code
- *
- * chipshift - total number of address bits for the device which
- * is used to calculate address offsets and the total
- * number of bytes the device is capable of.
- *
- * page256 - denotes if flash device has 256 byte pages or not.
- *
- * pageadrlen - number of bytes minus one needed to hold the
- * complete address into the flash array. Keep in
- * mind that when a read or write is done to a
- * specific address, the address is input serially
- * 8 bits at a time. This structure member is used
- * by the read/write routines as a loop index for
- * shifting the address out 8 bits at a time.
- *
- * erasesize - size of an erase block in the flash device.
+/**
+ * struct nand_flash_dev - NAND Flash Device ID Structure
+ *
+ * @name: Identify the device type
+ * @id: device ID code
+ * @pagesize: Pagesize in bytes. Either 256 or 512 or 0
+ * If the pagesize is 0, then the real pagesize
+ * and the eraseize are determined from the
+ * extended id bytes in the chip
+ * @erasesize: Size of an erase block in the flash device.
+ * @chipsize: Total chipsize in Mega Bytes
+ * @options: Bitfield to store chip relevant options
*/
struct nand_flash_dev {
- char * name;
+ char *name;
int id;
- int chipshift;
+ unsigned long pagesize;
+ unsigned long chipsize;
unsigned long erasesize;
- char page256;
+ unsigned long options;
};
-/*
- * NAND Flash Manufacturer ID Structure
- *
- * name - Manufacturer name
- *
- * id - manufacturer ID code of device.
+/**
+ * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
+ * @name: Manufacturer name
+ * @id: manufacturer ID code of device.
*/
struct nand_manufacturers {
int id;
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
+/**
+ * struct nand_bbt_descr - bad block table descriptor
+ * @options: options for this descriptor
+ * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
+ * when bbt is searched, then we store the found bbts pages here.
+ * Its an array and supports up to 8 chips now
+ * @offs: offset of the pattern in the oob area of the page
+ * @veroffs: offset of the bbt version counter in the oob are of the page
+ * @version: version read from the bbt page during scan
+ * @len: length of the pattern, if 0 no pattern check is performed
+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
+ * blocks is reserved at the end of the device where the tables are
+ * written.
+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
+ * bad) block in the stored bbt
+ * @pattern: pattern to identify bad block table or factory marked good /
+ * bad blocks, can be NULL, if len = 0
+ *
+ * Descriptor for the bad block table marker and the descriptor for the
+ * pattern which identifies good and bad blocks. The assumption is made
+ * that the pattern and the version count are always located in the oob area
+ * of the first block.
+ */
+struct nand_bbt_descr {
+ int options;
+ int pages[NAND_MAX_CHIPS];
+ int offs;
+ int veroffs;
+ uint8_t version[NAND_MAX_CHIPS];
+ int len;
+ int maxblocks;
+ int reserved_block_code;
+ uint8_t *pattern;
+};
+
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK 0x0000000F
+#define NAND_BBT_1BIT 0x00000001
+#define NAND_BBT_2BIT 0x00000002
+#define NAND_BBT_4BIT 0x00000004
+#define NAND_BBT_8BIT 0x00000008
+/* The bad block table is in the last good block of the device */
+#define NAND_BBT_LASTBLOCK 0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE 0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH 0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP 0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION 0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE 0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES 0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY 0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE 0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT 0x00002000
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE 0x00004000
+
+/* The maximum number of blocks to scan for a bbt */
+#define NAND_BBT_SCAN_MAXBLOCKS 4
+
+extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
+extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
+extern int nand_default_bbt (struct mtd_info *mtd);
+extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
+extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
+
/*
* Constants for oob configuration
*/
-#define NAND_BADBLOCK_POS 5
+#define NAND_SMALL_BADBLOCK_POS 5
+#define NAND_LARGE_BADBLOCK_POS 0
#endif /* __LINUX_MTD_NAND_H */
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
- * $Id: nand_ecc.h,v 1.2 2003/02/20 13:34:20 sjhill Exp $
+ * $Id: nand_ecc.h,v 1.4 2004/06/17 02:35:02 dbrown Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* This file is the header for the ECC algorithm.
*/
-/*
- * Creates non-inverted ECC code from line parity
- */
-void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code);
+#ifndef __MTD_NAND_ECC_H__
+#define __MTD_NAND_ECC_H__
+
+struct mtd_info;
/*
* Calculate 3 byte ECC code for 256 byte block
*/
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
/*
* Detect and correct a 1 bit error for 256 byte block
*/
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+
+#endif /* __MTD_NAND_ECC_H__ */
/*
- * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $
+ * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $
*
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
*/
#include <linux/mtd/mtd.h>
#include <linux/mtd/blktrans.h>
-/* Block Control Information */
-
-struct nftl_bci {
- unsigned char ECCSig[6];
- __u8 Status;
- __u8 Status1;
-}__attribute__((packed));
-
-/* Unit Control Information */
-
-struct nftl_uci0 {
- __u16 VirtUnitNum;
- __u16 ReplUnitNum;
- __u16 SpareVirtUnitNum;
- __u16 SpareReplUnitNum;
-} __attribute__((packed));
-
-struct nftl_uci1 {
- __u32 WearInfo;
- __u16 EraseMark;
- __u16 EraseMark1;
-} __attribute__((packed));
-
-struct nftl_uci2 {
- __u16 FoldMark;
- __u16 FoldMark1;
- __u32 unused;
-} __attribute__((packed));
-
-union nftl_uci {
- struct nftl_uci0 a;
- struct nftl_uci1 b;
- struct nftl_uci2 c;
-};
-
-struct nftl_oob {
- struct nftl_bci b;
- union nftl_uci u;
-};
-
-/* NFTL Media Header */
-
-struct NFTLMediaHeader {
- char DataOrgID[6];
- __u16 NumEraseUnits;
- __u16 FirstPhysicalEUN;
- __u32 FormattedSize;
- unsigned char UnitSizeFactor;
-} __attribute__((packed));
-
-#define MAX_ERASE_ZONES (8192 - 512)
-
-#define ERASE_MARK 0x3c69
-#define SECTOR_FREE 0xff
-#define SECTOR_USED 0x55
-#define SECTOR_IGNORE 0x11
-#define SECTOR_DELETED 0x00
-
-#define FOLD_MARK_IN_PROGRESS 0x5555
-
-#define ZONE_GOOD 0xff
-#define ZONE_BAD_ORIGINAL 0
-#define ZONE_BAD_MARKED 7
-
-#ifdef __KERNEL__
+#include <mtd/nftl-user.h>
/* these info are used in ReplUnitTable */
#define BLOCK_NIL 0xffff /* last block of a chain */
unsigned int nb_blocks; /* number of physical blocks */
unsigned int nb_boot_blocks; /* number of blocks used by the bios */
struct erase_info instr;
+ struct nand_oobinfo oobinfo;
};
int NFTL_mount(struct NFTLrecord *s);
#define MAX_SECTORS_PER_UNIT 64
#define NFTL_PARTN_BITS 4
-#endif /* __KERNEL__ */
-
#endif /* __MTD_NFTL_H__ */
*
* This code is GPL
*
- * $Id: partitions.h,v 1.14 2003/05/20 21:56:29 dwmw2 Exp $
+ * $Id: partitions.h,v 1.15 2003/07/09 11:15:43 dwmw2 Exp $
*/
#ifndef MTD_PARTITIONS_H
#define MTDPART_SIZ_FULL (0)
-int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
/*
#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
+#define NFS_MOUNT_TAGXID 0x8000 /* tagxid */
#define NFS_MOUNT_FLAGMASK 0xFFFF
#endif
+++ /dev/null
-#error THIS FILE SHOULD NO LONGER BE USED
-
-#ifndef _NX_INLINE_H
-#define _NX_INLINE_H
-
-
-// #define NX_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-
-#include "vserver/network.h"
-
-#if defined(NX_DEBUG)
-#define nxdprintk(x...) printk("nxd: " x)
-#else
-#define nxdprintk(x...)
-#endif
-
-
-extern int proc_pid_nx_info(struct task_struct *, char *);
-
-
-#define get_nx_info(i) __get_nx_info(i,__FILE__,__LINE__)
-
-static inline struct nx_info *__get_nx_info(struct nx_info *nxi,
- const char *_file, int _line)
-{
- if (!nxi)
- return NULL;
- nxdprintk("get_nx_info(%p[#%d.%d])\t%s:%d\n",
- nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0,
- _file, _line);
- atomic_inc(&nxi->nx_usecnt);
- return nxi;
-}
-
-
-#define free_nx_info(nxi) \
- call_rcu(&nxi->nx_rcu, rcu_free_nx_info, nxi);
-
-#define put_nx_info(i) __put_nx_info(i,__FILE__,__LINE__)
-
-static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line)
-{
- if (!nxi)
- return;
- nxdprintk("put_nx_info(%p[#%d.%d])\t%s:%d\n",
- nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0,
- _file, _line);
- if (atomic_dec_and_test(&nxi->nx_usecnt))
- free_nx_info(nxi);
-}
-
-
-#define set_nx_info(p,i) __set_nx_info(p,i,__FILE__,__LINE__)
-
-static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi,
- const char *_file, int _line)
-{
- BUG_ON(*nxp);
- if (!nxi)
- return;
- nxdprintk("set_nx_info(%p[#%d.%d.%d])\t%s:%d\n",
- nxi, nxi?nxi->nx_id:0,
- nxi?atomic_read(&nxi->nx_usecnt):0,
- nxi?atomic_read(&nxi->nx_refcnt):0,
- _file, _line);
- atomic_inc(&nxi->nx_refcnt);
- *nxp = __get_nx_info(nxi, _file, _line);
-}
-
-#define clr_nx_info(p) __clr_nx_info(p,__FILE__,__LINE__)
-
-static inline void __clr_nx_info(struct nx_info **nxp,
- const char *_file, int _line)
-{
- struct nx_info *nxo = *nxp;
-
- if (!nxo)
- return;
- nxdprintk("clr_nx_info(%p[#%d.%d.%d])\t%s:%d\n",
- nxo, nxo?nxo->nx_id:0,
- nxo?atomic_read(&nxo->nx_usecnt):0,
- nxo?atomic_read(&nxo->nx_refcnt):0,
- _file, _line);
- *nxp = NULL;
- wmb();
- if (nxo && atomic_dec_and_test(&nxo->nx_refcnt))
- unhash_nx_info(nxo);
- __put_nx_info(nxo, _file, _line);
-}
-
-
-#define task_get_nx_info(i) __task_get_nx_info(i,__FILE__,__LINE__)
-
-static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p,
- const char *_file, int _line)
-{
- struct nx_info *nxi;
-
- task_lock(p);
- nxi = __get_nx_info(p->nx_info, _file, _line);
- task_unlock(p);
- return nxi;
-}
-
-#define nx_verify_info(p,i) \
- __nx_verify_info((p)->nx_info,i,__FILE__,__LINE__)
-
-static __inline__ void __nx_verify_info(
- struct nx_info *ipa, struct nx_info *ipb,
- const char *_file, int _line)
-{
- if (ipa == ipb)
- return;
- printk(KERN_ERR "ip bad assumption (%p==%p) at %s:%d\n",
- ipa, ipb, _file, _line);
-}
-
-
-#define nx_task_nid(t) ((t)->nid)
-
-#define nx_current_nid() nx_task_nid(current)
-
-#define nx_check(c,m) __nx_check(nx_current_nid(),c,m)
-
-#define nx_weak_check(c,m) ((m) ? nx_check(c,m) : 1)
-
-#undef nxdprintk
-#define nxdprintk(x...)
-
-
-#define __nx_flags(v,m,f) (((v) & (m)) ^ (f))
-
-#define __nx_task_flags(t,m,f) \
- (((t) && ((t)->nx_info)) ? \
- __nx_flags((t)->nx_info->nx_flags,(m),(f)) : 0)
-
-#define nx_current_flags() \
- ((current->nx_info) ? current->nx_info->nx_flags : 0)
-
-#define nx_flags(m,f) __nx_flags(nx_current_flags(),(m),(f))
-
-
-#define nx_current_ncaps() \
- ((current->nx_info) ? current->nx_info->nx_ncaps : 0)
-
-#define nx_ncaps(c) (nx_current_ncaps() & (c))
-
-
-
-#define sock_nx_init(s) do { \
- (s)->sk_nid = 0; \
- (s)->sk_nx_info = NULL; \
- } while (0)
-
-
-
-#endif
REISERFS_XATTRS,
REISERFS_XATTRS_USER,
REISERFS_POSIXACL,
+ REISERFS_TAGXID,
REISERFS_TEST1,
REISERFS_TEST2,
* reason (mips != alpha!)
*/
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
+#elif defined(CONFIG_SBC8560)
+/*
+ * WindRiver did something similarly broken on their SBC8560 board. The
+ * UART tristates its IRQ output while OUT2 is clear, but they pulled
+ * the interrupt line _up_ instead of down, so if we register the IRQ
+ * while the UART is in that state, we die in an IRQ storm. */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
#else
#define ALPHA_KLUDGE_MCR 0
#endif
/* PPC CPM type number */
#define PORT_CPM 58
+/* Marvell MPSC for PPC & MIPS */
+#define PORT_MPSC 59
+
#ifdef __KERNEL__
#include <linux/config.h>
unsigned int nlink;
uid_t uid;
gid_t gid;
+ xid_t xid;
dev_t rdev;
loff_t size;
struct timespec atime;
/* FIFO of established children */
struct open_request *accept_queue;
#ifndef CONFIG_ACCEPT_QUEUES
- struct open_request *accept_queue_tail;
+ struct open_request *accept_queue_tail;
#endif
+
unsigned int keepalive_time; /* time before keep alive takes place */
unsigned int keepalive_intvl; /* time interval between keep alive probes */
int linger2;
+++ /dev/null
-#error THIS FILE SHOULD NO LONGER BE USED
-
-
-#ifndef _VX_INLINE_H
-#define _VX_INLINE_H
-
-
-// #define VX_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-
-#include "vserver/context.h"
-#include "vserver/limit.h"
-#include "vserver/cvirt.h"
-
-#if defined(VX_DEBUG)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-
-
-extern int proc_pid_vx_info(struct task_struct *, char *);
-
-
-#define get_vx_info(i) __get_vx_info(i,__FILE__,__LINE__)
-
-static inline struct vx_info *__get_vx_info(struct vx_info *vxi,
- const char *_file, int _line)
-{
- if (!vxi)
- return NULL;
- vxdprintk("get_vx_info(%p[#%d.%d])\t%s:%d\n",
- vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0,
- _file, _line);
- atomic_inc(&vxi->vx_usecnt);
- return vxi;
-}
-
-
-#define free_vx_info(vxi) \
- call_rcu(&vxi->vx_rcu, rcu_free_vx_info, vxi);
-
-#define put_vx_info(i) __put_vx_info(i,__FILE__,__LINE__)
-
-static inline void __put_vx_info(struct vx_info *vxi, const char *_file, int _line)
-{
- if (!vxi)
- return;
- vxdprintk("put_vx_info(%p[#%d.%d])\t%s:%d\n",
- vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0,
- _file, _line);
- if (atomic_dec_and_test(&vxi->vx_usecnt))
- free_vx_info(vxi);
-}
-
-#define set_vx_info(p,i) __set_vx_info(p,i,__FILE__,__LINE__)
-
-static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi,
- const char *_file, int _line)
-{
- BUG_ON(*vxp);
- if (!vxi)
- return;
- vxdprintk("set_vx_info(%p[#%d.%d.%d])\t%s:%d\n",
- vxi, vxi?vxi->vx_id:0,
- vxi?atomic_read(&vxi->vx_usecnt):0,
- vxi?atomic_read(&vxi->vx_refcnt):0,
- _file, _line);
- atomic_inc(&vxi->vx_refcnt);
- *vxp = __get_vx_info(vxi, _file, _line);
-}
-
-#define clr_vx_info(p) __clr_vx_info(p,__FILE__,__LINE__)
-
-static inline void __clr_vx_info(struct vx_info **vxp,
- const char *_file, int _line)
-{
- struct vx_info *vxo = *vxp;
-
- if (!vxo)
- return;
- vxdprintk("clr_vx_info(%p[#%d.%d.%d])\t%s:%d\n",
- vxo, vxo?vxo->vx_id:0,
- vxo?atomic_read(&vxo->vx_usecnt):0,
- vxo?atomic_read(&vxo->vx_refcnt):0,
- _file, _line);
- *vxp = NULL;
- wmb();
- if (vxo && atomic_dec_and_test(&vxo->vx_refcnt))
- unhash_vx_info(vxo);
- __put_vx_info(vxo, _file, _line);
-}
-
-
-#define task_get_vx_info(i) __task_get_vx_info(i,__FILE__,__LINE__)
-
-static __inline__ struct vx_info *__task_get_vx_info(struct task_struct *p,
- const char *_file, int _line)
-{
- struct vx_info *vxi;
-
- task_lock(p);
- vxi = __get_vx_info(p->vx_info, _file, _line);
- task_unlock(p);
- return vxi;
-}
-
-
-#define vx_verify_info(p,i) \
- __vx_verify_info((p)->vx_info,i,__FILE__,__LINE__)
-
-static __inline__ void __vx_verify_info(
- struct vx_info *vxa, struct vx_info *vxb,
- const char *_file, int _line)
-{
- if (vxa == vxb)
- return;
- printk(KERN_ERR "vx bad assumption (%p==%p) at %s:%d\n",
- vxa, vxb, _file, _line);
-}
-
-
-#define vx_task_xid(t) ((t)->xid)
-
-#define vx_current_xid() vx_task_xid(current)
-
-#define vx_check(c,m) __vx_check(vx_current_xid(),c,m)
-
-#define vx_weak_check(c,m) ((m) ? vx_check(c,m) : 1)
-
-
-/*
- * check current context for ADMIN/WATCH and
- * optionally agains supplied argument
- */
-static __inline__ int __vx_check(xid_t cid, xid_t id, unsigned int mode)
-{
- if (mode & VX_ARG_MASK) {
- if ((mode & VX_IDENT) &&
- (id == cid))
- return 1;
- }
- if (mode & VX_ATR_MASK) {
- if ((mode & VX_DYNAMIC) &&
- (id >= MIN_D_CONTEXT) &&
- (id <= MAX_S_CONTEXT))
- return 1;
- if ((mode & VX_STATIC) &&
- (id > 1) && (id < MIN_D_CONTEXT))
- return 1;
- }
- return (((mode & VX_ADMIN) && (cid == 0)) ||
- ((mode & VX_WATCH) && (cid == 1)));
-}
-
-
-#define __vx_flags(v,m,f) (((v) & (m)) ^ (f))
-
-#define __vx_task_flags(t,m,f) \
- (((t) && ((t)->vx_info)) ? \
- __vx_flags((t)->vx_info->vx_flags,(m),(f)) : 0)
-
-#define vx_current_flags() \
- ((current->vx_info) ? current->vx_info->vx_flags : 0)
-
-#define vx_flags(m,f) __vx_flags(vx_current_flags(),(m),(f))
-
-
-#define vx_current_ccaps() \
- ((current->vx_info) ? current->vx_info->vx_ccaps : 0)
-
-#define vx_ccaps(c) (vx_current_ccaps() & (c))
-
-#define vx_current_bcaps() \
- (((current->vx_info) && !vx_flags(VXF_STATE_SETUP, 0)) ? \
- current->vx_info->vx_bcaps : cap_bset)
-
-
-#define VX_DEBUG_ACC_RSS 0
-#define VX_DEBUG_ACC_VM 0
-#define VX_DEBUG_ACC_VML 0
-
-#undef vxdprintk
-#if (VX_DEBUG_ACC_RSS) || (VX_DEBUG_ACC_VM) || (VX_DEBUG_ACC_VML)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-#define vx_acc_page(m, d, v, r) \
- __vx_acc_page(&(m->v), m->mm_vx_info, r, d, __FILE__, __LINE__)
-
-static inline void __vx_acc_page(unsigned long *v, struct vx_info *vxi,
- int res, int dir, char *file, int line)
-{
- if (v) {
- if (dir > 0)
- ++(*v);
- else
- --(*v);
- }
- if (vxi) {
- if (dir > 0)
- atomic_inc(&vxi->limit.res[res]);
- else
- atomic_dec(&vxi->limit.res[res]);
- }
-}
-
-
-#define vx_acc_pages(m, p, v, r) \
- __vx_acc_pages(&(m->v), m->mm_vx_info, r, p, __FILE__, __LINE__)
-
-static inline void __vx_acc_pages(unsigned long *v, struct vx_info *vxi,
- int res, int pages, char *file, int line)
-{
- if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) ||
- (res == RLIMIT_AS && VX_DEBUG_ACC_VM) ||
- (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML))
- vxdprintk("vx_acc_pages [%5d,%2d]: %5d += %5d in %s:%d\n",
- (vxi?vxi->vx_id:-1), res,
- (vxi?atomic_read(&vxi->limit.res[res]):0),
- pages, file, line);
- if (pages == 0)
- return;
- if (v)
- *v += pages;
- if (vxi)
- atomic_add(pages, &vxi->limit.res[res]);
-}
-
-
-
-#define vx_acc_vmpage(m,d) vx_acc_page(m, d, total_vm, RLIMIT_AS)
-#define vx_acc_vmlpage(m,d) vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK)
-#define vx_acc_rsspage(m,d) vx_acc_page(m, d, rss, RLIMIT_RSS)
-
-#define vx_acc_vmpages(m,p) vx_acc_pages(m, p, total_vm, RLIMIT_AS)
-#define vx_acc_vmlpages(m,p) vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK)
-#define vx_acc_rsspages(m,p) vx_acc_pages(m, p, rss, RLIMIT_RSS)
-
-#define vx_pages_add(s,r,p) __vx_acc_pages(0, s, r, p, __FILE__, __LINE__)
-#define vx_pages_sub(s,r,p) __vx_pages_add(s, r, -(p))
-
-#define vx_vmpages_inc(m) vx_acc_vmpage(m, 1)
-#define vx_vmpages_dec(m) vx_acc_vmpage(m,-1)
-#define vx_vmpages_add(m,p) vx_acc_vmpages(m, p)
-#define vx_vmpages_sub(m,p) vx_acc_vmpages(m,-(p))
-
-#define vx_vmlocked_inc(m) vx_acc_vmlpage(m, 1)
-#define vx_vmlocked_dec(m) vx_acc_vmlpage(m,-1)
-#define vx_vmlocked_add(m,p) vx_acc_vmlpages(m, p)
-#define vx_vmlocked_sub(m,p) vx_acc_vmlpages(m,-(p))
-
-#define vx_rsspages_inc(m) vx_acc_rsspage(m, 1)
-#define vx_rsspages_dec(m) vx_acc_rsspage(m,-1)
-#define vx_rsspages_add(m,p) vx_acc_rsspages(m, p)
-#define vx_rsspages_sub(m,p) vx_acc_rsspages(m,-(p))
-
-
-
-#define vx_pages_avail(m, p, r) \
- __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__)
-
-static inline int __vx_pages_avail(struct vx_info *vxi,
- int res, int pages, char *file, int line)
-{
- if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) ||
- (res == RLIMIT_AS && VX_DEBUG_ACC_VM) ||
- (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML))
- printk("vx_pages_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n",
- (vxi?vxi->vx_id:-1), res,
- (vxi?vxi->limit.rlim[res]:1),
- (vxi?atomic_read(&vxi->limit.res[res]):0),
- pages, file, line);
- if (!vxi)
- return 1;
- if (vxi->limit.rlim[res] == RLIM_INFINITY)
- return 1;
- if (atomic_read(&vxi->limit.res[res]) + pages < vxi->limit.rlim[res])
- return 1;
- return 0;
-}
-
-#define vx_vmpages_avail(m,p) vx_pages_avail(m, p, RLIMIT_AS)
-#define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK)
-#define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS)
-
-/* file limits */
-
-#define VX_DEBUG_ACC_FILE 0
-#define VX_DEBUG_ACC_OPENFD 0
-
-#undef vxdprintk
-#if (VX_DEBUG_ACC_FILE) || (VX_DEBUG_ACC_OPENFD)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-
-#define vx_acc_cres(v,d,r) \
- __vx_acc_cres((v), (r), (d), __FILE__, __LINE__)
-
-static inline void __vx_acc_cres(struct vx_info *vxi,
- int res, int dir, char *file, int line)
-{
- if (vxi) {
- if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) ||
- (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD))
- printk("vx_acc_cres[%5d,%2d]: %5d%s in %s:%d\n",
- (vxi?vxi->vx_id:-1), res,
- (vxi?atomic_read(&vxi->limit.res[res]):0),
- (dir>0)?"++":"--", file, line);
- if (dir > 0)
- atomic_inc(&vxi->limit.res[res]);
- else
- atomic_dec(&vxi->limit.res[res]);
- }
-}
-
-#define vx_files_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_NOFILE)
-#define vx_files_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_NOFILE)
-
-#define vx_openfd_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_OPENFD)
-#define vx_openfd_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_OPENFD)
-
-#define vx_cres_avail(v,n,r) \
- __vx_cres_avail((v), (r), (n), __FILE__, __LINE__)
-
-static inline int __vx_cres_avail(struct vx_info *vxi,
- int res, int num, char *file, int line)
-{
- if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) ||
- (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD))
- printk("vx_cres_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n",
- (vxi?vxi->vx_id:-1), res,
- (vxi?vxi->limit.rlim[res]:1),
- (vxi?atomic_read(&vxi->limit.res[res]):0),
- num, file, line);
- if (!vxi)
- return 1;
- if (vxi->limit.rlim[res] == RLIM_INFINITY)
- return 1;
- if (vxi->limit.rlim[res] < atomic_read(&vxi->limit.res[res]) + num)
- return 0;
- return 1;
-}
-
-#define vx_files_avail(n) \
- vx_cres_avail(current->vx_info, (n), RLIMIT_NOFILE)
-
-#define vx_openfd_avail(n) \
- vx_cres_avail(current->vx_info, (n), RLIMIT_OPENFD)
-
-/* socket limits */
-
-#define vx_sock_inc(f) vx_acc_cres(current->vx_info, 1, VLIMIT_SOCK)
-#define vx_sock_dec(f) vx_acc_cres(current->vx_info,-1, VLIMIT_SOCK)
-
-#define vx_sock_avail(n) \
- vx_cres_avail(current->vx_info, (n), VLIMIT_SOCK)
-
-/* procfs ioctls */
-
-#define FIOC_GETXFLG _IOR('x', 5, long)
-#define FIOC_SETXFLG _IOW('x', 6, long)
-
-/* utsname virtualization */
-
-static inline struct new_utsname *vx_new_utsname(void)
-{
- if (current->vx_info)
- return ¤t->vx_info->cvirt.utsname;
- return &system_utsname;
-}
-
-#define vx_new_uts(x) ((vx_new_utsname())->x)
-
-/* generic flag merging */
-
-#define vx_mask_flags(v,f,m) (((v) & ~(m)) | ((f) & (m)))
-
-#define vx_mask_mask(v,f,m) (((v) & ~(m)) | ((v) & (f) & (m)))
-
-
-/* socket accounting */
-
-#include <linux/socket.h>
-
-static inline int vx_sock_type(int family)
-{
- int type = 4;
-
- if (family > 0 && family < 3)
- type = family;
- else if (family == PF_INET6)
- type = 3;
- return type;
-}
-
-#define vx_acc_sock(v,f,p,s) \
- __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__)
-
-static inline void __vx_acc_sock(struct vx_info *vxi,
- int family, int pos, int size, char *file, int line)
-{
- if (vxi) {
- int type = vx_sock_type(family);
-
- atomic_inc(&vxi->cacct.sock[type][pos].count);
- atomic_add(size, &vxi->cacct.sock[type][pos].total);
- }
-}
-
-#define vx_sock_recv(sk,s) \
- vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s))
-#define vx_sock_send(sk,s) \
- vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s))
-#define vx_sock_fail(sk,s) \
- vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s))
-
-
-#define sock_vx_init(s) do { \
- (s)->sk_xid = 0; \
- (s)->sk_vx_info = NULL; \
- } while (0)
-
-
-/* pid faking stuff */
-
-
-#define vx_map_tgid(v,p) \
- __vx_map_tgid((v), (p), __FILE__, __LINE__)
-
-static inline int __vx_map_tgid(struct vx_info *vxi, int pid,
- char *file, int line)
-{
- if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) {
- vxdprintk("vx_map_tgid: %p/%llx: %d -> %d in %s:%d\n",
- vxi, vxi->vx_flags, pid,
- (pid == vxi->vx_initpid)?1:pid,
- file, line);
- if (pid == vxi->vx_initpid)
- return 1;
- }
- return pid;
-}
-
-#define vx_rmap_tgid(v,p) \
- __vx_rmap_tgid((v), (p), __FILE__, __LINE__)
-
-static inline int __vx_rmap_tgid(struct vx_info *vxi, int pid,
- char *file, int line)
-{
- if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) {
- vxdprintk("vx_rmap_tgid: %p/%llx: %d -> %d in %s:%d\n",
- vxi, vxi->vx_flags, pid,
- (pid == 1)?vxi->vx_initpid:pid,
- file, line);
- if ((pid == 1) && vxi->vx_initpid)
- return vxi->vx_initpid;
- }
- return pid;
-}
-
-#undef vxdprintk
-#define vxdprintk(x...)
-
-#endif
#include <linux/vs_context.h>
#include <linux/vs_network.h>
-
#ifndef __KERNEL__
#warning This file is not supposed to be used outside of kernel.
#endif
{
return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
}
-
#endif
/*
Say N if unsure, Y to use the feature.
config CKRM_CPU_MONITOR
- tristate "CKRM CPU Resoure Monitor"
+ bool "CKRM CPU Resoure Monitor"
depends on CKRM_CPU_SCHEDULE
default m
help
for processing it. A preliminary version of these tools is available
at <http://http://www.de.kernel.org/pub/linux/utils/acct/>.
-
config SYSCTL
bool "Sysctl support"
---help---
#include <asm/setup.h>
#include <linux/ckrm.h>
+#ifdef CONFIG_CKRM_CPU_SCHEDULE
int __init init_ckrm_sched_res(void);
-
+#else
+#define init_ckrm_sched_res() ((void)0)
+#endif
/*
* This is one of the first .c files built. Error out early
#include <asm/unistd.h>
+#include <asm/unistd.h>
+
#include "util.h"
/**
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/mempolicy.h>
-#include <linux/vs_limit.h>
-
#include <linux/ckrm.h>
#include <linux/ckrm_tsk.h>
+#include <linux/vs_limit.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
struct file * file = xchg(&files->fd[i], NULL);
if (file) {
filp_close(file, files);
- vx_openfd_dec(fd);
cond_resched();
- } else {
- vx_openfd_dec(fd);
}
+ vx_openfd_dec(fd);
}
i++;
set >>= 1;
#include <linux/mount.h>
#include <linux/audit.h>
#include <linux/rmap.h>
-
#include <linux/vs_network.h>
-#include <linux/vs_memory.h>
#include <linux/vs_limit.h>
-#include <linux/vs_base.h>
-
#include <linux/ckrm.h>
#include <linux/ckrm_tsk.h>
vxi = current->vx_info;
if (vxi) {
atomic_inc(&vxi->cacct.nr_threads);
- // atomic_inc(&vxi->limit.res[RLIMIT_NPROC]);
+ // atomic_inc(&vxi->limit.rcur[RLIMIT_NPROC]);
}
vx_nproc_inc();
write_unlock_irq(&tasklist_lock);
#include <linux/cpu.h>
#include <linux/percpu.h>
#include <linux/kthread.h>
-#include <asm/tlb.h>
#include <linux/vserver/sched.h>
#include <linux/vs_base.h>
+#include <asm/tlb.h>
#include <asm/unistd.h>
#define TASK_PREEMPTS_CURR(p, rq) \
(((p)->cpu_class != (rq)->curr->cpu_class) && ((rq)->curr != (rq)->idle))? class_preempts_curr((p),(rq)->curr) : ((p)->prio < (rq)->curr->prio)
#else
+#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
+struct prio_array {
+ unsigned int nr_active;
+ unsigned long bitmap[BITMAP_SIZE];
+ struct list_head queue[MAX_PRIO];
+};
+#define rq_active(p,rq) (rq->active)
+#define rq_expired(p,rq) (rq->expired)
+#define ckrm_rebalance_tick(j,this_cpu) do {} while (0)
#define TASK_PREEMPTS_CURR(p, rq) \
((p)->prio < (rq)->curr->prio)
#endif
array = queue->active;
//check switch active/expired queue
if (unlikely(!queue->active->nr_active)) {
+ prio_array_t *array;
+
+ array = queue->active;
queue->active = queue->expired;
queue->expired = array;
queue->expired_timestamp = 0;
next_group:
group = group->next;
} while (group != sd->groups);
->>>>>>> 1.1.9.3
}
#endif /* CONFIG_CKRM_CPU_SCHEDULE*/
#include <linux/security.h>
#include <linux/dcookies.h>
#include <linux/suspend.h>
+#include <linux/ckrm.h>
#include <linux/vs_base.h>
#include <linux/vs_cvirt.h>
-#include <linux/ckrm.h>
#include <asm/uaccess.h>
#include <asm/io.h>
old_rlim = current->rlim + resource;
if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
- !capable(CAP_SYS_RESOURCE) && vx_ccaps(VXC_SET_RLIMIT))
+ !capable(CAP_SYS_RESOURCE) && !vx_ccaps(VXC_SET_RLIMIT))
return -EPERM;
if (resource == RLIMIT_NOFILE) {
if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
void rcu_free_vx_info(struct rcu_head *head)
{
- struct vx_info *vxi = container_of(head, struct vx_info, vx_rcu);
+ struct vx_info *vxi = container_of(head, struct vx_info, vx_rcu);
int usecnt, refcnt;
- BUG_ON(!vxi || !head);
+ BUG_ON(!vxi);
usecnt = atomic_read(&vxi->vx_usecnt);
BUG_ON(usecnt < 0);
void rcu_free_dl_info(struct rcu_head *head)
{
- struct dl_info *dli = container_of(head, struct dl_info, dl_rcu);
+ struct dl_info *dli = container_of(head, struct dl_info, dl_rcu);
int usecnt, refcnt;
- BUG_ON(!dli || !head);
+ BUG_ON(!dli);
usecnt = atomic_read(&dli->dl_usecnt);
BUG_ON(usecnt < 0);
void rcu_free_nx_info(struct rcu_head *head)
{
- struct nx_info *nxi = container_of(head, struct nx_info, nx_rcu);
+ struct nx_info *nxi = container_of(head, struct nx_info, nx_rcu);
int usecnt, refcnt;
- BUG_ON(!nxi || !head);
-
usecnt = atomic_read(&nxi->nx_usecnt);
BUG_ON(usecnt < 0);
goto out;
if (pmd_huge(*pmd))
return follow_huge_pmd(mm, address, pmd, write);
- if (unlikely(pmd_bad(*pmd)))
+ if (pmd_bad(*pmd))
goto out;
ptep = pte_offset_map(pmd, address);
if (pte_present(pte)) {
if (write && !pte_write(pte))
goto out;
+ if (write && !pte_dirty(pte)) {
+ struct page *page = pte_page(pte);
+ if (!PageDirty(page))
+ set_page_dirty(page);
+ }
pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
- page = pfn_to_page(pfn);
- if (write && !pte_dirty(pte) && !PageDirty(page))
- set_page_dirty(page);
+ struct page *page = pfn_to_page(pfn);
+
mark_page_accessed(page);
return page;
} else {
pte_t entry;
struct page * page = ZERO_PAGE(addr);
- if (!vx_rsspages_avail(mm, 1)) {
- spin_unlock(&mm->page_table_lock);
- return VM_FAULT_OOM;
- }
-
/* Read-only mapping of ZERO_PAGE. */
entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
if (unlikely(anon_vma_prepare(vma)))
goto no_mem;
+ if (!vx_rsspages_avail(mm, 1))
+ goto no_mem;
+
page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
if (!page)
goto no_mem;
/* Only go through if we didn't race with anybody else... */
if (pte_none(*page_table)) {
if (!PageReserved(new_page))
- // ++mm->rss;
- vx_rsspages_inc(mm);
+ ++mm->rss;
flush_icache_page(vma, new_page);
entry = mk_pte(new_page, vma->vm_page_prot);
if (write_access)
ret = make_pages_present(start, end);
}
- vma->vm_mm->locked_vm -= pages;
+ // vma->vm_mm->locked_vm -= pages;
+ vx_vmlocked_sub(vma->vm_mm, pages);
out:
return ret;
}
ret = -ENOMEM;
if (!vx_vmlocked_avail(current->mm, current->mm->total_vm))
goto out;
- /* check vserver lock limits? */
if ((current->mm->total_vm <= lock_limit) || capable(CAP_IPC_LOCK))
ret = do_mlockall(flags);
out:
address &= PAGE_MASK;
grow = (address - vma->vm_end) >> PAGE_SHIFT;
- /* Overcommit.. */
- if (security_vm_enough_memory(grow) ||
- !vx_vmpages_avail(vma->vm_mm, grow)) {
+ /* Overcommit.. vx check first to avoid vm_unacct_memory() */
+ if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+ security_vm_enough_memory(grow)) {
anon_vma_unlock(vma);
return -ENOMEM;
}
vm_unacct_memory(grow);
return -ENOMEM;
}
-
vma->vm_end = address;
// vma->vm_mm->total_vm += grow;
vx_vmpages_add(vma->vm_mm, grow);
address &= PAGE_MASK;
grow = (vma->vm_start - address) >> PAGE_SHIFT;
- /* Overcommit.. */
- if (security_vm_enough_memory(grow) ||
- !vx_vmpages_avail(vma->vm_mm, grow)) {
+ /* Overcommit.. vx check first to avoid vm_unacct_memory() */
+ if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+ security_vm_enough_memory(grow)) {
anon_vma_unlock(vma);
return -ENOMEM;
}
vm_unacct_memory(grow);
return -ENOMEM;
}
-
vma->vm_start = address;
vma->vm_pgoff -= grow;
// vma->vm_mm->total_vm += grow;
locked += len;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
return -EAGAIN;
- /* vserver checks ? */
+ if (!vx_vmlocked_avail(mm, len >> PAGE_SHIFT))
+ return -ENOMEM;
}
/*
#include <linux/fs.h>
#include <linux/highmem.h>
#include <linux/security.h>
-#include <linux/vs_memory.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
ret = -EAGAIN;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
goto out;
+ ret = -ENOMEM;
+ if (!vx_vmlocked_avail(current->mm,
+ (new_len - old_len) >> PAGE_SHIFT))
+ goto out;
}
ret = -ENOMEM;
if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
vx_vmpages_add(current->mm, pages);
if (vma->vm_flags & VM_LOCKED) {
// current->mm->locked_vm += pages;
- vx_vmlocked_add(current->mm, pages);
+ vx_vmlocked_add(vma->vm_mm, pages);
make_pages_present(addr + old_len,
addr + new_len);
}
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
struct page *page = NULL;
swp_entry_t *entry;
- static const swp_entry_t unswapped = { 0 };
if (sgp != SGP_WRITE &&
((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
while (!(entry = shmem_swp_entry(info, index, &page))) {
if (sgp == SGP_READ)
- return (swp_entry_t *) &unswapped;
+ return shmem_swp_map(ZERO_PAGE(0));
/*
* Test free_blocks against 1 not 0, since we have 1 data
* page (and perhaps indirect index pages) yet to allocate:
#include <asm/tlbflush.h>
#include <linux/swapops.h>
#include <linux/vs_base.h>
-#include <linux/vs_memory.h>
spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
unsigned int nr_swapfiles;
#include <linux/kallsyms.h>
#include <linux/netpoll.h>
#include <linux/rcupdate.h>
+#include <linux/vserver/network.h>
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
#include <net/iw_handler.h>
security_sk_free(sk);
BUG_ON(sk->sk_vx_info);
BUG_ON(sk->sk_nx_info);
-/* clr_vx_info(&sk->sk_vx_info);
- clr_nx_info(&sk->sk_nx_info); */
kmem_cache_free(sk->sk_slab, sk);
module_put(owner);
}
if (inet->opt)
kfree(inet->opt);
- BUG_ON(sk->sk_nx_info);
- BUG_ON(sk->sk_vx_info);
+ clr_vx_info(&sk->sk_vx_info);
+ sk->sk_xid = -1;
+ clr_nx_info(&sk->sk_nx_info);
+ sk->sk_nid = -1;
+
dst_release(sk->sk_dst_cache);
#ifdef INET_REFCNT_DEBUG
atomic_dec(&inet_sock_nr);
if (!answer)
goto out_sk_free;
err = -EPERM;
+ if ((protocol == IPPROTO_ICMP) && vx_ccaps(VXC_RAW_ICMP))
+ goto override;
if (answer->capability > 0 && !capable(answer->capability))
goto out_sk_free;
+override:
err = -EPROTONOSUPPORT;
if (!protocol)
goto out_sk_free;
timeout = sk->sk_lingertime;
sock->sk = NULL;
clr_vx_info(&sk->sk_vx_info);
+ sk->sk_xid = -1;
clr_nx_info(&sk->sk_nx_info);
+ sk->sk_nid = -1;
sk->sk_prot->close(sk, timeout);
}
return 0;
.saddr = saddr,
.tos = RT_TOS(tos) } },
.proto = IPPROTO_ICMP };
+
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
.proto = inet->hdrincl ? IPPROTO_RAW :
sk->sk_protocol,
};
+
+ if (sk->sk_nx_info) {
+ err = ip_find_src(sk->sk_nx_info, &rt, &fl);
+
+ if (err)
+ goto done;
+ }
err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
}
if (err)
atomic_t tcp_orphan_count = ATOMIC_INIT(0);
int sysctl_tcp_default_win_scale = 7;
+
int sysctl_tcp_mem[3];
int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
newsk->sk_priority = 0;
atomic_set(&newsk->sk_refcnt, 2);
- /* hmm, maybe from socket? */
- set_vx_info(&newsk->sk_vx_info, current->vx_info);
- set_nx_info(&newsk->sk_nx_info, current->nx_info);
+ set_vx_info(&newsk->sk_vx_info, sk->sk_vx_info);
+ newsk->sk_xid = sk->sk_xid;
+ set_nx_info(&newsk->sk_nx_info, sk->sk_nx_info);
+ newsk->sk_nid = sk->sk_nid;
#ifdef INET_REFCNT_DEBUG
atomic_inc(&inet_sock_nr);
#endif
#include <linux/socket.h>
#include <linux/sunrpc/clnt.h>
#include <linux/spinlock.h>
+#include <linux/vserver/xid.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
struct rpc_cred *ret;
get_group_info(current->group_info);
- acred.uid = current->fsuid;
- acred.gid = current->fsgid;
+ acred.uid = XIDINO_UID(current->fsuid, current->xid);
+ acred.gid = XIDINO_GID(current->fsgid, current->xid);
acred.group_info = current->group_info;
dprintk("RPC: looking up %s cred\n",
struct rpc_cred *ret;
get_group_info(current->group_info);
- acred.uid = current->fsuid;
- acred.gid = current->fsgid;
+ acred.uid = XIDINO_UID(current->fsuid, current->xid);
+ acred.gid = XIDINO_GID(current->fsgid, current->xid);
acred.group_info = current->group_info;
dprintk("RPC: %4d looking up %s cred\n",
#include <linux/in.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h>
+#include <linux/vserver/xid.h>
#define NFS_NGROUPS 16
cred->uc_uid = acred->uid;
cred->uc_gid = acred->gid;
+// cred->uc_puid = XIDINO_UID(current->uid, current->xid);
+// cred->uc_pgid = XIDINO_GID(current->gid, current->xid);
cred->uc_puid = current->uid;
cred->uc_pgid = current->gid;
for (i = 0; i < groups; i++)
if (cred->uc_uid != acred->uid
|| cred->uc_gid != acred->gid
- || cred->uc_puid != current->uid
- || cred->uc_pgid != current->gid)
+ || cred->uc_puid != XIDINO_UID(current->uid, current->xid)
+ || cred->uc_pgid != XIDINO_GID(current->gid, current->xid))
return 0;
groups = acred->group_info->ngroups;
#include <linux/mount.h>
#include <net/checksum.h>
#include <linux/security.h>
-
#include <linux/vs_context.h>
#include <linux/vs_network.h>
-
int sysctl_unix_max_dgram_qlen = 10;
kmem_cache_t *unix_sk_cachep;
if (($line =~ /\.init$/ || $line =~ /\.init\./) &&
($from !~ /\.init$/ &&
$from !~ /\.init\./ &&
+ $from !~ /\.eh_frame$/ &&
$from !~ /\.stab$/ &&
$from !~ /\.rodata$/ &&
$from !~ /\.text\.lock$/ &&