Commit 1d23a518 authored by Linus Torvalds's avatar Linus Torvalds

v2.4.10.3 -> v2.4.10.4

  - Al Viro: separate out superblocks and FS namespaces: fs/super.c fathers
  fs/namespace.c
  - David Woodhouse: large MTD and JFFS[2] update
  - Marcelo Tosatti: resurrect oom handling
  - Hugh Dickins: add_to_swap_cache racefix cleanup
  - Jean Tourrilhes: IrDA update
  - Martin Bligh: support clustered logical APIC for >8 CPU x86 boxes
  - Richard Henderson: alpha update
parent 0a97b16a
......@@ -119,6 +119,14 @@ CONFIG_SMP
SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ .
If you don't know what to do here, say N.
Multiquad support for NUMA systems
CONFIG_MULTIQUAD
This option is used for getting Linux to run on a (IBM/Sequent) NUMA
multiquad box. This changes the way that processors are bootstrapped,
and uses Clustered Logical APIC addressing mode instead of Flat Logical.
You will need a new lynxer.elf file to flash your firmware with - send
email to Martin.Bligh@us.ibm.com
IO-APIC Support on Uniprocessors
CONFIG_X86_UP_IOAPIC
......@@ -18495,6 +18503,16 @@ CONFIG_SMC_IRCC_FIR
here and read Documentation/modules.txt. The module will be called
smc-ircc.o.
VLSI 82C147 PCI-IrDA Controller Driver
CONFIG_VLSI_FIR
Say Y here if you want to build support for the VLSI 82C147
PCI-IrDA Controller. This controller is used by the HP OmniBook 800
and 5500 notebooks. The driver provides support for SIR, MIR and
FIR (4Mbps) speeds.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. The module will be called vlsi_ir.o.
Serial dongle support
CONFIG_DONGLE
Say Y here if you have an infrared device that connects to your
......
......@@ -126,7 +126,7 @@ solutions for on-flash filesystems as mentioned below.
Using JFFS2
-----------
Using JFFS2 (the Second Journaling Flash File System) is probably the most
Using JFFS2 (the Second Journalling Flash File System) is probably the most
convenient way to store a writable filesystem into flash. JFFS2 is used in
conjunction with the MTD layer which is responsible for low-level flash
management. More information on the Linux MTD can be found on-line at:
......
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 11
EXTRAVERSION =-pre3
EXTRAVERSION =-pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
......
......@@ -59,7 +59,7 @@ ksize.h: vmlinux.nh dummy
echo "#define KERNEL_SIZE `ls -l vmlinux.nh | awk '{print $$5}'`" > $@T
ifdef INITRD
[ -f $(INITRD) ] || exit 1
echo "#define INITRD_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T
echo "#define INITRD_IMAGE_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T
endif
cmp -s $@T $@ || mv -f $@T $@
rm -f $@T
......
......@@ -147,7 +147,7 @@ start_kernel(void)
*/
static long nbytes;
static char envval[256] __attribute__((aligned(8)));
#ifdef INITRD_SIZE
#ifdef INITRD_IMAGE_SIZE
static unsigned long initrd_start;
#endif
......@@ -164,7 +164,7 @@ start_kernel(void)
}
pal_init();
#ifdef INITRD_SIZE
#ifdef INITRD_IMAGE_SIZE
/* The initrd must be page-aligned. See below for the
cause of the magic number 5. */
initrd_start = ((START_ADDR + 5*KERNEL_SIZE) | (PAGE_SIZE-1)) + 1;
......@@ -192,17 +192,17 @@ start_kernel(void)
*
* Sigh... */
#ifdef INITRD_SIZE
load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_SIZE);
#ifdef INITRD_IMAGE_SIZE
load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_IMAGE_SIZE);
#endif
load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
memset((char*)ZERO_PGE, 0, PAGE_SIZE);
strcpy((char*)ZERO_PGE, envval);
#ifdef INITRD_SIZE
#ifdef INITRD_IMAGE_SIZE
((long *)(ZERO_PGE+256))[0] = initrd_start;
((long *)(ZERO_PGE+256))[1] = INITRD_SIZE;
((long *)(ZERO_PGE+256))[1] = INITRD_IMAGE_SIZE;
#endif
runkernel();
......
......@@ -142,15 +142,18 @@ if [ "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_EIGER" = "y" ]
then
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_TSUNAMI y
bool 'EV67 (or later) CPU (speed > 600MHz)?' CONFIG_ALPHA_EV67
fi
if [ "$CONFIG_ALPHA_SHARK" = "y" ]
then
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_EV67 y
define_bool CONFIG_ALPHA_TSUNAMI y
fi
if [ "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "y" ]
then
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_EV67 y
fi
if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
then
......@@ -170,6 +173,7 @@ if [ "$CONFIG_ALPHA_NAUTILUS" = "y" ]
then
define_bool CONFIG_ALPHA_IRONGATE y
define_bool CONFIG_ALPHA_EV6 y
define_bool CONFIG_ALPHA_EV67 y
fi
if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
......
......@@ -108,11 +108,6 @@ init_IRQ(void)
wrent(entInt, 0);
alpha_mv.init_irq();
/* If we had wanted SRM console printk echoing early, undo it now. */
if (alpha_using_srm && srmcons_output) {
unregister_srm_console();
}
}
/*
......
......@@ -63,12 +63,20 @@ unsigned long srm_hae;
/* Which processor we booted from. */
int boot_cpuid;
/* Using SRM callbacks for initial console output. This works from
setup_arch() time through the end of init_IRQ(), as those places
are under our control.
By default, OFF; set it with a bootcommand arg of "srmcons".
*/
/*
* Using SRM callbacks for initial console output. This works from
* setup_arch() time through the end of time_init(), as those places
* are under our (Alpha) control.
* "srmcons" specified in the boot command arguments allows us to
* see kernel messages during the period of time before the true
* console device is "registered" during console_init(). As of this
* version (2.4.10), time_init() is the last Alpha-specific code
* called before console_init(), so we put "unregister" code
* there to prevent schizophrenic console behavior later... ;-}
*
* By default, OFF; set it with a bootcommand arg of "srmcons".
*/
int srmcons_output = 0;
/* Enforce a memory size limit; useful for testing. By default, none. */
......@@ -85,7 +93,7 @@ unsigned char aux_device_present = 0xaa;
static struct alpha_machine_vector *get_sysvec(long, long, long);
static struct alpha_machine_vector *get_sysvec_byname(const char *);
static void get_sysnames(long, long, char **, char **);
static void get_sysnames(long, long, long, char **, char **);
static char command_line[COMMAND_LINE_SIZE];
char saved_command_line[COMMAND_LINE_SIZE];
......@@ -537,14 +545,14 @@ setup_arch(char **cmdline_p)
/*
* Indentify and reconfigure for the current system.
*/
cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
&type_name, &var_name);
cpu->type, &type_name, &var_name);
if (*var_name == '0')
var_name = "";
if (!vec) {
cpu = (struct percpu_struct*)
((char*)hwrpb + hwrpb->processor_offset);
vec = get_sysvec(hwrpb->sys_type, hwrpb->sys_variation,
cpu->type);
}
......@@ -801,6 +809,8 @@ get_sysvec(long type, long variation, long cpu)
/* Member ID is a bit-field. */
long member = (variation >> 10) & 0x3f;
cpu &= 0xffffffff; /* make it usable */
switch (type) {
case ST_DEC_ALCOR:
if (member < N(alcor_indices))
......@@ -809,6 +819,10 @@ get_sysvec(long type, long variation, long cpu)
case ST_DEC_EB164:
if (member < N(eb164_indices))
vec = eb164_vecs[eb164_indices[member]];
/* PC164 may show as EB164 variation with EV56 CPU,
but, since no true EB164 had anything but EV5... */
if (vec == &eb164_mv && cpu == EV56_CPU)
vec = &pc164_mv;
break;
case ST_DEC_EB64P:
if (member < N(eb64p_indices))
......@@ -827,21 +841,18 @@ get_sysvec(long type, long variation, long cpu)
vec = tsunami_vecs[tsunami_indices[member]];
break;
case ST_DEC_1000:
cpu &= 0xffffffff;
if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &mikasa_primo_mv;
else
vec = &mikasa_mv;
break;
case ST_DEC_NORITAKE:
cpu &= 0xffffffff;
if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &noritake_primo_mv;
else
vec = &noritake_mv;
break;
case ST_DEC_2100_A500:
cpu &= 0xffffffff;
if (cpu == EV5_CPU || cpu == EV56_CPU)
vec = &sable_gamma_mv;
else
......@@ -905,7 +916,7 @@ get_sysvec_byname(const char *name)
}
static void
get_sysnames(long type, long variation,
get_sysnames(long type, long variation, long cpu,
char **type_name, char **variation_name)
{
long member;
......@@ -938,12 +949,18 @@ get_sysnames(long type, long variation,
member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
cpu &= 0xffffffff; /* make it usable */
switch (type) { /* select by family */
default: /* default to variation "0" for now */
break;
case ST_DEC_EB164:
if (member < N(eb164_indices))
*variation_name = eb164_names[eb164_indices[member]];
/* PC164 may show as EB164 variation, but with EV56 CPU,
so, since no true EB164 had anything but EV5... */
if (eb164_indices[member] == 0 && cpu == EV56_CPU)
*variation_name = eb164_names[1]; /* make it PC164 */
break;
case ST_DEC_ALCOR:
if (member < N(alcor_indices))
......@@ -1054,7 +1071,7 @@ int get_cpuinfo(char *buffer)
cpu_name = cpu_names[cpu_index];
get_sysnames(hwrpb->sys_type, hwrpb->sys_variation,
&systype_name, &sysvariation_name);
cpu->type, &systype_name, &sysvariation_name);
nr_processors = get_nr_processors(cpu, hwrpb->nr_processors);
......
......@@ -106,12 +106,12 @@ cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
}
static void __init
cabriolet_init_irq(void)
common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
{
init_i8259a_irqs();
if (alpha_using_srm) {
alpha_mv.device_interrupt = srm_device_interrupt;
alpha_mv.device_interrupt = srm_dev_int;
init_srm_irqs(35, 0);
}
else {
......@@ -131,29 +131,47 @@ cabriolet_init_irq(void)
setup_irq(16+4, &isa_cascade_irqaction);
}
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
static void
pc164_device_interrupt(unsigned long v, struct pt_regs *r)
static void __init
cabriolet_init_irq(void)
{
/* In theory, the PC164 has the same interrupt hardware as
the other Cabriolet based systems. However, something
got screwed up late in the development cycle which broke
the interrupt masking hardware. Repeat, it is not
possible to mask and ack interrupts. At all.
common_init_irq(srm_device_interrupt);
}
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
/* In theory, the PC164 has the same interrupt hardware as the other
Cabriolet based systems. However, something got screwed up late
in the development cycle which broke the interrupt masking hardware.
Repeat, it is not possible to mask and ack interrupts. At all.
In an attempt to work around this, while processing
interrupts, we do not allow the IPL to drop below what
it is currently. This prevents the possibility of
recursion.
In an attempt to work around this, while processing interrupts,
we do not allow the IPL to drop below what it is currently. This
prevents the possibility of recursion.
??? Another option might be to force all PCI devices
to use edge triggered rather than level triggered
interrupts. That might be too invasive though. */
??? Another option might be to force all PCI devices to use edge
triggered rather than level triggered interrupts. That might be
too invasive though. */
static void
pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r)
{
__min_ipl = getipl();
srm_device_interrupt(v, r);
__min_ipl = 0;
}
static void
pc164_device_interrupt(unsigned long v, struct pt_regs *r)
{
__min_ipl = getipl();
cabriolet_device_interrupt(v, r);
__min_ipl = 0;
}
static void __init
pc164_init_irq(void)
{
common_init_irq(pc164_srm_device_interrupt);
}
#endif
/*
......@@ -419,7 +437,7 @@ struct alpha_machine_vector pc164_mv __initmv = {
device_interrupt: pc164_device_interrupt,
init_arch: cia_init_arch,
init_irq: cabriolet_init_irq,
init_irq: pc164_init_irq,
init_rtc: common_init_rtc,
init_pci: alphapc164_init_pci,
pci_map_irq: alphapc164_map_irq,
......
......@@ -332,6 +332,21 @@ time_init(void)
alpha_mv.init_rtc();
do_get_fast_time = do_gettimeofday;
/*
* If we had wanted SRM console printk echoing early, undo it now.
*
* "srmcons" specified in the boot command arguments allows us to
* see kernel messages during the period of time before the true
* console device is "registered" during console_init(). As of this
* version (2.4.10), time_init() is the last Alpha-specific code
* called before console_init(), so we put this "unregister" code
* here to prevent schizophrenic console behavior later... ;-}
*/
if (alpha_using_srm && srmcons_output) {
unregister_srm_console();
srmcons_output = 0;
}
}
/*
......
......@@ -123,6 +123,10 @@ static char *vidmem = (char *)0xb8000;
static int vidport;
static int lines, cols;
#ifdef CONFIG_MULTIQUAD
static void *xquad_portio = NULL;
#endif
#include "../../../../lib/inflate.c"
static void *malloc(int size)
......
......@@ -178,6 +178,8 @@ if [ "$CONFIG_SMP" != "y" ]; then
if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then
define_bool CONFIG_X86_IO_APIC y
fi
else
bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
fi
if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
......
......@@ -59,6 +59,7 @@ CONFIG_NOHIGHMEM=y
# CONFIG_MATH_EMULATION is not set
# CONFIG_MTRR is not set
CONFIG_SMP=y
# CONFIG_MULTIQUAD is not set
CONFIG_HAVE_DEC_LOCK=y
#
......@@ -603,6 +604,7 @@ CONFIG_AUTOFS4_FS=y
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_TMPFS=y
# CONFIG_RAMFS is not set
......
......@@ -48,7 +48,7 @@ int get_maxlvt(void)
return maxlvt;
}
static void clear_local_APIC(void)
void clear_local_APIC(void)
{
int maxlvt;
unsigned long v;
......@@ -254,6 +254,14 @@ void __init setup_local_APIC (void)
{
unsigned long value, ver, maxlvt;
/* Pound the ESR really hard over the head with a big hammer - mbligh */
if (esr_disable) {
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
apic_write(APIC_ESR, 0);
}
value = apic_read(APIC_LVR);
ver = GET_APIC_VERSION(value);
......@@ -262,8 +270,10 @@ void __init setup_local_APIC (void)
/*
* Double-check wether this APIC is really registered.
* This is meaningless in clustered apic mode, so we skip it.
*/
if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
if (!clustered_apic_mode &&
!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
BUG();
/*
......@@ -272,19 +282,22 @@ void __init setup_local_APIC (void)
* document number 292116). So here it goes...
*/
/*
* Put the APIC into flat delivery mode.
* Must be "all ones" explicitly for 82489DX.
*/
apic_write_around(APIC_DFR, 0xffffffff);
if (!clustered_apic_mode) {
/*
* In clustered apic mode, the firmware does this for us
* Put the APIC into flat delivery mode.
* Must be "all ones" explicitly for 82489DX.
*/
apic_write_around(APIC_DFR, 0xffffffff);
/*
* Set up the logical destination ID.
*/
value = apic_read(APIC_LDR);
value &= ~APIC_LDR_MASK;
value |= (1<<(smp_processor_id()+24));
apic_write_around(APIC_LDR, value);
/*
* Set up the logical destination ID.
*/
value = apic_read(APIC_LDR);
value &= ~APIC_LDR_MASK;
value |= (1<<(smp_processor_id()+24));
apic_write_around(APIC_LDR, value);
}
/*
* Set Task Priority to 'accept all'. We never change this
......@@ -367,7 +380,7 @@ void __init setup_local_APIC (void)
value |= APIC_LVT_LEVEL_TRIGGER;
apic_write_around(APIC_LVT1, value);
if (APIC_INTEGRATED(ver)) { /* !82489DX */
if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */
maxlvt = get_maxlvt();
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
......@@ -383,8 +396,18 @@ void __init setup_local_APIC (void)
apic_write(APIC_ESR, 0);
value = apic_read(APIC_ESR);
printk("ESR value after enabling vector: %08lx\n", value);
} else
printk("No ESR for 82489DX.\n");
} else {
if (esr_disable)
/*
* Something untraceble is creating bad interrupts on
* secondary quads ... for the moment, just leave the
* ESR disabled - we can't do anything useful with the
* errors anyway - mbligh
*/
printk("Leaving ESR disabled.\n");
else
printk("No ESR for 82489DX.\n");
}
if (nmi_watchdog == NMI_LOCAL_APIC)
setup_apic_nmi_watchdog();
......@@ -598,7 +621,7 @@ static int __init detect_init_APIC (void)
}
set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
boot_cpu_id = 0;
boot_cpu_physical_apicid = 0;
if (nmi_watchdog != NMI_NONE)
nmi_watchdog = NMI_LOCAL_APIC;
......@@ -636,8 +659,8 @@ void __init init_apic_mappings(void)
* Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken).
*/
if (boot_cpu_id == -1U)
boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
if (boot_cpu_physical_apicid == -1U)
boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
#ifdef CONFIG_X86_IO_APIC
{
......@@ -1077,9 +1100,9 @@ int __init APIC_init_uniprocessor (void)
/*
* Complain if the BIOS pretends there is one.
*/
if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_id);
boot_cpu_physical_apicid);
return -1;
}
......@@ -1088,7 +1111,7 @@ int __init APIC_init_uniprocessor (void)
connect_bsp_APIC();
phys_cpu_present_map = 1;
apic_write_around(APIC_ID, boot_cpu_id);
apic_write_around(APIC_ID, boot_cpu_physical_apicid);
apic_pm_init2();
......
......@@ -44,11 +44,6 @@ static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
*/
int nr_ioapic_registers[MAX_IO_APICS];
#if CONFIG_SMP
# define TARGET_CPUS cpu_online_map
#else
# define TARGET_CPUS 0x01
#endif
/*
* Rough estimation of how many shared IRQs there are, can
* be changed anytime.
......@@ -603,7 +598,7 @@ void __init setup_IO_APIC_irqs(void)
memset(&entry,0,sizeof(entry));
entry.delivery_mode = dest_LowestPrio;
entry.dest_mode = 1; /* logical delivery */
entry.dest_mode = INT_DELIVERY_MODE;
entry.mask = 0; /* enable IRQ */
entry.dest.logical.logical_dest = TARGET_CPUS;
......@@ -677,7 +672,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
* We use logical delivery to get the timer IRQ
* to the first CPU.
*/
entry.dest_mode = 1; /* logical delivery */
entry.dest_mode = INT_DELIVERY_MODE;
entry.mask = 0; /* unmask IRQ now */
entry.dest.logical.logical_dest = TARGET_CPUS;
entry.delivery_mode = dest_LowestPrio;
......@@ -1016,6 +1011,9 @@ static void __init setup_ioapic_ids_from_mpc (void)
unsigned char old_id;
unsigned long flags;
if (clustered_apic_mode)
/* We don't have a good way to do this yet - hack */
phys_id_present_map = (u_long) 0xf;
/*
* Set the IOAPIC ID to the value stored in the MPC table.
*/
......@@ -1053,8 +1051,12 @@ static void __init setup_ioapic_ids_from_mpc (void)
i);
phys_id_present_map |= 1 << i;
mp_ioapics[apic].mpc_apicid = i;
} else {
printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid);
phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid;
}
/*
* We need to adjust the IRQ routing table
* if the ID changed.
......
......@@ -54,7 +54,7 @@ int pic_mode;
unsigned long mp_lapic_addr;
/* Processor that is doing the boot up */
unsigned int boot_cpu_id = -1U;
unsigned int boot_cpu_physical_apicid = -1U;
/* Internal processor count */
static unsigned int num_processors;
......@@ -180,8 +180,9 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
Dprintk(" Bootup CPU\n");
boot_cpu_id = m->mpc_apicid;
boot_cpu_physical_apicid = m->mpc_apicid;
}
num_processors++;
if (m->mpc_apicid > MAX_APICS) {
......@@ -191,7 +192,12 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
}
ver = m->mpc_apicver;
phys_cpu_present_map |= 1 << m->mpc_apicid;
if (clustered_apic_mode)
/* Crude temporary hack. Assumes processors are sequential */
phys_cpu_present_map |= 1 << (num_processors-1);
else
phys_cpu_present_map |= 1 << m->mpc_apicid;
/*
* Validate version
*/
......@@ -377,6 +383,10 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
}
}
if (clustered_apic_mode && nr_ioapics > 2) {
/* don't initialise IO apics on secondary quads */
nr_ioapics = 2;
}
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
......
......@@ -376,7 +376,7 @@ void machine_restart(char * __unused)
if ((reboot_cpu == -1) ||
(reboot_cpu > (NR_CPUS -1)) ||
!(phys_cpu_present_map & (1<<cpuid)))
reboot_cpu = boot_cpu_id;
reboot_cpu = boot_cpu_physical_apicid;
reboot_smp = 0; /* use this as a flag to only go through this once*/
/* re-run this function on the other CPUs
......
......@@ -2416,7 +2416,12 @@ int get_cpuinfo(char * buffer)
struct cpuinfo_x86 *c = cpu_data;
int i, n;
for (n = 0; n < NR_CPUS; n++, c++) {
/*
* WARNING - nasty evil hack ... if we print > 8, it overflows the
* page buffer and corrupts memory - this needs fixing properly
*/
for (n = 0; n < 8; n++, c++) {
/* for (n = 0; n < NR_CPUS; n++, c++) { */
int fpu_exception;
#ifdef CONFIG_SMP
if (!(cpu_online_map & (1<<n)))
......@@ -2479,7 +2484,7 @@ int get_cpuinfo(char * buffer)
return p - buffer;
}
static unsigned long cpu_initialized __initdata = 0;
unsigned long cpu_initialized __initdata = 0;
/*
* cpu_init() initializes state that is per-CPU. Some data is already
......
......@@ -20,6 +20,7 @@
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/smpboot.h>
/*
* Some notes on x86 processor bugs affecting SMP operation:
......@@ -148,28 +149,12 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
apic_write_around(APIC_ICR, cfg);
}
static inline void send_IPI_allbutself(int vector)
{
/*
* if there are no other CPUs in the system then
* we get an APIC send error if we try to broadcast.
* thus we have to avoid sending IPIs in this case.
*/
if (smp_num_cpus > 1)
__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
}
static inline void send_IPI_all(int vector)
{
__send_IPI_shortcut(APIC_DEST_ALLINC, vector);
}
void send_IPI_self(int vector)
{
__send_IPI_shortcut(APIC_DEST_SELF, vector);
}
static inline void send_IPI_mask(int mask, int vector)
static inline void send_IPI_mask_bitmask(int mask, int vector)
{
unsigned long cfg;
unsigned long flags;
......@@ -177,29 +162,122 @@ static inline void send_IPI_mask(int mask, int vector)
__save_flags(flags);
__cli();
/*
* Wait for idle.
*/
apic_wait_icr_idle();
/*
* prepare target chip field
*/
cfg = __prepare_ICR2(mask);
apic_write_around(APIC_ICR2, cfg);
/*
* program the ICR
*/
cfg = __prepare_ICR(0, vector);
/*
* Send the IPI. The write to APIC_ICR fires this off.
*/
apic_write_around(APIC_ICR, cfg);
__restore_flags(flags);
}
static inline void send_IPI_mask_sequence(int mask, int vector)
{
unsigned long cfg, flags;
unsigned int query_cpu, query_mask;
/*
* Hack. The clustered APIC addressing mode doesn't allow us to send
* to an arbitrary mask, so I do a unicasts to each CPU instead. This
* should be modified to do 1 message per cluster ID - mbligh
*/
__save_flags(flags);
__cli();
for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
query_mask = 1 << query_cpu;
if (query_mask & mask) {
/*
* Wait for idle.
*/
apic_wait_icr_idle();
/*
* prepare target chip field
*/
cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
apic_write_around(APIC_ICR2, cfg);
/*
* program the ICR
*/
cfg = __prepare_ICR(0, vector);
/*
* Send the IPI. The write to APIC_ICR fires this off.
*/
apic_write_around(APIC_ICR, cfg);
}
}
__restore_flags(flags);
}
static inline void send_IPI_mask(int mask, int vector)
{
if (clustered_apic_mode)
send_IPI_mask_sequence(mask, vector);
else
send_IPI_mask_bitmask(mask, vector);
}
static inline void send_IPI_allbutself(int vector)
{
/*
* if there are no other CPUs in the system then
* we get an APIC send error if we try to broadcast.
* thus we have to avoid sending IPIs in this case.
*/
if (!(smp_num_cpus > 1))
return;
if (clustered_apic_mode) {
// Pointless. Use send_IPI_mask to do this instead
int cpu;
if (smp_num_cpus > 1) {
for (cpu = 0; cpu < smp_num_cpus; ++cpu) {
if (cpu != smp_processor_id())
send_IPI_mask(1 << cpu, vector);
}
}
} else {
__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
return;
}
}
static inline void send_IPI_all(int vector)
{
if (clustered_apic_mode) {
// Pointless. Use send_IPI_mask to do this instead
int cpu;
for (cpu = 0; cpu < smp_num_cpus; ++cpu) {
send_IPI_mask(1 << cpu, vector);
}
} else {
__send_IPI_shortcut(APIC_DEST_ALLINC, vector);
}
}
/*
* Smarter SMP flushing macros.
* c/o Linus Torvalds.
......
This diff is collapsed.
......@@ -36,7 +36,9 @@
ENTRY(trampoline_data)
r_base = .
#ifdef CONFIG_MULTIQUAD
wbinvd
#endif /* CONFIG_MULTIQUAD */
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
......
# $Id: Config.in,v 1.66 2001/05/07 21:00:43 dwmw2 Exp $
# $Id: Config.in,v 1.70 2001/08/11 16:13:38 dwmw2 Exp $
mainmenu_option next_comment
comment 'Memory Technology Devices (MTD)'
......@@ -14,6 +14,7 @@ if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then
dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
comment 'User Modules And Translation Layers'
dep_tristate ' Direct char device access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
......
......@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now inherited from the
# parent makes..
#
# $Id: Makefile,v 1.60 2001/05/31 20:43:18 dwmw2 Exp $
# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
obj-y += chips/chipslink.o maps/mapslink.o \
......@@ -19,7 +19,7 @@ obj- :=
O_TARGET := mtdlink.o
export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o
export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
list-multi := nftl.o
mod-subdirs :=
......@@ -47,6 +47,7 @@ obj-$(CONFIG_MTD) += mtdcore.o
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
......
/*======================================================================
drivers/mtd/afs.c: ARM Flash Layout/Partitioning
Copyright (C) 2000 ARM Limited
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 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This is access code for flashes using ARM's flash partitioning
standards.
$Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $
======================================================================*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
struct footer_struct {
u32 image_info_base; /* Address of first word of ImageFooter */
u32 image_start; /* Start of area reserved by this footer */
u32 signature; /* 'Magic' number proves it's a footer */
u32 type; /* Area type: ARM Image, SIB, customer */
u32 checksum; /* Just this structure */
};
struct image_info_struct {
u32 bootFlags; /* Boot flags, compression etc. */
u32 imageNumber; /* Unique number, selects for boot etc. */
u32 loadAddress; /* Address program should be loaded to */
u32 length; /* Actual size of image */
u32 address; /* Image is executed from here */
char name[16]; /* Null terminated */
u32 headerBase; /* Flash Address of any stripped header */
u32 header_length; /* Length of header in memory */
u32 headerType; /* AIF, RLF, s-record etc. */
u32 checksum; /* Image checksum (inc. this struct) */
};
static int
afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
u_int off, u_int mask)
{
struct footer_struct fs;
u_int ptr = off + mtd->erasesize - sizeof(fs);
size_t sz;
int ret;
ret = mtd->read(mtd, ptr, sizeof(fs), &sz, (u_char *) &fs);
if (ret >= 0 && sz != sizeof(fs))
ret = -EINVAL;
if (ret < 0) {
printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
ptr, ret);
return ret;
}
/*
* Does it contain the magic number?
*/
if (fs.signature != 0xa0ffff9f)
ret = 1;
*iis_start = fs.image_info_base & mask;
*img_start = fs.image_start & mask;
/*
* Check the image info base. This can not
* be located after the footer structure.
*/
if (*iis_start >= ptr)
ret = 1;
/*
* Check the start of this image. The image
* data can not be located after this block.
*/
if (*img_start > off)
ret = 1;
return ret;
}
static int
afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
{
size_t sz;
int ret;
memset(iis, 0, sizeof(*iis));
ret = mtd->read(mtd, ptr, sizeof(*iis), &sz, (u_char *) iis);
if (ret >= 0 && sz != sizeof(*iis))
ret = -EINVAL;
if (ret < 0)
printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
ptr, ret);
return ret;
}
int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts)
{
struct mtd_partition *parts;
u_int mask, off, idx, sz;
int ret = 0;
char *str;
/*
* This is the address mask; we use this to mask off out of
* range address bits.
*/
mask = mtd->size - 1;
/*
* First, calculate the size of the array we need for the
* partition information. We include in this the size of
* the strings.
*/
for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
struct image_info_struct iis;
u_int iis_ptr, img_ptr;
ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
if (ret < 0)
break;
if (ret == 1)
continue;
ret = afs_read_iis(mtd, &iis, iis_ptr);
if (ret < 0)
break;
sz += sizeof(struct mtd_partition);
sz += strlen(iis.name) + 1;
idx += 1;
}
if (!sz)
return ret;
parts = kmalloc(sz, GFP_KERNEL);
if (!parts)
return -ENOMEM;
str = (char *)(parts + idx);
/*
* Identify the partitions
*/
for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
struct image_info_struct iis;
u_int iis_ptr, img_ptr, size;
/* Read the footer. */
ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
if (ret < 0)
break;
if (ret == 1)
continue;
/* Read the image info block */
ret = afs_read_iis(mtd, &iis, iis_ptr);
if (ret < 0)
break;
strcpy(str, iis.name);
size = mtd->erasesize + off - img_ptr;
/*
* In order to support JFFS2 partitions on this layout,
* we must lie to MTD about the real size of JFFS2
* partitions; this ensures that the AFS flash footer
* won't be erased by JFFS2. Please ensure that your
* JFFS2 partitions are given image numbers between
* 1000 and 2000 inclusive.
*/
if (iis.imageNumber >= 1000 && iis.imageNumber < 2000)
size -= mtd->erasesize;
parts[idx].name = str;
parts[idx].size = size;
parts[idx].offset = img_ptr;
parts[idx].mask_flags = 0;
printk(" mtd%d: at 0x%08x, %5dKB, %8u, %s\n",
idx, img_ptr, parts[idx].size / 1024,
iis.imageNumber, str);
idx += 1;
str = str + strlen(iis.name) + 1;
}
if (!idx) {
kfree(parts);
parts = NULL;
}
*pparts = parts;
return idx ? idx : ret;
}
EXPORT_SYMBOL(parse_afs_partitions);
MODULE_AUTHOR("ARM Ltd");
MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
MODULE_LICENSE("GPL");
......@@ -3,7 +3,7 @@
*
* Copyright 2001 Compaq Computer Corporation.
*
* $Id: bootldr.c,v 1.4 2001/06/02 18:24:27 nico Exp $
* $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
......@@ -24,6 +24,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/setup.h>
#include <linux/bootmem.h>
#define FLASH_PARTITION_NAMELEN 32
enum LFR_FLAGS {
......@@ -33,6 +35,9 @@ enum LFR_FLAGS {
LFR_EXPAND = 8 /* expand partition size to fit rest of flash */
};
// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
// for now
#define MAX_NUM_PARTITIONS 8
typedef struct FlashRegion {
char name[FLASH_PARTITION_NAMELEN];
unsigned long base;
......@@ -43,7 +48,7 @@ typedef struct FlashRegion {
typedef struct BootldrFlashPartitionTable {
int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
int npartitions;
struct FlashRegion partition[0];
struct FlashRegion partition[8];
} BootldrFlashPartitionTable;
#define BOOTLDR_MAGIC 0x646c7462 /* btld: marks a valid bootldr image */
......@@ -56,6 +61,10 @@ typedef struct BootldrFlashPartitionTable {
#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
static struct BootldrFlashPartitionTable Table;
static struct BootldrFlashPartitionTable *partition_table = NULL;
int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
{
struct mtd_partition *parts;
......@@ -65,9 +74,10 @@ int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **ppa
long bootmagic = 0;
long bootcap = 0;
int namelen = 0;
struct BootldrFlashPartitionTable *partition_table = NULL;
char *names;
#if 0
/* verify bootldr magic */
ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
if (ret)
......@@ -87,22 +97,33 @@ int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **ppa
partition_table_offset = master->size - master->erasesize;
printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
/* Read the partition table */
partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!partition_table)
return -ENOMEM;
ret = master->read(master, partition_table_offset,
PAGE_SIZE, &retlen, (void *)partition_table);
if (ret)
goto out;
goto out;
#endif
if (!partition_table)
return -ENOMEM;
printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
/* check for partition table magic number */
if (partition_table->magic != BOOTLDR_PARTITION_MAGIC)
goto out;
npartitions = partition_table->npartitions;
npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
MAX_NUM_PARTITIONS:partition_table->npartitions;
printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
......@@ -118,6 +139,9 @@ int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **ppa
names = (char *)&parts[npartitions];
memset(parts, 0, sizeof(*parts)*npartitions + namelen);
// from here we use the partition table
for (i = 0; i < npartitions; i++) {
struct FlashRegion *partition = &partition_table->partition[i];
const char *name = partition->name;
......@@ -141,9 +165,50 @@ int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **ppa
*pparts = parts;
out:
#if 0
if (partition_table)
kfree(partition_table);
#endif
return ret;
}
static int __init parse_tag_ptable(const struct tag *tag)
{
char buf[128];
int i;
int j;
partition_table = &Table;
#ifdef CONFIG_DEBUG_LL
sprintf(buf,"ptable: magic = = 0x%lx npartitions= %d \n",
tag->u.ptable.magic,tag->u.ptable.npartitions);
printascii(buf);
for (i=0; i<tag->u.ptable.npartitions; i++){
sprintf(buf,"ptable: partition name = %s base= 0x%lx size= 0x%lx flags= 0x%lx\n",
(char *) (&tag->u.ptable.partition[i].name[0]),
tag->u.ptable.partition[i].base,
tag->u.ptable.partition[i].size,
tag->u.ptable.partition[i].flags);
printascii(buf);
}
#endif
memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
return 0;
}
__tagtable(ATAG_PTABLE, parse_tag_ptable);
EXPORT_SYMBOL(parse_bootldr_partitions);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Compaq Computer Corporation");
MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
# drivers/mtd/chips/Config.in
# $Id: Config.in,v 1.4 2001/05/14 09:48:12 dwmw2 Exp $
# $Id: Config.in,v 1.12 2001/09/23 15:35:21 dwmw2 Exp $
mainmenu_option next_comment
comment 'RAM/ROM/Flash chip drivers'
dep_tristate ' Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_CFI" = "m" ]; then
bool ' CFI Virtual erase regions (EXPERIMENTAL)' CONFIG_MTD_CFI_VIRTUAL_ER
bool ' CFI Advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS
dep_tristate ' Detect flash chips by Common Flash Interface (CFI) probe' CONFIG_MTD_CFI $CONFIG_MTD
#dep_tristate ' Detect non-CFI Intel-compatible flash chips' CONFIG_MTD_INTELPROBE $CONFIG_MTD
dep_tristate ' Detect non-CFI AMD/JEDEC-compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD
if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_INTELPROBE" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
define_bool CONFIG_MTD_GEN_PROBE y
else
if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_INTELPROBE" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
define_bool CONFIG_MTD_GEN_PROBE m
else
define_bool CONFIG_MTD_GEN_PROBE n
fi
fi
if [ "$CONFIG_MTD_GEN_PROBE" = "y" -o "$CONFIG_MTD_GEN_PROBE" = "m" ]; then
bool ' Flash chip driver advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS
if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then
choice 'Flash cmd/query data swapping' \
"NO CONFIG_MTD_CFI_NOSWAP \
BIG_ENDIAN_BYTE CONFIG_MTD_CFI_BE_BYTE_SWAP \
LITTLE_ENDIAN_BYTE CONFIG_MTD_CFI_LE_BYTE_SWAP \
LART_ENDIAN_BYTE CONFIG_MTD_CFI_LART_BIT_SWAP" NO
LITTLE_ENDIAN_BYTE CONFIG_MTD_CFI_LE_BYTE_SWAP" NO
bool ' Specific CFI Flash geometry selection' CONFIG_MTD_CFI_GEOMETRY
if [ "$CONFIG_MTD_CFI_GEOMETRY" = "y" ]; then
bool ' Support 8-bit buswidth' CONFIG_MTD_CFI_B1
......@@ -31,12 +41,17 @@ if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_CFI" = "m" ]; then
fi
fi
fi
dep_tristate ' CFI support for Intel/Sharp Basic/Extended Commands' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI
dep_tristate ' CFI support for AMD/Fujitsu Standard Commands' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_CFI
dep_tristate ' AMD compatible flash chip support (non-CFI)' CONFIG_MTD_AMDSTD $CONFIG_MTD
dep_tristate ' pre-CFI Sharp chip support' CONFIG_MTD_SHARP $CONFIG_MTD
dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
dep_tristate ' JEDEC device support' CONFIG_MTD_JEDEC $CONFIG_MTD
dep_tristate ' Support for absent chips in bus mapping' CONFIG_MTD_ABSENT $CONFIG_MTD
bool ' Older (theoretically obsoleted now) drivers for non-CFI chips' CONFIG_MTD_OBSOLETE_CHIPS
dep_tristate ' AMD compatible flash chip support (non-CFI)' CONFIG_MTD_AMDSTD $CONFIG_MTD $CONFIG_MTD_OBSOLETE_CHIPS
dep_tristate ' pre-CFI Sharp chip support' CONFIG_MTD_SHARP $CONFIG_MTD $CONFIG_MTD_OBSOLETE_CHIPS
dep_tristate ' JEDEC device support' CONFIG_MTD_JEDEC $CONFIG_MTD $CONFIG_MTD_OBSOLETE_CHIPS
endmenu
#
# linux/drivers/chips/Makefile
#
# $Id: Makefile,v 1.4 2001/06/09 19:57:57 dwmw2 Exp $
# $Id: Makefile,v 1.6 2001/09/02 18:57:01 dwmw2 Exp $
O_TARGET := chipslink.o
......@@ -16,12 +16,16 @@ export-objs := chipreg.o
obj-$(CONFIG_MTD) += chipreg.o
obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o cfi_jedec.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o
obj-$(CONFIG_MTD_JEDEC) += jedec.o
obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o
obj-$(CONFIG_MTD_RAM) += map_ram.o
obj-$(CONFIG_MTD_ROM) += map_rom.o
obj-$(CONFIG_MTD_SHARP) += sharp.o
obj-$(CONFIG_MTD_ABSENT) += map_absent.o
include $(TOPDIR)/Rules.make
......@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.8 2001/06/02 14:47:16 dwmw2 Exp $
* $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
......@@ -33,6 +33,8 @@
/* Addresses */
#define ADDR_MANUFACTURER 0x0000
#define ADDR_DEVICE_ID 0x0001
#define ADDR_SECTOR_LOCK 0x0002
#define ADDR_HANDSHAKE 0x0003
#define ADDR_UNLOCK_1 0x0555
#define ADDR_UNLOCK_2 0x02AA
......@@ -46,6 +48,8 @@
#define CMD_SECTOR_ERASE_UNLOCK_DATA 0x0080
#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x0030
#define CMD_UNLOCK_SECTOR 0x0060
/* Manufacturers */
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_FUJITSU 0x0004
......@@ -60,6 +64,9 @@
#define AM29LV800BT 0x22DA
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
#define AM29BDS643D 0x227E
/* Fujitsu */
#define MBM29LV160TE 0x22C4
......@@ -202,6 +209,92 @@ static inline int flash_is_busy(struct map_info *map, unsigned long addr,
(wide_read(map, addr) & D6_MASK));
}
static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
int unlock)
{
/* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
int SLA = unlock ?
(sect_addr | (0x40 * map->buswidth)) :
(sect_addr & ~(0x40 * map->buswidth)) ;
__u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
}
static inline int is_sector_locked(struct map_info *map,
unsigned long sect_addr)
{
int status;
wide_write(map, CMD_RESET_DATA, 0);
send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
/* status is 0x0000 for unlocked and 0x0001 for locked */
status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
wide_write(map, CMD_RESET_DATA, 0);
return status;
}
static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
int is_unlock)
{
struct map_info *map;
struct mtd_erase_region_info *merip;
int eraseoffset, erasesize, eraseblocks;
int i;
int retval = 0;
int lock_status;
map = mtd->priv;
/* Pass the whole chip through sector by sector and check for each
sector if the sector and the given interval overlap */
for(i = 0; i < mtd->numeraseregions; i++) {
merip = &mtd->eraseregions[i];
eraseoffset = merip->offset;
erasesize = merip->erasesize;
eraseblocks = merip->numblocks;
if (ofs > eraseoffset + erasesize)
continue;
while (eraseblocks > 0) {
if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
unlock_sector(map, eraseoffset, is_unlock);
lock_status = is_sector_locked(map, eraseoffset);
if (is_unlock && lock_status) {
printk("Cannot unlock sector at address %x length %xx\n",
eraseoffset, merip->erasesize);
retval = -1;
} else if (!is_unlock && !lock_status) {
printk("Cannot lock sector at address %x length %x\n",
eraseoffset, merip->erasesize);
retval = -1;
}
}
eraseoffset += erasesize;
eraseblocks --;
}
}
return retval;
}
static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
return amd_flash_do_unlock(mtd, ofs, len, 1);
}
static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
return amd_flash_do_unlock(mtd, ofs, len, 0);
}
/*
......@@ -213,7 +306,8 @@ static int probe_new_chip(struct mtd_info *mtd, __u32 base,
struct amd_flash_private *private,
const struct amd_flash_info *table, int table_size)
{
__u32 mfr_id, dev_id;
__u32 mfr_id;
__u32 dev_id;
struct map_info *map = mtd->priv;
struct amd_flash_private temp;
int i;
......@@ -231,8 +325,8 @@ static int probe_new_chip(struct mtd_info *mtd, __u32 base,
if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
((dev_id >> 16) == (dev_id & 0xffff))) {
mfr_id = mfr_id & 0xffff;
dev_id = dev_id & 0xffff;
mfr_id &= 0xffff;
dev_id &= 0xffff;
} else {
temp.interleave = 1;
}
......@@ -248,15 +342,24 @@ static int probe_new_chip(struct mtd_info *mtd, __u32 base,
* autoselect mode now.
*/
for (j = 0; j < private->numchips; j++) {
if ((wide_read(map, chips[j].start +
(map->buswidth *
ADDR_MANUFACTURER))
== mfr_id)
&&
(wide_read(map, chips[j].start +
(map->buswidth *
ADDR_DEVICE_ID))
== dev_id)) {
__u32 mfr_id_other;
__u32 dev_id_other;
mfr_id_other =
wide_read(map, chips[j].start +
(map->buswidth *
ADDR_MANUFACTURER
));
dev_id_other =
wide_read(map, chips[j].start +
(map->buswidth *
ADDR_DEVICE_ID));
if (temp.interleave == 2) {
mfr_id_other &= 0xffff;
dev_id_other &= 0xffff;
}
if ((mfr_id_other == mfr_id) &&
(dev_id_other == dev_id)) {
/* Exit autoselect mode. */
send_cmd(map, base,
......@@ -488,6 +591,28 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
{ offset: 0x008000, erasesize: 0x08000, numblocks: 1 },
{ offset: 0x010000, erasesize: 0x10000, numblocks: 31 }
}
}, {
mfr_id: MANUFACTURER_AMD,
dev_id: AM29BDS323D,
name: "AMD AM29BDS323D",
size: 0x00400000,
numeraseregions: 3,
regions: {
{ offset: 0x000000, erasesize: 0x10000, numblocks: 48 },
{ offset: 0x300000, erasesize: 0x10000, numblocks: 15 },
{ offset: 0x3f0000, erasesize: 0x02000, numblocks: 8 },
}
}, {
mfr_id: MANUFACTURER_AMD,
dev_id: AM29BDS643D,
name: "AMD AM29BDS643D",
size: 0x00800000,
numeraseregions: 3,
regions: {
{ offset: 0x000000, erasesize: 0x10000, numblocks: 96 },
{ offset: 0x600000, erasesize: 0x10000, numblocks: 31 },
{ offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 },
}
}
};
......@@ -597,6 +722,8 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
mtd->sync = amd_flash_sync;
mtd->suspend = amd_flash_suspend;
mtd->resume = amd_flash_resume;
mtd->lock = amd_flash_lock;
mtd->unlock = amd_flash_unlock;
private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
temp.numchips), GFP_KERNEL);
......@@ -761,8 +888,7 @@ static int write_one_word(struct map_info *map, struct flchip *chip,
wide_write(map, datum, adr);
times_left = 500000;
while (times_left-- && flash_is_busy(map, chip->start,
private->interleave)) {
while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
if (current->need_resched) {
spin_unlock_bh(chip->mutex);
schedule();
......@@ -964,7 +1090,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip,
schedule_timeout(HZ);
spin_lock_bh(chip->mutex);
while (flash_is_busy(map, chip->start, private->interleave)) {
while (flash_is_busy(map, adr, private->interleave)) {
if (chip->state != FL_ERASING) {
/* Someone's suspended the erase. Sleep */
......@@ -1250,3 +1376,7 @@ void __exit amd_flash_exit(void)
module_init(amd_flash_init);
module_exit(amd_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
* This code is GPL
*
* $Id: cfi_cmdset_0002.c,v 1.48 2001/06/03 01:32:57 nico Exp $
* $Id: cfi_cmdset_0002.c,v 1.51 2001/10/02 15:05:12 dwmw2 Exp $
*
*/
......@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
......@@ -37,93 +38,107 @@ static void cfi_amdstd_resume (struct mtd_info *);
static void cfi_amdstd_destroy(struct mtd_info *);
void cfi_cmdset_0002(struct map_info *, int, unsigned long);
struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
static struct mtd_info *cfi_amdstd_setup (struct map_info *);
static struct mtd_chip_driver cfi_amdstd_chipdrv = {
probe: cfi_amdstd_setup,
probe: NULL, /* Not usable directly */
destroy: cfi_amdstd_destroy,
name: "cfi_cmdset_0002",
module: THIS_MODULE
};
void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
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;
// struct cfi_pri_intelext *extp;
__u32 base = cfi->chips[0].start;
if (cfi->cfi_mode==0){
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
if (cfi->cfi_mode==1){
__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
cfi_send_gen_cmd(0x98, 0x55, 0, map, cfi, cfi->device_type, NULL);
major = cfi_read_query(map, (adr+3)*ofs_factor);
minor = cfi_read_query(map, (adr+4)*ofs_factor);
printk(" Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
major, minor, adr);
cfi_send_gen_cmd(0xf0, 0x55, 0, 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);
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(" 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);
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. */
/* 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
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, 0, map, cfi, cfi->device_type, NULL);
bootloc = cfi_read_query(map, (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);
for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
int j = (cfi->cfiq->NumEraseRegions-1)-i;
__u32 swap;
swap = cfi->cfiq->EraseRegionInfo[i];
cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
cfi->cfiq->EraseRegionInfo[j] = swap;
{
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);
for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
int j = (cfi->cfiq->NumEraseRegions-1)-i;
__u32 swap;
swap = cfi->cfiq->EraseRegionInfo[i];
cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
cfi->cfiq->EraseRegionInfo[j] = swap;
}
}
}
}
/* If there was an old setup function, decrease its use count */
if (map->fldrv)
if(map->fldrv->module)
__MOD_DEC_USE_COUNT(map->fldrv->module);
if (cfi->cmdset_priv)
kfree(cfi->cmdset_priv);
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 cfi_cmdset_0002 device type %d\n", cfi->device_type);
return NULL;
}
} /* CFI mode */
for (i=0; i< cfi->numchips; i++) {
for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
}
}
map->fldrv = &cfi_amdstd_chipdrv;
MOD_INC_USE_COUNT;
map->fldrv = &cfi_amdstd_chipdrv;
MOD_INC_USE_COUNT;
cfi_send_gen_cmd(0xf0, 0x55, 0, map, cfi, cfi->device_type, NULL);
return;
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)
......@@ -913,20 +928,15 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd)
kfree(cfi);
}
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define cfi_amdstd_init init_module
#define cfi_amdstd_exit cleanup_module
#endif
static char im_name[]="cfi_cmdset_0002";
mod_init_t cfi_amdstd_init(void)
int __init cfi_amdstd_init(void)
{
inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
return 0;
}
mod_exit_t cfi_amdstd_exit(void)
static void __exit cfi_amdstd_exit(void)
{
inter_module_unregister(im_name);
}
......@@ -934,3 +944,6 @@ mod_exit_t cfi_amdstd_exit(void)
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");
This diff is collapsed.
/*
* $Id: chipreg.c,v 1.8 2001/06/09 19:58:19 dwmw2 Exp $
* $Id: chipreg.c,v 1.12 2001/10/02 15:29:53 dwmw2 Exp $
*
* Registration for chip drivers
*
......@@ -90,3 +90,7 @@ struct mtd_info *do_map_probe(char *name, struct map_info *map)
EXPORT_SYMBOL(register_mtd_chip_driver);
EXPORT_SYMBOL(unregister_mtd_chip_driver);
EXPORT_SYMBOL(do_map_probe);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Core routines for registering and invoking MTD chip drivers");
/*
* Routines common to all CFI-type probes.
* (C) 2001, 2001 Red Hat, Inc.
* GPL'd
* $Id: gen_probe.c,v 1.5 2001/10/02 15:05:12 dwmw2 Exp $
*/
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/gen_probe.h>
static struct mtd_info *check_cmd_set(struct map_info *, int);
static struct cfi_private *genprobe_ident_chips(struct map_info *map,
struct chip_probe *cp);
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi);
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
{
struct mtd_info *mtd = NULL;
struct cfi_private *cfi;
/* First probe the map to see if we have CFI stuff there. */
cfi = genprobe_ident_chips(map, cp);
if (!cfi)
return NULL;
map->fldrv_priv = cfi;
/* OK we liked it. Now find a driver for the command set it talks */
mtd = check_cmd_set(map, 1); /* First the primary cmdset */
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */
if (mtd)
return mtd;
printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n");
kfree(cfi->cfiq);
kfree(cfi);
map->fldrv_priv = NULL;
return NULL;
}
EXPORT_SYMBOL(mtd_do_chip_probe);
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;
memset(&cfi, 0, sizeof(cfi));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
if (!genprobe_new_chip(map, cp, &cfi)) {
/* The probe didn't like it */
printk(KERN_WARNING "%s: Found no %s device at location zero\n",
cp->name, map->name);
return NULL;
}
#if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD
probe routines won't ever return a broken CFI structure anyway,
because they make them up themselves.
*/
if (cfi.cfiq->NumEraseRegions == 0) {
printk(KERN_WARNING "Number of erase regions is zero\n");
kfree(cfi.cfiq);
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:
cfi.chipshift++;
break;
#endif
#ifdef CFIDEV_INTERLEAVE_4
case 4:
cfi.chipshift+=2;
break;
#endif
default:
BUG();
}
cfi.numchips = 1;
/*
* 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.
*/
for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
base += (1<<cfi.chipshift))
cp->probe_chip(map, base, &chip[0], &cfi);
/*
* Now allocate the space for the structures we need to return to
* our caller, and copy the appropriate data into them.
*/
retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
if (!retcfi) {
printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
kfree(cfi.cfiq);
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;
}
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 */
default:
printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
return 0;
}
return 0;
}
typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
extern cfi_cmdset_fn_t cfi_cmdset_0001;
extern cfi_cmdset_fn_t cfi_cmdset_0002;
static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
#if defined(CONFIG_MODULES) && defined(HAVE_INTER_MODULE)
char probename[32];
cfi_cmdset_fn_t *probe_function;
sprintf(probename, "cfi_cmdset_%4.4X", type);
probe_function = inter_module_get_request(probename, probename);
if (probe_function) {
struct mtd_info *mtd;
mtd = (*probe_function)(map, primary);
/* If it was happy, it'll have increased its own use count */
inter_module_put(probename);
return mtd;
}
#endif
printk(KERN_NOTICE "Support for command set %04X not present\n",
type);
return NULL;
}
static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
__u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
if (type == P_ID_NONE || type == P_ID_RESERVED)
return NULL;
switch(type){
/* Urgh. Ifdefs. The version with weak symbols was
* _much_ nicer. Shame it didn't seem to work on
* anything but x86, really.
* But we can't rely in inter_module_get() because
* that'd mean we depend on link order.
*/
#ifdef CONFIG_MTD_CFI_INTELEXT
case 0x0001:
case 0x0003:
return cfi_cmdset_0001(map, primary);
#endif
#ifdef CONFIG_MTD_CFI_AMDSTD
case 0x0002:
return cfi_cmdset_0002(map, primary);
#endif
}
return cfi_cmdset_unknown(map, primary);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Helper routines for flash chip probe code");
......@@ -11,17 +11,17 @@
* not going to guess how to send commands to them, plus I expect they will
* all speak CFI..
*
* $Id: jedec.c,v 1.8 2001/06/09 23:56:57 dwmw2 Exp $
* $Id: jedec.c,v 1.11 2001/10/02 15:05:12 dwmw2 Exp $
*/
#include <linux/mtd/jedec.h>
struct mtd_info *jedec_probe(struct map_info *);
int jedec_probe8(struct map_info *map,unsigned long base,
static struct mtd_info *jedec_probe(struct map_info *);
static int jedec_probe8(struct map_info *map,unsigned long base,
struct jedec_private *priv);
int jedec_probe16(struct map_info *map,unsigned long base,
static int jedec_probe16(struct map_info *map,unsigned long base,
struct jedec_private *priv);
int jedec_probe32(struct map_info *map,unsigned long base,
static int jedec_probe32(struct map_info *map,unsigned long base,
struct jedec_private *priv);
static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
unsigned long len);
......@@ -48,7 +48,7 @@ static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
struct mtd_info *jedec_probe(struct map_info *map);
static struct mtd_info *jedec_probe(struct map_info *map);
......@@ -59,23 +59,31 @@ static struct mtd_chip_driver jedec_chipdrv = {
};
/* Probe entry point */
struct jedec_private priv;
struct mtd_info __MTD;
struct mtd_info *jedec_probe(struct map_info *map)
static struct mtd_info *jedec_probe(struct map_info *map)
{
struct mtd_info *MTD = &__MTD;
struct mtd_info *MTD;
struct jedec_private *priv;
unsigned long Base;
unsigned long SectorSize;
unsigned count;
unsigned I,Uniq;
char Part[200];
memset(&priv,0,sizeof(priv));
MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
if (!MTD)
return NULL;
memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private));
priv = (struct jedec_private *)&MTD[1];
my_bank_size = map->size;
if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
{
printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
kfree(MTD);
return 0;
}
......@@ -86,33 +94,35 @@ struct mtd_info *jedec_probe(struct map_info *map)
map->buswidth = 1;
if (map->buswidth == 1){
if (jedec_probe8(map,Base,&priv) == 0) {
if (jedec_probe8(map,Base,priv) == 0) {
printk("did recognize jedec chip\n");
kfree(MTD);
return 0;
}
}
if (map->buswidth == 2)
jedec_probe16(map,Base,&priv);
jedec_probe16(map,Base,priv);
if (map->buswidth == 4)
jedec_probe32(map,Base,&priv);
jedec_probe32(map,Base,priv);
}
// Get the biggest sector size
SectorSize = 0;
for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
{
// printk("priv.chips[%d].jedec is %x\n",I,priv.chips[I].jedec);
// printk("priv.chips[%d].sectorsize is %lx\n",I,priv.chips[I].sectorsize);
if (priv.chips[I].sectorsize > SectorSize)
SectorSize = priv.chips[I].sectorsize;
// printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
// printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
if (priv->chips[I].sectorsize > SectorSize)
SectorSize = priv->chips[I].sectorsize;
}
// Quickly ensure that the other sector sizes are factors of the largest
for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
{
if ((SectorSize/priv.chips[I].sectorsize)*priv.chips[I].sectorsize != SectorSize)
if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
{
printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
kfree(MTD);
return 0;
}
}
......@@ -124,21 +134,22 @@ struct mtd_info *jedec_probe(struct map_info *map)
Part[sizeof(Part)-11] = 0;
strcat(Part," ");
Uniq = 0;
for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
{
const struct JEDECTable *JEDEC;
if (priv.chips[I+1].jedec == priv.chips[I].jedec)
if (priv->chips[I+1].jedec == priv->chips[I].jedec)
{
count++;
continue;
}
// Locate the chip in the jedec table
JEDEC = jedec_idtoinf(priv.chips[I].jedec >> 8,priv.chips[I].jedec);
JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
if (JEDEC == 0)
{
printk("mtd: Internal Error, JEDEC not set\n");
kfree(MTD);
return 0;
}
......@@ -159,37 +170,39 @@ struct mtd_info *jedec_probe(struct map_info *map)
are empty banks. Note, the last bank does not count here, only the
first banks are important. Holes on non-bank boundaries can not exist
due to the way the detection algorithm works. */
if (priv.size < my_bank_size)
my_bank_size = priv.size;
priv.is_banked = 0;
//printk("priv.size is %x, my_bank_size is %x\n",priv.size,my_bank_size);
//printk("priv.bank_fill[0] is %x\n",priv.bank_fill[0]);
if (!priv.size) {
printk("priv.size is zero\n");
if (priv->size < my_bank_size)
my_bank_size = priv->size;
priv->is_banked = 0;
//printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
//printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
if (!priv->size) {
printk("priv->size is zero\n");
kfree(MTD);
return 0;
}
if (priv.size/my_bank_size) {
if (priv.size/my_bank_size == 1) {
priv.size = my_bank_size;
if (priv->size/my_bank_size) {
if (priv->size/my_bank_size == 1) {
priv->size = my_bank_size;
}
else {
for (I = 0; I != priv.size/my_bank_size - 1; I++)
for (I = 0; I != priv->size/my_bank_size - 1; I++)
{
if (priv.bank_fill[I] != my_bank_size)
priv.is_banked = 1;
if (priv->bank_fill[I] != my_bank_size)
priv->is_banked = 1;
/* This even could be eliminated, but new de-optimized read/write
functions have to be written */
printk("priv.bank_fill[%d] is %lx, priv.bank_fill[0] is %lx\n",I,priv.bank_fill[I],priv.bank_fill[0]);
if (priv.bank_fill[I] != priv.bank_fill[0])
printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
if (priv->bank_fill[I] != priv->bank_fill[0])
{
printk("mtd: Failed. Cannot handle unsymetric banking\n");
printk("mtd: Failed. Cannot handle unsymmetric banking\n");
kfree(MTD);
return 0;
}
}
}
}
if (priv.is_banked == 1)
if (priv->is_banked == 1)
strcat(Part,", banked");
// printk("Part: '%s'\n",Part);
......@@ -202,18 +215,18 @@ struct mtd_info *jedec_probe(struct map_info *map)
MTD->flags = MTD_CAP_NORFLASH;
MTD->erasesize = SectorSize*(map->buswidth);
// printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
MTD->size = priv.size;
MTD->size = priv->size;
// printk("MTD->size is %x\n",(unsigned int)MTD->size);
//MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
MTD->erase = flash_erase;
if (priv.is_banked == 1)
if (priv->is_banked == 1)
MTD->read = jedec_read_banked;
else
MTD->read = jedec_read;
MTD->write = flash_write;
MTD->sync = jedec_sync;
MTD->priv = map;
map->fldrv_priv = &priv;
map->fldrv_priv = priv;
map->fldrv = &jedec_chipdrv;
MOD_INC_USE_COUNT;
return MTD;
......@@ -334,7 +347,7 @@ const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
}
// Look for flash using an 8 bit bus interface
int jedec_probe8(struct map_info *map,unsigned long base,
static int jedec_probe8(struct map_info *map,unsigned long base,
struct jedec_private *priv)
{
#define flread(x) map->read8(map,base+x)
......@@ -387,14 +400,14 @@ int jedec_probe8(struct map_info *map,unsigned long base,
}
// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
int jedec_probe16(struct map_info *map,unsigned long base,
static int jedec_probe16(struct map_info *map,unsigned long base,
struct jedec_private *priv)
{
return 0;
}
// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
int jedec_probe32(struct map_info *map,unsigned long base,
static int jedec_probe32(struct map_info *map,unsigned long base,
struct jedec_private *priv)
{
#define flread(x) map->read32(map,base+((x)<<2))
......@@ -859,11 +872,6 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start
chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
}
}
/*}}}*/
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define jedec_probe_init init_module
#define jedec_probe_exit cleanup_module
#endif
int __init jedec_probe_init(void)
{
......@@ -878,3 +886,7 @@ static void __exit jedec_probe_exit(void)
module_init(jedec_probe_init);
module_exit(jedec_probe_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");
/* $Id: cfi_jedec.c,v 1.5 2001/06/02 14:52:23 dwmw2 Exp $ */
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id: jedec_probe.c,v 1.3 2001/10/02 15:05:12 dwmw2 Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
......@@ -8,9 +12,12 @@
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/gen_probe.h>
/* Manufacturers */
#define MANUFACTURER_AMD 0x0001
......@@ -241,29 +248,22 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x08000,2),
ERASEINFO(0x02000,8)
}
}, {
0
}
};
int cfi_jedec_lookup(int index, int mfr_id, int dev_id)
{
if (index>=0){
if (jedec_table[index].mfr_id == mfr_id &&
jedec_table[index].dev_id == dev_id) return index;
}
else{
for (index=0; jedec_table[index].mfr_id; index++){
if (jedec_table[index].mfr_id == mfr_id &&
jedec_table[index].dev_id == dev_id) return index;
}
}
return -1;
}
int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
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);
struct mtd_info *jedec_probe(struct map_info *map);
#define jedec_read_mfr(map, base, osf) cfi_read(map, base)
#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf))
static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
{
int i,num_erase_regions;
int i,num_erase_regions;
printk("Found: %s\n",jedec_table[index].name);
......@@ -272,7 +272,7 @@ int i,num_erase_regions;
p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
if (!p_cfi->cfiq) {
//xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
return -1;
return 0;
}
memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
......@@ -284,6 +284,158 @@ int i,num_erase_regions;
for (i=0; i<num_erase_regions; i++){
p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
}
return 0; /* ok */
return 1; /* ok */
}
static int jedec_probe_chip(struct map_info *map, __u32 base,
struct flchip *chips, struct cfi_private *cfi)
{
int i;
int osf = cfi->interleave * cfi->device_type;
int retried = 0;
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;
}
}
retry:
/* Reset */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
/* Autoselect Mode */
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(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
if (!cfi->numchips) {
/* This is the first time we're called. Set up the CFI
stuff accordingly and return */
cfi->mfr = jedec_read_mfr(map, base, osf);
cfi->id = jedec_read_id(map, base, osf);
for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
if (cfi->mfr == jedec_table[i].mfr_id &&
cfi->id == jedec_table[i].dev_id)
return cfi_jedec_setup(cfi, i);
}
if (!retried++) {
/* Deal with whichever strange chips these were */
cfi->addr_unlock1 |= cfi->addr_unlock1 << 8;
cfi->addr_unlock2 |= cfi->addr_unlock2 << 8;
goto retry;
}
return 0;
}
/* 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, base, osf) == cfi->mfr &&
jedec_read_id(map, base, osf) == cfi->id) {
/* Eep. This chip also looks like it's in autoselect mode.
Is it an alias for the new one? */
cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
/* If the device IDs go away, it's an alias */
if (jedec_read_mfr(map, base, osf) != cfi->mfr ||
jedec_read_id(map, base, osf) != 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);
return 0;
}
/* Yes, it's actually got the device IDs as data. Most
* unfortunate. Stick the new chip in read mode
* 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);
if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
jedec_read_id(map, base, osf) == 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);
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;
cfi->numchips++;
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 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",
map->name, cfi->interleave, cfi->device_type*8, base,
map->buswidth*8);
return 1;
}
static struct chip_probe jedec_chip_probe = {
name: "JEDEC",
probe_chip: jedec_probe_chip
};
struct mtd_info *jedec_probe(struct map_info *map)
{
/*
* Just use the generic probe stuff to call our CFI-specific
* chip_probe routine in all the possible permutations, etc.
*/
return mtd_do_chip_probe(map, &jedec_chip_probe);
}
static struct mtd_chip_driver jedec_chipdrv = {
probe: jedec_probe,
name: "jedec_probe",
module: THIS_MODULE
};
int __init jedec_probe_init(void)
{
register_mtd_chip_driver(&jedec_chipdrv);
return 0;
}
static void __exit jedec_probe_exit(void)
{
unregister_mtd_chip_driver(&jedec_chipdrv);
}
module_init(jedec_probe_init);
module_exit(jedec_probe_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
MODULE_DESCRIPTION("Probe code for JEDEC-compliant flash chips");
/*
* Common code to handle absent "placeholder" devices
* Copyright 2001 Resilience Corporation <ebrower@resilience.com>
* $Id: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $
*
* This map driver is used to allocate "placeholder" MTD
* devices on systems that have socketed/removable media.
* Use of this driver as a fallback preserves the expected
* registration of MTD device nodes regardless of probe outcome.
* A usage example is as follows:
*
* my_dev[i] = do_map_probe("cfi", &my_map[i]);
* if(NULL == my_dev[i]) {
* my_dev[i] = do_map_probe("map_absent", &my_map[i]);
* }
*
* Any device 'probed' with this driver will return -ENODEV
* upon open.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mtd/map.h>
static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int map_absent_erase (struct mtd_info *, struct erase_info *);
static void map_absent_sync (struct mtd_info *);
static struct mtd_info *map_absent_probe(struct map_info *map);
static void map_absent_destroy (struct mtd_info *);
static struct mtd_chip_driver map_absent_chipdrv = {
probe: map_absent_probe,
destroy: map_absent_destroy,
name: "map_absent",
module: THIS_MODULE
};
static struct mtd_info *map_absent_probe(struct map_info *map)
{
struct mtd_info *mtd;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
map->fldrv = &map_absent_chipdrv;
mtd->priv = map;
mtd->name = map->name;
mtd->type = MTD_ABSENT;
mtd->size = map->size;
mtd->erase = map_absent_erase;
mtd->read = map_absent_read;
mtd->write = map_absent_write;
mtd->sync = map_absent_sync;
mtd->flags = 0;
mtd->erasesize = PAGE_SIZE;
MOD_INC_USE_COUNT;
return mtd;
}
static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
*retlen = 0;
return -ENODEV;
}
static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
{
*retlen = 0;
return -ENODEV;
}
static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr)
{
return -ENODEV;
}
static void map_absent_sync(struct mtd_info *mtd)
{
/* nop */
}
static void map_absent_destroy(struct mtd_info *mtd)
{
/* nop */
}
int __init map_absent_init(void)
{
register_mtd_chip_driver(&map_absent_chipdrv);
return 0;
}
static void __exit map_absent_exit(void)
{
unregister_mtd_chip_driver(&map_absent_chipdrv);
}
module_init(map_absent_init);
module_exit(map_absent_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Resilience Corporation - Eric Brower <ebrower@resilience.com>");
MODULE_DESCRIPTION("Placeholder MTD chip driver for 'absent' chips");
/*
* Common code to handle map devices which are simple RAM
* (C) 2000 Red Hat. GPL'd.
* $Id: map_ram.c,v 1.11 2001/06/08 15:34:04 dwmw2 Exp $
* $Id: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $
*/
#include <linux/module.h>
......@@ -24,7 +24,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map);
static struct mtd_chip_driver mapram_chipdrv = {
probe: map_ram_probe,
name: "ram",
name: "map_ram",
module: THIS_MODULE
};
......@@ -63,14 +63,16 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->priv = map;
mtd->name = map->name;
mtd->type = MTD_RAM;
mtd->erasesize = 0x10000;
mtd->size = map->size;
mtd->erase = mapram_erase;
mtd->read = mapram_read;
mtd->write = mapram_write;
mtd->sync = mapram_nop;
mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
mtd->erasesize = PAGE_SIZE;
while(mtd->size & (mtd->erasesize - 1))
mtd->erasesize >>= 1;
MOD_INC_USE_COUNT;
return mtd;
......@@ -116,12 +118,7 @@ static void mapram_nop(struct mtd_info *mtd)
/* Nothing to see here */
}
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define map_ram_init init_module
#define map_ram_exit cleanup_module
#endif
static int __init map_ram_init(void)
int __init map_ram_init(void)
{
register_mtd_chip_driver(&mapram_chipdrv);
return 0;
......@@ -134,3 +131,7 @@ static void __exit map_ram_exit(void)
module_init(map_ram_init);
module_exit(map_ram_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("MTD chip driver for RAM chips");
/*
* Common code to handle map devices which are simple ROM
* (C) 2000 Red Hat. GPL'd.
* $Id: map_rom.c,v 1.14 2001/06/02 14:30:43 dwmw2 Exp $
* $Id: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
......@@ -21,7 +22,7 @@ struct mtd_info *map_rom_probe(struct map_info *map);
static struct mtd_chip_driver maprom_chipdrv = {
probe: map_rom_probe,
name: "rom",
name: "map_rom",
module: THIS_MODULE
};
......@@ -45,6 +46,8 @@ struct mtd_info *map_rom_probe(struct map_info *map)
mtd->sync = maprom_nop;
mtd->flags = MTD_CAP_ROM;
mtd->erasesize = 131072;
while(mtd->size & (mtd->erasesize - 1))
mtd->erasesize >>= 1;
MOD_INC_USE_COUNT;
return mtd;
......@@ -71,21 +74,20 @@ static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *re
return -EIO;
}
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define map_rom_init init_module
#define map_rom_exit cleanup_module
#endif
mod_init_t map_rom_init(void)
int __init map_rom_init(void)
{
register_mtd_chip_driver(&maprom_chipdrv);
return 0;
}
mod_exit_t map_rom_exit(void)
static void __exit map_rom_exit(void)
{
unregister_mtd_chip_driver(&maprom_chipdrv);
}
module_init(map_rom_init);
module_exit(map_rom_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("MTD chip driver for ROM chips");
......@@ -4,7 +4,7 @@
* Copyright 2000,2001 David A. Schleef <ds@schleef.org>
* 2000,2001 Lineo, Inc.
*
* $Id: sharp.c,v 1.4 2001/04/29 16:21:17 dwmw2 Exp $
* $Id: sharp.c,v 1.6 2001/10/02 15:05:12 dwmw2 Exp $
*
* Devices supported:
* LH28F016SCT Symmetrical block flash memory, 2Mx8
......@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/delay.h>
......@@ -569,11 +570,6 @@ static void sharp_destroy(struct mtd_info *mtd)
}
#if LINUX_VERSION_CODE < 0x020212 && defined(MODULE)
#define sharp_probe_init init_module
#define sharp_probe_exit cleanup_module
#endif
int __init sharp_probe_init(void)
{
printk("MTD Sharp chip driver <ds@lineo.com>\n");
......@@ -591,3 +587,7 @@ static void __exit sharp_probe_exit(void)
module_init(sharp_probe_init);
module_exit(sharp_probe_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Schleef <ds@schleef.org>");
MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
# drivers/mtd/maps/Config.in
# $Id: Config.in,v 1.2 2001/04/29 16:24:34 dwmw2 Exp $
# $Id: Config.in,v 1.5 2001/09/23 15:33:10 dwmw2 Exp $
mainmenu_option next_comment
......@@ -11,6 +11,9 @@ if [ "$CONFIG_MTD_PMC551" = "y" -o "$CONFIG_MTD_PMC551" = "m" ]; then
bool ' PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
fi
dep_tristate ' Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
if [ "$CONFIG_SA1100_LART" = "y" ]; then
dep_tristate ' 28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
fi
dep_tristate ' Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD
if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
int 'MTDRAM device size in KiB' CONFIG_MTDRAM_TOTAL_SIZE 4096
......@@ -19,6 +22,7 @@ if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
hex 'SRAM Hexadecimal Absolute position or 0' CONFIG_MTDRAM_ABS_POS 0
fi
fi
dep_tristate ' MTD emulation using block device' CONFIG_MTD_BLKMTD $CONFIG_MTD
comment 'Disk-On-Chip Device Drivers'
dep_tristate ' M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD
......
#
# linux/drivers/devices/Makefile
#
# $Id: Makefile,v 1.2 2001/04/19 22:12:36 dwmw2 Exp $
# $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
O_TARGET := devlink.o
......@@ -19,5 +19,7 @@ obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o
obj-$(CONFIG_MTD_SLRAM) += slram.o
obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
/*======================================================================
$Id: doc1000.c,v 1.11 2000/11/24 13:43:16 dwmw2 Exp $
$Id: doc1000.c,v 1.15 2001/10/02 15:05:13 dwmw2 Exp $
======================================================================*/
......@@ -286,9 +286,9 @@ int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen
static inline int byte_write (volatile u_char *addr, u_char byte)
{
register u_char status;
register u_short i = 0;
do {
register u_short i = 0;
do {
status = readb(addr);
if (status & CSR_WR_READY)
{
......@@ -510,11 +510,6 @@ static void flashcard_periodic(unsigned long data)
}
#if defined (MODULE) && LINUX_VERSION_CODE < 0x20211
#define init_doc1000 init_module
#define cleanup_doc1000 cleanup_module
#endif
int __init init_doc1000(void)
{
struct mypriv *priv;
......@@ -591,7 +586,10 @@ static void __init cleanup_doc1000(void)
kfree(mymtd);
}
#if LINUX_VERSION_CODE >= 0x20211
module_init(init_doc1000);
module_exit(cleanup_doc1000);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000");
This diff is collapsed.
......@@ -4,7 +4,7 @@
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*
* $Id: doc2001.c,v 1.34 2001/06/02 14:30:43 dwmw2 Exp $
* $Id: doc2001.c,v 1.35 2001/10/02 15:05:13 dwmw2 Exp $
*/
#include <linux/kernel.h>
......@@ -848,11 +848,6 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
#define cleanup_doc2001 cleanup_module
#define init_doc2001 init_module
#endif
int __init init_doc2001(void)
{
inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
......@@ -880,4 +875,6 @@ static void __exit cleanup_doc2001(void)
module_exit(cleanup_doc2001);
module_init(init_doc2001);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
MODULE_DESCRIPTION("Alternative driver for DiskOnChip Millennium");
......@@ -7,7 +7,7 @@
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
* $Id: docecc.c,v 1.1 2000/11/03 12:43:43 dwmw2 Exp $
* $Id: docecc.c,v 1.4 2001/10/02 15:05:13 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
......@@ -36,6 +36,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/mtd/compatmac.h> /* for min() in older kernels */
#include <linux/mtd/mtd.h>
#include <linux/mtd/doc2000.h>
......@@ -402,7 +403,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for (i = min_t(int, deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
if(lambda[i+1] != A0)
den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])];
}
......@@ -518,3 +519,6 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
return nb_errors;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment