Remove files now present upstream in files-2.6.25 (This is mostly just drivers/ssb and include/linux/ssb) [brcm47xx] Regenerate patches against 2.6.25.1 kernel+files set Default is still to build against 2.6.23.16
SVN-Revision: 11155
This commit is contained in:
parent
9788ab458c
commit
79aed699d7
96 changed files with 18635 additions and 4788 deletions
252
target/linux/brcm47xx/config-2.6.25
Normal file
252
target/linux/brcm47xx/config-2.6.25
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
CONFIG_32BIT=y
|
||||||
|
# CONFIG_64BIT is not set
|
||||||
|
# CONFIG_8139TOO is not set
|
||||||
|
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
|
||||||
|
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
|
||||||
|
# CONFIG_ARCH_SUPPORTS_MSI is not set
|
||||||
|
# CONFIG_ARPD is not set
|
||||||
|
# CONFIG_ATMEL is not set
|
||||||
|
CONFIG_B44=y
|
||||||
|
CONFIG_BASE_SMALL=0
|
||||||
|
# CONFIG_BCM43XX is not set
|
||||||
|
CONFIG_BCM47XX=y
|
||||||
|
CONFIG_BITREVERSE=y
|
||||||
|
# CONFIG_BONDING is not set
|
||||||
|
# CONFIG_BSD_DISKLABEL is not set
|
||||||
|
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||||
|
# CONFIG_BT_HCIBCM203X is not set
|
||||||
|
# CONFIG_BT_HCIBFUSB is not set
|
||||||
|
# CONFIG_BT_HCIBPA10X is not set
|
||||||
|
# CONFIG_BT_HCIVHCI is not set
|
||||||
|
CONFIG_CFE=y
|
||||||
|
# CONFIG_CIFS_STATS is not set
|
||||||
|
# CONFIG_CLS_U32_MARK is not set
|
||||||
|
# CONFIG_CLS_U32_PERF is not set
|
||||||
|
CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd console=ttyS0,115200"
|
||||||
|
# CONFIG_CONFIGFS_FS is not set
|
||||||
|
CONFIG_CONNECTOR=m
|
||||||
|
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||||
|
CONFIG_CPU_HAS_LLSC=y
|
||||||
|
CONFIG_CPU_HAS_PREFETCH=y
|
||||||
|
CONFIG_CPU_HAS_SYNC=y
|
||||||
|
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||||
|
# CONFIG_CPU_LOONGSON2 is not set
|
||||||
|
CONFIG_CPU_MIPS32=y
|
||||||
|
CONFIG_CPU_MIPS32_R1=y
|
||||||
|
# CONFIG_CPU_MIPS32_R2 is not set
|
||||||
|
# CONFIG_CPU_MIPS64_R1 is not set
|
||||||
|
# CONFIG_CPU_MIPS64_R2 is not set
|
||||||
|
CONFIG_CPU_MIPSR1=y
|
||||||
|
# CONFIG_CPU_NEVADA is not set
|
||||||
|
# CONFIG_CPU_R10000 is not set
|
||||||
|
# CONFIG_CPU_R3000 is not set
|
||||||
|
# CONFIG_CPU_R4300 is not set
|
||||||
|
# CONFIG_CPU_R4X00 is not set
|
||||||
|
# CONFIG_CPU_R5000 is not set
|
||||||
|
# CONFIG_CPU_R5432 is not set
|
||||||
|
# CONFIG_CPU_R6000 is not set
|
||||||
|
# CONFIG_CPU_R8000 is not set
|
||||||
|
# CONFIG_CPU_RM7000 is not set
|
||||||
|
# CONFIG_CPU_RM9000 is not set
|
||||||
|
# CONFIG_CPU_SB1 is not set
|
||||||
|
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
|
||||||
|
CONFIG_CPU_SUPPORTS_HIGHMEM=y
|
||||||
|
# CONFIG_CPU_TX39XX is not set
|
||||||
|
# CONFIG_CPU_TX49XX is not set
|
||||||
|
# CONFIG_CPU_VR41XX is not set
|
||||||
|
# CONFIG_CRYPTO_HW is not set
|
||||||
|
CONFIG_DEVPORT=y
|
||||||
|
# CONFIG_DM9000 is not set
|
||||||
|
CONFIG_DMA_NEED_PCI_MAP_STATE=y
|
||||||
|
CONFIG_DMA_NONCOHERENT=y
|
||||||
|
# CONFIG_E100 is not set
|
||||||
|
CONFIG_FS_POSIX_ACL=y
|
||||||
|
CONFIG_GENERIC_FIND_NEXT_BIT=y
|
||||||
|
CONFIG_GENERIC_GPIO=y
|
||||||
|
# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
|
||||||
|
# CONFIG_HAMRADIO is not set
|
||||||
|
CONFIG_HAS_DMA=y
|
||||||
|
CONFIG_HAS_IOMEM=y
|
||||||
|
CONFIG_HAS_IOPORT=y
|
||||||
|
CONFIG_HID=m
|
||||||
|
# CONFIG_HID_SUPPORT is not set
|
||||||
|
CONFIG_HW_HAS_PCI=y
|
||||||
|
CONFIG_HW_RANDOM=y
|
||||||
|
CONFIG_HZ=250
|
||||||
|
# CONFIG_HZ_100 is not set
|
||||||
|
CONFIG_HZ_250=y
|
||||||
|
# CONFIG_I2C is not set
|
||||||
|
# CONFIG_IDE is not set
|
||||||
|
# CONFIG_IKCONFIG is not set
|
||||||
|
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
|
||||||
|
CONFIG_INITRAMFS_SOURCE=""
|
||||||
|
CONFIG_INPUT=y
|
||||||
|
CONFIG_INPUT_EVDEV=y
|
||||||
|
CONFIG_INPUT_POLLDEV=y
|
||||||
|
# CONFIG_IP6_NF_MATCH_FRAG is not set
|
||||||
|
# CONFIG_IP6_NF_MATCH_HL is not set
|
||||||
|
# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
|
||||||
|
# CONFIG_IP6_NF_MATCH_OPTS is not set
|
||||||
|
# CONFIG_IP6_NF_MATCH_RT is not set
|
||||||
|
# CONFIG_IP6_NF_TARGET_HL is not set
|
||||||
|
CONFIG_IPW2200_QOS=y
|
||||||
|
# CONFIG_IP_ROUTE_VERBOSE is not set
|
||||||
|
CONFIG_IRQ_CPU=y
|
||||||
|
# CONFIG_LEDS_ALIX is not set
|
||||||
|
CONFIG_LEDS_GPIO=y
|
||||||
|
# CONFIG_LEMOTE_FULONG is not set
|
||||||
|
# CONFIG_LLC2 is not set
|
||||||
|
# CONFIG_MACH_ALCHEMY is not set
|
||||||
|
# CONFIG_MACH_DECSTATION is not set
|
||||||
|
# CONFIG_MACH_JAZZ is not set
|
||||||
|
# CONFIG_MACH_VR41XX is not set
|
||||||
|
CONFIG_MIPS=y
|
||||||
|
# CONFIG_MIPS_ATLAS is not set
|
||||||
|
# CONFIG_MIPS_COBALT is not set
|
||||||
|
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||||
|
# CONFIG_MIPS_MALTA is not set
|
||||||
|
CONFIG_MIPS_MT_DISABLED=y
|
||||||
|
# CONFIG_MIPS_MT_SMP is not set
|
||||||
|
# CONFIG_MIPS_MT_SMTC is not set
|
||||||
|
# CONFIG_MIPS_SEAD is not set
|
||||||
|
# CONFIG_MIPS_SIM is not set
|
||||||
|
CONFIG_MTD=y
|
||||||
|
# CONFIG_MTD_ABSENT is not set
|
||||||
|
CONFIG_MTD_BCM47XX=y
|
||||||
|
CONFIG_MTD_BLKDEVS=y
|
||||||
|
CONFIG_MTD_BLOCK=y
|
||||||
|
# CONFIG_MTD_BLOCK2MTD is not set
|
||||||
|
CONFIG_MTD_CFI=y
|
||||||
|
# CONFIG_MTD_CFI_ADV_OPTIONS is not set
|
||||||
|
CONFIG_MTD_CFI_AMDSTD=y
|
||||||
|
CONFIG_MTD_CFI_I1=y
|
||||||
|
CONFIG_MTD_CFI_I2=y
|
||||||
|
# CONFIG_MTD_CFI_I4 is not set
|
||||||
|
# CONFIG_MTD_CFI_I8 is not set
|
||||||
|
CONFIG_MTD_CFI_INTELEXT=y
|
||||||
|
# CONFIG_MTD_CFI_STAA is not set
|
||||||
|
CONFIG_MTD_CFI_UTIL=y
|
||||||
|
CONFIG_MTD_CHAR=y
|
||||||
|
# CONFIG_MTD_CMDLINE_PARTS is not set
|
||||||
|
CONFIG_MTD_COMPLEX_MAPPINGS=y
|
||||||
|
# CONFIG_MTD_CONCAT is not set
|
||||||
|
# CONFIG_MTD_DEBUG is not set
|
||||||
|
# CONFIG_MTD_DOC2000 is not set
|
||||||
|
# CONFIG_MTD_DOC2001 is not set
|
||||||
|
# CONFIG_MTD_DOC2001PLUS is not set
|
||||||
|
CONFIG_MTD_GEN_PROBE=y
|
||||||
|
# CONFIG_MTD_JEDECPROBE is not set
|
||||||
|
CONFIG_MTD_MAP_BANK_WIDTH_1=y
|
||||||
|
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
|
||||||
|
CONFIG_MTD_MAP_BANK_WIDTH_2=y
|
||||||
|
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
|
||||||
|
CONFIG_MTD_MAP_BANK_WIDTH_4=y
|
||||||
|
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
|
||||||
|
# CONFIG_MTD_MTDRAM is not set
|
||||||
|
# CONFIG_MTD_ONENAND is not set
|
||||||
|
CONFIG_MTD_PARTITIONS=y
|
||||||
|
# CONFIG_MTD_PCI is not set
|
||||||
|
# CONFIG_MTD_PHRAM is not set
|
||||||
|
# CONFIG_MTD_PHYSMAP is not set
|
||||||
|
# CONFIG_MTD_PLATRAM is not set
|
||||||
|
# CONFIG_MTD_PMC551 is not set
|
||||||
|
# CONFIG_MTD_RAM is not set
|
||||||
|
# CONFIG_MTD_REDBOOT_PARTS is not set
|
||||||
|
# CONFIG_MTD_ROM is not set
|
||||||
|
# CONFIG_MTD_SLRAM is not set
|
||||||
|
# CONFIG_NATSEMI is not set
|
||||||
|
# CONFIG_NE2K_PCI is not set
|
||||||
|
CONFIG_NETDEV_1000=y
|
||||||
|
# CONFIG_NET_EMATCH is not set
|
||||||
|
# CONFIG_NET_IPGRE_BROADCAST is not set
|
||||||
|
# CONFIG_NET_PKTGEN is not set
|
||||||
|
# CONFIG_NET_SCH_NETEM is not set
|
||||||
|
# CONFIG_NET_VENDOR_3COM is not set
|
||||||
|
# CONFIG_NO_IOPORT is not set
|
||||||
|
# CONFIG_PAGE_SIZE_16KB is not set
|
||||||
|
CONFIG_PAGE_SIZE_4KB=y
|
||||||
|
# CONFIG_PAGE_SIZE_64KB is not set
|
||||||
|
# CONFIG_PAGE_SIZE_8KB is not set
|
||||||
|
# CONFIG_PMC_MSP is not set
|
||||||
|
# CONFIG_PMC_YOSEMITE is not set
|
||||||
|
# CONFIG_PNX8550_JBS is not set
|
||||||
|
# CONFIG_PNX8550_STB810 is not set
|
||||||
|
# CONFIG_PPP_MULTILINK is not set
|
||||||
|
# CONFIG_PPP_SYNC_TTY is not set
|
||||||
|
# CONFIG_PROC_KCORE is not set
|
||||||
|
CONFIG_RFKILL=y
|
||||||
|
CONFIG_RFKILL_INPUT=y
|
||||||
|
CONFIG_RFKILL_LEDS=y
|
||||||
|
# CONFIG_RTC is not set
|
||||||
|
CONFIG_RWSEM_GENERIC_SPINLOCK=y
|
||||||
|
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
|
||||||
|
# CONFIG_SCSI_MULTI_LUN is not set
|
||||||
|
CONFIG_SCSI_WAIT_SCAN=m
|
||||||
|
# CONFIG_SERIAL_8250_DETECT_IRQ is not set
|
||||||
|
CONFIG_SERIAL_8250_EXTENDED=y
|
||||||
|
# CONFIG_SERIAL_8250_MANY_PORTS is not set
|
||||||
|
# CONFIG_SERIAL_8250_RSA is not set
|
||||||
|
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||||
|
# CONFIG_SGI_IP22 is not set
|
||||||
|
# CONFIG_SGI_IP27 is not set
|
||||||
|
# CONFIG_SGI_IP32 is not set
|
||||||
|
# CONFIG_SIBYTE_BIGSUR is not set
|
||||||
|
# CONFIG_SIBYTE_CARMEL is not set
|
||||||
|
# CONFIG_SIBYTE_CRHINE is not set
|
||||||
|
# CONFIG_SIBYTE_CRHONE is not set
|
||||||
|
# CONFIG_SIBYTE_LITTLESUR is not set
|
||||||
|
# CONFIG_SIBYTE_PTSWARM is not set
|
||||||
|
# CONFIG_SIBYTE_RHONE is not set
|
||||||
|
# CONFIG_SIBYTE_SENTOSA is not set
|
||||||
|
# CONFIG_SIBYTE_SWARM is not set
|
||||||
|
# CONFIG_SPARSEMEM_STATIC is not set
|
||||||
|
CONFIG_SSB=y
|
||||||
|
CONFIG_SSB_DEBUG=y
|
||||||
|
CONFIG_SSB_DRIVER_EXTIF=y
|
||||||
|
# CONFIG_SSB_DRIVER_GIGE is not set
|
||||||
|
CONFIG_SSB_DRIVER_MIPS=y
|
||||||
|
CONFIG_SSB_DRIVER_PCICORE=y
|
||||||
|
CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
|
||||||
|
CONFIG_SSB_EMBEDDED=y
|
||||||
|
CONFIG_SSB_PCICORE_HOSTMODE=y
|
||||||
|
CONFIG_SSB_PCIHOST=y
|
||||||
|
CONFIG_SSB_PCIHOST_POSSIBLE=y
|
||||||
|
CONFIG_SSB_POSSIBLE=y
|
||||||
|
CONFIG_SSB_SERIAL=y
|
||||||
|
# CONFIG_SSB_SILENT is not set
|
||||||
|
CONFIG_SYSVIPC_SYSCTL=y
|
||||||
|
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
|
||||||
|
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
|
||||||
|
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
|
||||||
|
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
|
||||||
|
# CONFIG_TC35815 is not set
|
||||||
|
# CONFIG_TOSHIBA_JMR3927 is not set
|
||||||
|
# CONFIG_TOSHIBA_RBTX4927 is not set
|
||||||
|
# CONFIG_TOSHIBA_RBTX4938 is not set
|
||||||
|
CONFIG_TRAD_SIGNALS=y
|
||||||
|
# CONFIG_USB_CATC is not set
|
||||||
|
CONFIG_USB_EHCI_HCD=m
|
||||||
|
CONFIG_USB_EHCI_SPLIT_ISO=y
|
||||||
|
# CONFIG_USB_KAWETH is not set
|
||||||
|
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
|
||||||
|
# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
|
||||||
|
CONFIG_USB_OHCI_HCD=m
|
||||||
|
CONFIG_USB_OHCI_HCD_SSB=y
|
||||||
|
# CONFIG_USB_PEGASUS is not set
|
||||||
|
# CONFIG_USB_R8A66597_HCD is not set
|
||||||
|
# CONFIG_USB_SERIAL_OTI6858 is not set
|
||||||
|
# CONFIG_USB_STORAGE_ALAUDA is not set
|
||||||
|
# CONFIG_USB_STORAGE_DATAFAB is not set
|
||||||
|
# CONFIG_USB_STORAGE_DPCM is not set
|
||||||
|
# CONFIG_USB_STORAGE_FREECOM is not set
|
||||||
|
# CONFIG_USB_STORAGE_JUMPSHOT is not set
|
||||||
|
# CONFIG_USB_STORAGE_KARMA is not set
|
||||||
|
# CONFIG_USB_STORAGE_SDDR09 is not set
|
||||||
|
# CONFIG_USB_STORAGE_SDDR55 is not set
|
||||||
|
# CONFIG_USB_STORAGE_USBAT is not set
|
||||||
|
CONFIG_USB_UHCI_HCD=m
|
||||||
|
# CONFIG_USER_NS is not set
|
||||||
|
# CONFIG_VGASTATE is not set
|
||||||
|
# CONFIG_VIA_RHINE is not set
|
||||||
|
# CONFIG_WATCHDOG is not set
|
||||||
|
CONFIG_ZONE_DMA_FLAG=0
|
|
@ -1,7 +0,0 @@
|
||||||
#
|
|
||||||
# Makefile for the BCM47xx specific kernel interface routines
|
|
||||||
# under Linux.
|
|
||||||
#
|
|
||||||
|
|
||||||
obj-y := irq.o prom.o setup.o time.o
|
|
||||||
obj-y += nvram.o cfe_env.o
|
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
|
|
||||||
* Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
|
|
||||||
*
|
|
||||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* 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.,
|
|
||||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/irq.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/smp.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
|
|
||||||
#include <asm/cpu.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <asm/irq.h>
|
|
||||||
#include <asm/irq_cpu.h>
|
|
||||||
|
|
||||||
|
|
||||||
extern struct ssb_bus ssb;
|
|
||||||
|
|
||||||
|
|
||||||
void plat_irq_dispatch(void)
|
|
||||||
{
|
|
||||||
u32 cause;
|
|
||||||
|
|
||||||
cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
|
|
||||||
|
|
||||||
clear_c0_status(cause);
|
|
||||||
|
|
||||||
if (cause & CAUSEF_IP7)
|
|
||||||
do_IRQ(7);
|
|
||||||
if (cause & CAUSEF_IP2)
|
|
||||||
do_IRQ(2);
|
|
||||||
if (cause & CAUSEF_IP3)
|
|
||||||
do_IRQ(3);
|
|
||||||
if (cause & CAUSEF_IP4)
|
|
||||||
do_IRQ(4);
|
|
||||||
if (cause & CAUSEF_IP5)
|
|
||||||
do_IRQ(5);
|
|
||||||
if (cause & CAUSEF_IP6)
|
|
||||||
do_IRQ(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init arch_init_irq(void)
|
|
||||||
{
|
|
||||||
mips_cpu_irq_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = ssb_pcibios_map_irq(dev, slot, pin);
|
|
||||||
if (res < 0) {
|
|
||||||
printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
|
|
||||||
dev->dev.bus_id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* IRQ-0 and IRQ-1 are software interrupts. */
|
|
||||||
WARN_ON((res == 0) || (res == 1));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
|
|
||||||
*
|
|
||||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* 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.,
|
|
||||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/bootmem.h>
|
|
||||||
|
|
||||||
#include <asm/addrspace.h>
|
|
||||||
#include <asm/bootinfo.h>
|
|
||||||
#include <asm/pmon.h>
|
|
||||||
#include "../cfe/cfe_private.h"
|
|
||||||
|
|
||||||
const char *get_system_type(void)
|
|
||||||
{
|
|
||||||
return "Broadcom BCM47xx";
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init prom_init(void)
|
|
||||||
{
|
|
||||||
unsigned long mem;
|
|
||||||
|
|
||||||
mips_machgroup = MACH_GROUP_BRCM;
|
|
||||||
mips_machtype = MACH_BCM47XX;
|
|
||||||
|
|
||||||
cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3);
|
|
||||||
|
|
||||||
/* Figure out memory size by finding aliases */
|
|
||||||
for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
|
|
||||||
if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
|
|
||||||
*(unsigned long *)(prom_init))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_memory_region(0, mem, BOOT_MEM_RAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init prom_free_prom_memory(void)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,246 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
|
|
||||||
* Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
|
|
||||||
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
|
||||||
* Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de>
|
|
||||||
*
|
|
||||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* 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.,
|
|
||||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/tty.h>
|
|
||||||
#include <linux/serial.h>
|
|
||||||
#include <linux/serial_core.h>
|
|
||||||
#include <linux/serial_reg.h>
|
|
||||||
#include <linux/serial_8250.h>
|
|
||||||
#include <asm/bootinfo.h>
|
|
||||||
#include <asm/time.h>
|
|
||||||
#include <asm/reboot.h>
|
|
||||||
#include <asm/cfe.h>
|
|
||||||
#include <linux/pm.h>
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
#include <linux/ssb/ssb_embedded.h>
|
|
||||||
|
|
||||||
#include <nvram.h>
|
|
||||||
|
|
||||||
extern void bcm47xx_pci_init(void);
|
|
||||||
extern void bcm47xx_time_init(void);
|
|
||||||
|
|
||||||
struct ssb_bus ssb;
|
|
||||||
|
|
||||||
|
|
||||||
int pcibios_plat_dev_init(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = ssb_pcibios_plat_dev_init(dev);
|
|
||||||
if (err) {
|
|
||||||
printk(KERN_ALERT "PCI: Failed to init device %s\n",
|
|
||||||
pci_name(dev));
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bcm47xx_machine_restart(char *command)
|
|
||||||
{
|
|
||||||
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
|
|
||||||
local_irq_disable();
|
|
||||||
/* CFE has a reboot callback, but that does not work.
|
|
||||||
* Oopses with: Reserved instruction in kernel code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Set the watchdog timer to reset immediately */
|
|
||||||
if (ssb_watchdog_timer_set(&ssb, 1))
|
|
||||||
printk(KERN_EMERG "SSB watchdog-triggered reboot failed!\n");
|
|
||||||
while (1)
|
|
||||||
cpu_relax();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bcm47xx_machine_halt(void)
|
|
||||||
{
|
|
||||||
/* Disable interrupts and watchdog and spin forever */
|
|
||||||
local_irq_disable();
|
|
||||||
if (ssb_watchdog_timer_set(&ssb, 0))
|
|
||||||
printk(KERN_EMERG "Failed to disable SSB watchdog!\n");
|
|
||||||
while (1)
|
|
||||||
cpu_relax();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void e_aton(char *str, char *dest)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (str == NULL) {
|
|
||||||
memset(dest, 0, 6);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
dest[i++] = (char) simple_strtoul(str, NULL, 16);
|
|
||||||
str += 2;
|
|
||||||
if (!*str++ || i == 6)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
memset(sprom, 0xFF, sizeof(struct ssb_sprom));
|
|
||||||
|
|
||||||
sprom->revision = 1;
|
|
||||||
if ((s = nvram_get("il0macaddr")))
|
|
||||||
e_aton(s, sprom->il0mac);
|
|
||||||
if ((s = nvram_get("et0macaddr")))
|
|
||||||
e_aton(s, sprom->et0mac);
|
|
||||||
if ((s = nvram_get("et1macaddr")))
|
|
||||||
e_aton(s, sprom->et1mac);
|
|
||||||
if ((s = nvram_get("et0phyaddr")))
|
|
||||||
sprom->et0phyaddr = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("et1phyaddr")))
|
|
||||||
sprom->et1phyaddr = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("et0mdcport")))
|
|
||||||
sprom->et0mdcport = !!simple_strtoul(s, NULL, 10);
|
|
||||||
if ((s = nvram_get("et1mdcport")))
|
|
||||||
sprom->et1mdcport = !!simple_strtoul(s, NULL, 10);
|
|
||||||
if ((s = nvram_get("pa0b0")))
|
|
||||||
sprom->pa0b0 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa0b1")))
|
|
||||||
sprom->pa0b1 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa0b2")))
|
|
||||||
sprom->pa0b2 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa1b0")))
|
|
||||||
sprom->pa1b0 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa1b1")))
|
|
||||||
sprom->pa1b1 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa1b2")))
|
|
||||||
sprom->pa1b2 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("wl0gpio0")))
|
|
||||||
sprom->gpio0 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("wl0gpio1")))
|
|
||||||
sprom->gpio1 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("wl0gpio2")))
|
|
||||||
sprom->gpio2 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("wl0gpio3")))
|
|
||||||
sprom->gpio3 = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa0maxpwr")))
|
|
||||||
sprom->maxpwr_bg = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa1maxpwr")))
|
|
||||||
sprom->maxpwr_a = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa0itssit")))
|
|
||||||
sprom->itssi_bg = simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("pa1itssit")))
|
|
||||||
sprom->itssi_a = simple_strtoul(s, NULL, 0);
|
|
||||||
sprom->boardflags_lo = 0;
|
|
||||||
if ((s = nvram_get("boardflags")))
|
|
||||||
sprom->boardflags_lo = simple_strtoul(s, NULL, 0);
|
|
||||||
sprom->boardflags_hi = 0;
|
|
||||||
if ((s = nvram_get("boardflags2")))
|
|
||||||
sprom->boardflags_hi = simple_strtoul(s, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
|
|
||||||
if ((s = nvram_get("boardtype")))
|
|
||||||
iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0);
|
|
||||||
if ((s = nvram_get("boardrev")))
|
|
||||||
iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0);
|
|
||||||
|
|
||||||
bcm47xx_fill_sprom(&iv->sprom);
|
|
||||||
|
|
||||||
if ((s = nvram_get("cardbus")))
|
|
||||||
iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init plat_mem_setup(void)
|
|
||||||
{
|
|
||||||
int i, err;
|
|
||||||
char *s;
|
|
||||||
struct ssb_mipscore *mcore;
|
|
||||||
|
|
||||||
err = ssb_bus_ssbbus_register(&ssb, SSB_ENUM_BASE, bcm47xx_get_invariants);
|
|
||||||
if (err) {
|
|
||||||
const char *msg = "Failed to initialize SSB bus (err %d)\n";
|
|
||||||
cfe_printk(msg, err); /* Make sure the message gets out of the box. */
|
|
||||||
panic(msg, err);
|
|
||||||
}
|
|
||||||
mcore = &ssb.mipscore;
|
|
||||||
|
|
||||||
s = nvram_get("kernel_args");
|
|
||||||
if (s && !strncmp(s, "console=ttyS1", 13)) {
|
|
||||||
struct ssb_serial_port port;
|
|
||||||
|
|
||||||
cfe_printk("Swapping serial ports!\n");
|
|
||||||
/* swap serial ports */
|
|
||||||
memcpy(&port, &mcore->serial_ports[0], sizeof(port));
|
|
||||||
memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
|
|
||||||
memcpy(&mcore->serial_ports[1], &port, sizeof(port));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < mcore->nr_serial_ports; i++) {
|
|
||||||
struct ssb_serial_port *port = &(mcore->serial_ports[i]);
|
|
||||||
struct uart_port s;
|
|
||||||
|
|
||||||
memset(&s, 0, sizeof(s));
|
|
||||||
s.line = i;
|
|
||||||
s.membase = port->regs;
|
|
||||||
s.irq = port->irq + 2;
|
|
||||||
s.uartclk = port->baud_base;
|
|
||||||
s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
|
||||||
s.iotype = SERIAL_IO_MEM;
|
|
||||||
s.regshift = port->reg_shift;
|
|
||||||
|
|
||||||
early_serial_setup(&s);
|
|
||||||
}
|
|
||||||
cfe_printk("Serial init done.\n");
|
|
||||||
|
|
||||||
_machine_restart = bcm47xx_machine_restart;
|
|
||||||
_machine_halt = bcm47xx_machine_halt;
|
|
||||||
pm_power_off = bcm47xx_machine_halt;
|
|
||||||
board_time_init = bcm47xx_time_init;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init bcm47xx_register_gpiodev(void)
|
|
||||||
{
|
|
||||||
static struct resource res = {
|
|
||||||
.start = 0xFFFFFFFF,
|
|
||||||
};
|
|
||||||
struct platform_device *pdev;
|
|
||||||
|
|
||||||
pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
|
|
||||||
if (!pdev) {
|
|
||||||
printk(KERN_ERR "bcm47xx: GPIODEV init failed\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
device_initcall(bcm47xx_register_gpiodev);
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(ssb);
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
|
|
||||||
*
|
|
||||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* 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.,
|
|
||||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/serial_reg.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
#include <asm/addrspace.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <asm/time.h>
|
|
||||||
|
|
||||||
extern struct ssb_bus ssb;
|
|
||||||
|
|
||||||
void __init
|
|
||||||
bcm47xx_time_init(void)
|
|
||||||
{
|
|
||||||
unsigned long hz;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use deterministic values for initial counter interrupt
|
|
||||||
* so that calibrate delay avoids encountering a counter wrap.
|
|
||||||
*/
|
|
||||||
write_c0_count(0);
|
|
||||||
write_c0_compare(0xffff);
|
|
||||||
|
|
||||||
hz = ssb_cpu_clock(&ssb.mipscore) / 2;
|
|
||||||
if (!hz)
|
|
||||||
hz = 100000000;
|
|
||||||
|
|
||||||
/* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
|
|
||||||
mips_hpt_frequency = hz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init
|
|
||||||
plat_timer_setup(struct irqaction *irq)
|
|
||||||
{
|
|
||||||
/* Enable the timer interrupt */
|
|
||||||
setup_irq(7, irq);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
#
|
|
||||||
# Makefile for the Broadcom Common Firmware Environment support
|
|
||||||
#
|
|
||||||
|
|
||||||
obj-y += cfe.o
|
|
|
@ -1,533 +0,0 @@
|
||||||
/*
|
|
||||||
* Broadcom Common Firmware Environment (CFE) support
|
|
||||||
*
|
|
||||||
* Copyright 2000, 2001, 2002
|
|
||||||
* Broadcom Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006 Michael Buesch
|
|
||||||
*
|
|
||||||
* Original Authors: Mitch Lichtenberg, Chris Demetriou
|
|
||||||
*
|
|
||||||
* This software is furnished under license and may be used and copied only
|
|
||||||
* in accordance with the following terms and conditions. Subject to these
|
|
||||||
* conditions, you may download, copy, install, use, modify and distribute
|
|
||||||
* modified or unmodified copies of this software in source and/or binary
|
|
||||||
* form. No title or ownership is transferred hereby.
|
|
||||||
*
|
|
||||||
* 1) Any source code used, modified or distributed must reproduce and
|
|
||||||
* retain this copyright notice and list of conditions as they appear in
|
|
||||||
* the source file.
|
|
||||||
*
|
|
||||||
* 2) No right is granted to use any trade name, trademark, or logo of
|
|
||||||
* Broadcom Corporation. The "Broadcom Corporation" name may not be
|
|
||||||
* used to endorse or promote products derived from this software
|
|
||||||
* without the prior written permission of Broadcom Corporation.
|
|
||||||
*
|
|
||||||
* 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
|
||||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
|
|
||||||
* FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
|
|
||||||
* LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
||||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
* OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <asm/cfe.h>
|
|
||||||
|
|
||||||
#include "cfe_private.h"
|
|
||||||
|
|
||||||
|
|
||||||
static cfe_uint_t cfe_handle;
|
|
||||||
static int (*cfe_trampoline)(long handle, long iocb);
|
|
||||||
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
|
|
||||||
void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
|
|
||||||
unsigned long fwarg2, unsigned long fwarg3)
|
|
||||||
{
|
|
||||||
if (fwarg3 == 0x80300000) {
|
|
||||||
/* WRT54G workaround */
|
|
||||||
fwarg3 = CFE_EPTSEAL;
|
|
||||||
fwarg2 = 0xBFC00500;
|
|
||||||
}
|
|
||||||
if (fwarg3 != CFE_EPTSEAL) {
|
|
||||||
/* We are not booted from CFE */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (fwarg1 == 0) {
|
|
||||||
/* We are on the boot CPU */
|
|
||||||
cfe_handle = (cfe_uint_t)fwarg0;
|
|
||||||
cfe_trampoline = CFE_TO_PTR(fwarg2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_vprintk(const char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
static char buffer[1024];
|
|
||||||
static DEFINE_SPINLOCK(lock);
|
|
||||||
static const char pfx[] = "CFE-console: ";
|
|
||||||
static const size_t pfx_len = sizeof(pfx) - 1;
|
|
||||||
unsigned long flags;
|
|
||||||
int len, cnt, pos;
|
|
||||||
int handle;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if (!cfe_present())
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&lock, flags);
|
|
||||||
handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
|
|
||||||
if (CFE_ISERR(handle)) {
|
|
||||||
len = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
strcpy(buffer, pfx);
|
|
||||||
len = vscnprintf(buffer + pfx_len,
|
|
||||||
sizeof(buffer) - pfx_len - 2,
|
|
||||||
fmt, args);
|
|
||||||
len += pfx_len;
|
|
||||||
/* The CFE console requires CR-LF line-ends.
|
|
||||||
* Add a CR, if we only terminate lines with a LF.
|
|
||||||
* This does only fix CR-LF at the end of the string.
|
|
||||||
* So for multiple lines, use multiple cfe_vprintk calls.
|
|
||||||
*/
|
|
||||||
if (len > 1 &&
|
|
||||||
buffer[len - 1] == '\n' && buffer[len - 2] != '\r') {
|
|
||||||
buffer[len - 1] = '\r';
|
|
||||||
buffer[len] = '\n';
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
cnt = len;
|
|
||||||
pos = 0;
|
|
||||||
while (cnt > 0) {
|
|
||||||
res = cfe_write(handle, buffer + pos, len - pos);
|
|
||||||
if (CFE_ISERR(res)) {
|
|
||||||
len = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cnt -= res;
|
|
||||||
pos += res;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&lock, flags);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_printk(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
res = cfe_vprintk(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cfe_iocb_dispatch(struct cfe_iocb *iocb)
|
|
||||||
{
|
|
||||||
if (!cfe_present())
|
|
||||||
return CFE_ERR_UNSUPPORTED;
|
|
||||||
return cfe_trampoline((long)cfe_handle, (long)iocb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_present(void)
|
|
||||||
{
|
|
||||||
return (cfe_trampoline != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_close(int handle)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_CLOSE;
|
|
||||||
iocb.handle = handle;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_CPUCTL;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_cpuctl);
|
|
||||||
iocb.cpuctl.number = cpu;
|
|
||||||
iocb.cpuctl.command = CFE_CPU_CMD_START;
|
|
||||||
iocb.cpuctl.gp = gp;
|
|
||||||
iocb.cpuctl.sp = sp;
|
|
||||||
iocb.cpuctl.a1 = a1;
|
|
||||||
iocb.cpuctl.start_addr = (long)fn;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_cpu_stop(int cpu)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_CPUCTL;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_cpuctl);
|
|
||||||
iocb.cpuctl.number = cpu;
|
|
||||||
iocb.cpuctl.command = CFE_CPU_CMD_STOP;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_ENV_ENUM;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_envbuf);
|
|
||||||
iocb.envbuf.index = idx;
|
|
||||||
iocb.envbuf.name = PTR_TO_CFE(name);
|
|
||||||
iocb.envbuf.name_len = namelen;
|
|
||||||
iocb.envbuf.val = PTR_TO_CFE(val);
|
|
||||||
iocb.envbuf.val_len = vallen;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_enumdev(int idx, char *name, int namelen)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
|
|
||||||
iocb.fcode = CFE_CMD_DEV_ENUM;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_envbuf);
|
|
||||||
iocb.envbuf.index = idx;
|
|
||||||
iocb.envbuf.name = PTR_TO_CFE(name);
|
|
||||||
iocb.envbuf.name_len = namelen;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
|
|
||||||
u64 *type)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
|
|
||||||
iocb.fcode = CFE_CMD_FW_MEMENUM;
|
|
||||||
iocb.flags = flags;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_meminfo);
|
|
||||||
iocb.meminfo.index = idx;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (!CFE_ISERR(iocb.status)) {
|
|
||||||
*start = iocb.meminfo.addr;
|
|
||||||
*length = iocb.meminfo.size;
|
|
||||||
*type = iocb.meminfo.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_exit(int warm, int status)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
printk("CFE REBOOT\n");
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_RESTART;
|
|
||||||
if (warm)
|
|
||||||
iocb.flags = CFE_FLG_WARMSTART;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_exitstat);
|
|
||||||
iocb.exitstat.status = status;
|
|
||||||
|
|
||||||
printk("CALL\n");
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
printk("DONE\n");
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_flushcache(int flags)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_FLUSHCACHE;
|
|
||||||
iocb.flags = flags;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_getdevinfo(char *name)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_GETINFO;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_buf);
|
|
||||||
iocb.buffer.ptr = PTR_TO_CFE(name);
|
|
||||||
iocb.buffer.length = strlen(name);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.buffer.devflags;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_getenv(char *name, char *dest, int destlen)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
dest[0] = '\0';
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_ENV_GET;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_envbuf);
|
|
||||||
iocb.envbuf.name = PTR_TO_CFE(name);
|
|
||||||
iocb.envbuf.name_len = strlen(name);
|
|
||||||
iocb.envbuf.val = PTR_TO_CFE(dest);
|
|
||||||
iocb.envbuf.val_len = destlen;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_getfwinfo(struct cfe_fwinfo *info)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_GETINFO;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_fwinfo);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
info->version = iocb.fwinfo.version;
|
|
||||||
info->totalmem = iocb.fwinfo.totalmem;
|
|
||||||
info->flags = iocb.fwinfo.flags;
|
|
||||||
info->boardid = iocb.fwinfo.boardid;
|
|
||||||
info->bootarea_va = iocb.fwinfo.bootarea_va;
|
|
||||||
info->bootarea_pa = iocb.fwinfo.bootarea_pa;
|
|
||||||
info->bootarea_size = iocb.fwinfo.bootarea_size;
|
|
||||||
|
|
||||||
return iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_getstdhandle(int handletype)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_GETHANDLE;
|
|
||||||
iocb.flags = handletype;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_getticks(s64 *ticks)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_FW_GETTIME;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_time);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (!CFE_ISERR(iocb.status))
|
|
||||||
*ticks = iocb.time.ticks;
|
|
||||||
|
|
||||||
return iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_inpstat(int handle)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_INPSTAT;
|
|
||||||
iocb.handle = handle;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_inpstat);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.inpstat.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_ioctl(int handle, unsigned int ioctlnum,
|
|
||||||
unsigned char *buffer, int length,
|
|
||||||
int *retlen, u64 offset)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_IOCTL;
|
|
||||||
iocb.handle = handle;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_buf);
|
|
||||||
iocb.buffer.offset = offset;
|
|
||||||
iocb.buffer.ioctlcmd = ioctlnum;
|
|
||||||
iocb.buffer.ptr = PTR_TO_CFE(buffer);
|
|
||||||
iocb.buffer.length = length;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
if (retlen)
|
|
||||||
*retlen = iocb.buffer.retlen;
|
|
||||||
|
|
||||||
return iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_open(char *name)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_OPEN;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_buf);
|
|
||||||
iocb.buffer.ptr = PTR_TO_CFE(name);
|
|
||||||
iocb.buffer.length = strlen(name);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_read(int handle, unsigned char *buffer, int length)
|
|
||||||
{
|
|
||||||
return cfe_readblk(handle, 0, buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_READ;
|
|
||||||
iocb.handle = handle;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_buf);
|
|
||||||
iocb.buffer.offset = offset;
|
|
||||||
iocb.buffer.ptr = PTR_TO_CFE(buffer);
|
|
||||||
iocb.buffer.length = length;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.buffer.retlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_setenv(char *name, char *val)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_ENV_SET;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_envbuf);
|
|
||||||
iocb.envbuf.name = PTR_TO_CFE(name);
|
|
||||||
iocb.envbuf.name_len = strlen(name);
|
|
||||||
iocb.envbuf.val = PTR_TO_CFE(val);
|
|
||||||
iocb.envbuf.val_len = strlen(val);
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
|
|
||||||
return (CFE_ISERR(err)) ? err : iocb.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_write(int handle, unsigned char *buffer, int length)
|
|
||||||
{
|
|
||||||
return cfe_writeblk(handle, 0, buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length)
|
|
||||||
{
|
|
||||||
struct cfe_iocb iocb;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&iocb, 0, sizeof(iocb));
|
|
||||||
iocb.fcode = CFE_CMD_DEV_WRITE;
|
|
||||||
iocb.handle = handle;
|
|
||||||
iocb.psize = sizeof(struct cfe_iocb_buf);
|
|
||||||
iocb.buffer.offset = offset;
|
|
||||||
iocb.buffer.ptr = PTR_TO_CFE(buffer);
|
|
||||||
iocb.buffer.length = length;
|
|
||||||
|
|
||||||
err = cfe_iocb_dispatch(&iocb);
|
|
||||||
if (CFE_ISERR(err))
|
|
||||||
return err;
|
|
||||||
if (CFE_ISERR(iocb.status))
|
|
||||||
return iocb.status;
|
|
||||||
|
|
||||||
return iocb.buffer.retlen;
|
|
||||||
}
|
|
|
@ -1,176 +0,0 @@
|
||||||
/*
|
|
||||||
* Broadcom Common Firmware Environment (CFE) support
|
|
||||||
*
|
|
||||||
* Copyright 2000, 2001, 2002
|
|
||||||
* Broadcom Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006 Michael Buesch
|
|
||||||
*
|
|
||||||
* Original Authors: Mitch Lichtenberg, Chris Demetriou
|
|
||||||
*
|
|
||||||
* This software is furnished under license and may be used and copied only
|
|
||||||
* in accordance with the following terms and conditions. Subject to these
|
|
||||||
* conditions, you may download, copy, install, use, modify and distribute
|
|
||||||
* modified or unmodified copies of this software in source and/or binary
|
|
||||||
* form. No title or ownership is transferred hereby.
|
|
||||||
*
|
|
||||||
* 1) Any source code used, modified or distributed must reproduce and
|
|
||||||
* retain this copyright notice and list of conditions as they appear in
|
|
||||||
* the source file.
|
|
||||||
*
|
|
||||||
* 2) No right is granted to use any trade name, trademark, or logo of
|
|
||||||
* Broadcom Corporation. The "Broadcom Corporation" name may not be
|
|
||||||
* used to endorse or promote products derived from this software
|
|
||||||
* without the prior written permission of Broadcom Corporation.
|
|
||||||
*
|
|
||||||
* 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
|
||||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
|
|
||||||
* FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
|
|
||||||
* LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
||||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
* OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LINUX_CFE_PRIVATE_H_
|
|
||||||
#define LINUX_CFE_PRIVATE_H_
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
|
||||||
|
|
||||||
/* Seal indicating CFE's presence, passed to the kernel. */
|
|
||||||
#define CFE_EPTSEAL 0x43464531
|
|
||||||
|
|
||||||
#define CFE_CMD_FW_GETINFO 0
|
|
||||||
#define CFE_CMD_FW_RESTART 1
|
|
||||||
#define CFE_CMD_FW_BOOT 2
|
|
||||||
#define CFE_CMD_FW_CPUCTL 3
|
|
||||||
#define CFE_CMD_FW_GETTIME 4
|
|
||||||
#define CFE_CMD_FW_MEMENUM 5
|
|
||||||
#define CFE_CMD_FW_FLUSHCACHE 6
|
|
||||||
|
|
||||||
#define CFE_CMD_DEV_GETHANDLE 9
|
|
||||||
#define CFE_CMD_DEV_ENUM 10
|
|
||||||
#define CFE_CMD_DEV_OPEN 11
|
|
||||||
#define CFE_CMD_DEV_INPSTAT 12
|
|
||||||
#define CFE_CMD_DEV_READ 13
|
|
||||||
#define CFE_CMD_DEV_WRITE 14
|
|
||||||
#define CFE_CMD_DEV_IOCTL 15
|
|
||||||
#define CFE_CMD_DEV_CLOSE 16
|
|
||||||
#define CFE_CMD_DEV_GETINFO 17
|
|
||||||
|
|
||||||
#define CFE_CMD_ENV_ENUM 20
|
|
||||||
#define CFE_CMD_ENV_GET 22
|
|
||||||
#define CFE_CMD_ENV_SET 23
|
|
||||||
#define CFE_CMD_ENV_DEL 24
|
|
||||||
|
|
||||||
#define CFE_CMD_MAX 32
|
|
||||||
|
|
||||||
#define CFE_CMD_VENDOR_USE 0x8000 /* codes above this are for customer use */
|
|
||||||
|
|
||||||
typedef u64 cfe_uint_t;
|
|
||||||
typedef s64 cfe_int_t;
|
|
||||||
typedef s64 cfe_ptr_t;
|
|
||||||
|
|
||||||
/* Cast a pointer from native to CFE-API pointer and back */
|
|
||||||
#define CFE_TO_PTR(p) ((void *)(unsigned long)(p))
|
|
||||||
#define PTR_TO_CFE(p) ((cfe_ptr_t)(unsigned long)(p))
|
|
||||||
|
|
||||||
struct cfe_iocb_buf {
|
|
||||||
cfe_uint_t offset; /* offset on device (bytes) */
|
|
||||||
cfe_ptr_t ptr; /* pointer to a buffer */
|
|
||||||
cfe_uint_t length; /* length of this buffer */
|
|
||||||
cfe_uint_t retlen; /* returned length (for read ops) */
|
|
||||||
union {
|
|
||||||
cfe_uint_t ioctlcmd; /* IOCTL command (used only for IOCTLs) */
|
|
||||||
cfe_uint_t devflags; /* Returned device info flags */
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_inpstat {
|
|
||||||
cfe_uint_t status; /* 1 means input available */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_envbuf {
|
|
||||||
cfe_int_t index; /* 0-based enumeration index */
|
|
||||||
cfe_ptr_t name; /* name string buffer */
|
|
||||||
cfe_int_t name_len; /* size of name buffer */
|
|
||||||
cfe_ptr_t val; /* value string buffer */
|
|
||||||
cfe_int_t val_len; /* size of value string buffer */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_cpuctl {
|
|
||||||
cfe_uint_t number; /* cpu number to control */
|
|
||||||
cfe_uint_t command; /* command to issue to CPU */
|
|
||||||
cfe_uint_t start_addr; /* CPU start address */
|
|
||||||
cfe_uint_t gp; /* starting GP value */
|
|
||||||
cfe_uint_t sp; /* starting SP value */
|
|
||||||
cfe_uint_t a1; /* starting A1 value */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_time {
|
|
||||||
cfe_int_t ticks; /* current time in ticks */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_exitstat {
|
|
||||||
cfe_int_t status;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_meminfo {
|
|
||||||
cfe_int_t index; /* 0-based enumeration index */
|
|
||||||
cfe_int_t type; /* type of memory block */
|
|
||||||
cfe_uint_t addr; /* physical start address */
|
|
||||||
cfe_uint_t size; /* block size */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cfe_iocb_fwinfo {
|
|
||||||
cfe_int_t version; /* major, minor, eco version */
|
|
||||||
cfe_int_t totalmem; /* total installed mem */
|
|
||||||
cfe_int_t flags; /* various flags */
|
|
||||||
cfe_int_t boardid; /* board ID */
|
|
||||||
cfe_int_t bootarea_va; /* VA of boot area */
|
|
||||||
cfe_int_t bootarea_pa; /* PA of boot area */
|
|
||||||
cfe_int_t bootarea_size; /* size of boot area */
|
|
||||||
cfe_int_t reserved1;
|
|
||||||
cfe_int_t reserved2;
|
|
||||||
cfe_int_t reserved3;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* CFE I/O Control Block */
|
|
||||||
struct cfe_iocb {
|
|
||||||
cfe_uint_t fcode; /* IOCB function code */
|
|
||||||
cfe_int_t status; /* return status */
|
|
||||||
cfe_int_t handle; /* file/device handle */
|
|
||||||
cfe_uint_t flags; /* flags for this IOCB */
|
|
||||||
cfe_uint_t psize; /* size of parameter list */
|
|
||||||
union {
|
|
||||||
struct cfe_iocb_buf buffer; /* buffer parameters */
|
|
||||||
struct cfe_iocb_inpstat inpstat; /* input status parameters */
|
|
||||||
struct cfe_iocb_envbuf envbuf; /* environment function parameters */
|
|
||||||
struct cfe_iocb_cpuctl cpuctl; /* CPU control parameters */
|
|
||||||
struct cfe_iocb_time time; /* timer parameters */
|
|
||||||
struct cfe_iocb_meminfo meminfo; /* memory arena info parameters */
|
|
||||||
struct cfe_iocb_fwinfo fwinfo; /* firmware information */
|
|
||||||
struct cfe_iocb_exitstat exitstat; /* Exit Status */
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
|
||||||
|
|
||||||
void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
|
|
||||||
unsigned long fwarg2, unsigned long fwarg3);
|
|
||||||
|
|
||||||
#else /* __ASSEMBLY__ */
|
|
||||||
|
|
||||||
.macro cfe_early_init
|
|
||||||
#ifdef CONFIG_CFE
|
|
||||||
jal cfe_setup
|
|
||||||
#endif
|
|
||||||
.endm
|
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
|
||||||
#endif /* LINUX_CFE_PRIVATE_H_ */
|
|
|
@ -76,11 +76,11 @@ struct trx_header {
|
||||||
#define BUSWIDTH 2
|
#define BUSWIDTH 2
|
||||||
|
|
||||||
#ifdef CONFIG_SSB
|
#ifdef CONFIG_SSB
|
||||||
extern struct ssb_bus ssb;
|
extern struct ssb_bus ssb_bcm47xx;
|
||||||
#endif
|
#endif
|
||||||
static struct mtd_info *bcm947xx_mtd;
|
static struct mtd_info *bcm47xx_mtd;
|
||||||
|
|
||||||
static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
|
static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
|
||||||
{
|
{
|
||||||
if (len==1) {
|
if (len==1) {
|
||||||
memcpy_fromio(to, map->virt + from, len);
|
memcpy_fromio(to, map->virt + from, len);
|
||||||
|
@ -96,7 +96,7 @@ static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct map_info bcm947xx_map = {
|
static struct map_info bcm47xx_map = {
|
||||||
name: "Physically mapped flash",
|
name: "Physically mapped flash",
|
||||||
size: WINDOW_SIZE,
|
size: WINDOW_SIZE,
|
||||||
bankwidth: BUSWIDTH,
|
bankwidth: BUSWIDTH,
|
||||||
|
@ -105,7 +105,7 @@ static struct map_info bcm947xx_map = {
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_PARTITIONS
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
|
|
||||||
static struct mtd_partition bcm947xx_parts[] = {
|
static struct mtd_partition bcm47xx_parts[] = {
|
||||||
{ name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
|
{ name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
|
||||||
{ name: "linux", offset: 0, size: 0, },
|
{ name: "linux", offset: 0, size: 0, },
|
||||||
{ name: "rootfs", offset: 0, size: 0, },
|
{ name: "rootfs", offset: 0, size: 0, },
|
||||||
|
@ -323,46 +323,46 @@ init_mtd_partitions(struct mtd_info *mtd, size_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* boot loader */
|
/* boot loader */
|
||||||
bcm947xx_parts[0].offset = 0;
|
bcm47xx_parts[0].offset = 0;
|
||||||
bcm947xx_parts[0].size = cfe_size;
|
bcm47xx_parts[0].size = cfe_size;
|
||||||
|
|
||||||
/* nvram */
|
/* nvram */
|
||||||
if (cfe_size != 384 * 1024) {
|
if (cfe_size != 384 * 1024) {
|
||||||
bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
||||||
bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
||||||
} else {
|
} else {
|
||||||
/* nvram (old 128kb config partition on netgear wgt634u) */
|
/* nvram (old 128kb config partition on netgear wgt634u) */
|
||||||
bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
|
bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
|
||||||
bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
bcm47xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* linux (kernel and rootfs) */
|
/* linux (kernel and rootfs) */
|
||||||
if (cfe_size != 384 * 1024) {
|
if (cfe_size != 384 * 1024) {
|
||||||
bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
|
bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
|
||||||
bcm947xx_parts[1].size = bcm947xx_parts[3].offset -
|
bcm47xx_parts[1].size = bcm47xx_parts[3].offset -
|
||||||
bcm947xx_parts[1].offset;
|
bcm47xx_parts[1].offset;
|
||||||
} else {
|
} else {
|
||||||
/* do not count the elf loader, which is on one block */
|
/* do not count the elf loader, which is on one block */
|
||||||
bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
|
bcm47xx_parts[1].offset = bcm47xx_parts[0].size +
|
||||||
bcm947xx_parts[3].size + mtd->erasesize;
|
bcm47xx_parts[3].size + mtd->erasesize;
|
||||||
bcm947xx_parts[1].size = size -
|
bcm47xx_parts[1].size = size -
|
||||||
bcm947xx_parts[0].size -
|
bcm47xx_parts[0].size -
|
||||||
(2*bcm947xx_parts[3].size) -
|
(2*bcm47xx_parts[3].size) -
|
||||||
mtd->erasesize;
|
mtd->erasesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find and size rootfs */
|
/* find and size rootfs */
|
||||||
find_root(mtd,size,&bcm947xx_parts[2]);
|
find_root(mtd,size,&bcm47xx_parts[2]);
|
||||||
bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset - bcm947xx_parts[3].size;
|
bcm47xx_parts[2].size = size - bcm47xx_parts[2].offset - bcm47xx_parts[3].size;
|
||||||
|
|
||||||
return bcm947xx_parts;
|
return bcm47xx_parts;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int __init init_bcm947xx_map(void)
|
int __init init_bcm47xx_map(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SSB
|
#ifdef CONFIG_SSB
|
||||||
struct ssb_mipscore *mcore = &ssb.mipscore;
|
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
|
||||||
#endif
|
#endif
|
||||||
size_t size;
|
size_t size;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -376,40 +376,40 @@ int __init init_bcm947xx_map(void)
|
||||||
u32 window_size = mcore->flash_window_size;
|
u32 window_size = mcore->flash_window_size;
|
||||||
|
|
||||||
printk("flash init: 0x%08x 0x%08x\n", window, window_size);
|
printk("flash init: 0x%08x 0x%08x\n", window, window_size);
|
||||||
bcm947xx_map.phys = window;
|
bcm47xx_map.phys = window;
|
||||||
bcm947xx_map.size = window_size;
|
bcm47xx_map.size = window_size;
|
||||||
bcm947xx_map.virt = ioremap_nocache(window, window_size);
|
bcm47xx_map.virt = ioremap_nocache(window, window_size);
|
||||||
#else
|
#else
|
||||||
printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
|
printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
|
||||||
bcm947xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
|
bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!bcm947xx_map.virt) {
|
if (!bcm47xx_map.virt) {
|
||||||
printk("Failed to ioremap\n");
|
printk("Failed to ioremap\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_map_init(&bcm947xx_map);
|
simple_map_init(&bcm47xx_map);
|
||||||
|
|
||||||
if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
|
if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) {
|
||||||
printk("Failed to do_map_probe\n");
|
printk("Failed to do_map_probe\n");
|
||||||
iounmap((void *)bcm947xx_map.virt);
|
iounmap((void *)bcm47xx_map.virt);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override copy_from routine */
|
/* override copy_from routine */
|
||||||
bcm947xx_map.copy_from = bcm947xx_map_copy_from;
|
bcm47xx_map.copy_from = bcm47xx_map_copy_from;
|
||||||
|
|
||||||
bcm947xx_mtd->owner = THIS_MODULE;
|
bcm47xx_mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
size = bcm947xx_mtd->size;
|
size = bcm47xx_mtd->size;
|
||||||
|
|
||||||
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
|
printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
|
||||||
|
|
||||||
#ifdef CONFIG_MTD_PARTITIONS
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
parts = init_mtd_partitions(bcm947xx_mtd, size);
|
parts = init_mtd_partitions(bcm47xx_mtd, size);
|
||||||
for (i = 0; parts[i].name; i++);
|
for (i = 0; parts[i].name; i++);
|
||||||
ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
|
ret = add_mtd_partitions(bcm47xx_mtd, parts, i);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
|
printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -418,22 +418,22 @@ int __init init_bcm947xx_map(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (bcm947xx_mtd)
|
if (bcm47xx_mtd)
|
||||||
map_destroy(bcm947xx_mtd);
|
map_destroy(bcm47xx_mtd);
|
||||||
if (bcm947xx_map.virt)
|
if (bcm47xx_map.virt)
|
||||||
iounmap((void *)bcm947xx_map.virt);
|
iounmap((void *)bcm47xx_map.virt);
|
||||||
bcm947xx_map.virt = 0;
|
bcm47xx_map.virt = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit cleanup_bcm947xx_map(void)
|
void __exit cleanup_bcm47xx_map(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_MTD_PARTITIONS
|
#ifdef CONFIG_MTD_PARTITIONS
|
||||||
del_mtd_partitions(bcm947xx_mtd);
|
del_mtd_partitions(bcm47xx_mtd);
|
||||||
#endif
|
#endif
|
||||||
map_destroy(bcm947xx_mtd);
|
map_destroy(bcm47xx_mtd);
|
||||||
iounmap((void *)bcm947xx_map.virt);
|
iounmap((void *)bcm47xx_map.virt);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(init_bcm947xx_map);
|
module_init(init_bcm47xx_map);
|
||||||
module_exit(cleanup_bcm947xx_map);
|
module_exit(cleanup_bcm47xx_map);
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
* Broadcom Common Firmware Environment (CFE) support
|
|
||||||
*
|
|
||||||
* Copyright 2000, 2001, 2002
|
|
||||||
* Broadcom Corporation. All rights reserved.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006 Michael Buesch
|
|
||||||
*
|
|
||||||
* Original Authors: Mitch Lichtenberg, Chris Demetriou
|
|
||||||
*
|
|
||||||
* This software is furnished under license and may be used and copied only
|
|
||||||
* in accordance with the following terms and conditions. Subject to these
|
|
||||||
* conditions, you may download, copy, install, use, modify and distribute
|
|
||||||
* modified or unmodified copies of this software in source and/or binary
|
|
||||||
* form. No title or ownership is transferred hereby.
|
|
||||||
*
|
|
||||||
* 1) Any source code used, modified or distributed must reproduce and
|
|
||||||
* retain this copyright notice and list of conditions as they appear in
|
|
||||||
* the source file.
|
|
||||||
*
|
|
||||||
* 2) No right is granted to use any trade name, trademark, or logo of
|
|
||||||
* Broadcom Corporation. The "Broadcom Corporation" name may not be
|
|
||||||
* used to endorse or promote products derived from this software
|
|
||||||
* without the prior written permission of Broadcom Corporation.
|
|
||||||
*
|
|
||||||
* 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
|
||||||
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
|
|
||||||
* FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
|
|
||||||
* LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
||||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
* OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LINUX_CFE_API_H_
|
|
||||||
#define LINUX_CFE_API_H_
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define CFE_MI_RESERVED 0 /* memory is reserved, do not use */
|
|
||||||
#define CFE_MI_AVAILABLE 1 /* memory is available */
|
|
||||||
|
|
||||||
#define CFE_FLG_WARMSTART 0x00000001
|
|
||||||
#define CFE_FLG_FULL_ARENA 0x00000001
|
|
||||||
#define CFE_FLG_ENV_PERMANENT 0x00000001
|
|
||||||
|
|
||||||
#define CFE_CPU_CMD_START 1
|
|
||||||
#define CFE_CPU_CMD_STOP 0
|
|
||||||
|
|
||||||
#define CFE_STDHANDLE_CONSOLE 0
|
|
||||||
|
|
||||||
#define CFE_DEV_NETWORK 1
|
|
||||||
#define CFE_DEV_DISK 2
|
|
||||||
#define CFE_DEV_FLASH 3
|
|
||||||
#define CFE_DEV_SERIAL 4
|
|
||||||
#define CFE_DEV_CPU 5
|
|
||||||
#define CFE_DEV_NVRAM 6
|
|
||||||
#define CFE_DEV_CLOCK 7
|
|
||||||
#define CFE_DEV_OTHER 8
|
|
||||||
#define CFE_DEV_MASK 0x0F
|
|
||||||
|
|
||||||
#define CFE_CACHE_FLUSH_D 1
|
|
||||||
#define CFE_CACHE_INVAL_I 2
|
|
||||||
#define CFE_CACHE_INVAL_D 4
|
|
||||||
#define CFE_CACHE_INVAL_L2 8
|
|
||||||
|
|
||||||
#define CFE_FWI_64BIT 0x00000001
|
|
||||||
#define CFE_FWI_32BIT 0x00000002
|
|
||||||
#define CFE_FWI_RELOC 0x00000004
|
|
||||||
#define CFE_FWI_UNCACHED 0x00000008
|
|
||||||
#define CFE_FWI_MULTICPU 0x00000010
|
|
||||||
#define CFE_FWI_FUNCSIM 0x00000020
|
|
||||||
#define CFE_FWI_RTLSIM 0x00000040
|
|
||||||
|
|
||||||
struct cfe_fwinfo {
|
|
||||||
s64 version; /* major, minor, eco version */
|
|
||||||
s64 totalmem; /* total installed mem */
|
|
||||||
s64 flags; /* various flags */
|
|
||||||
s64 boardid; /* board ID */
|
|
||||||
s64 bootarea_va; /* VA of boot area */
|
|
||||||
s64 bootarea_pa; /* PA of boot area */
|
|
||||||
s64 bootarea_size; /* size of boot area */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* The public CFE API */
|
|
||||||
|
|
||||||
int cfe_present(void); /* Check if we booted from CFE. Returns bool */
|
|
||||||
|
|
||||||
int cfe_getticks(s64 *ticks);
|
|
||||||
int cfe_close(int handle);
|
|
||||||
int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1);
|
|
||||||
int cfe_cpu_stop(int cpu);
|
|
||||||
int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen);
|
|
||||||
int cfe_enumdev(int idx, char *name, int namelen);
|
|
||||||
int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
|
|
||||||
u64 *type);
|
|
||||||
int cfe_exit(int warm, int status);
|
|
||||||
int cfe_flushcache(int flags);
|
|
||||||
int cfe_getdevinfo(char *name);
|
|
||||||
int cfe_getenv(char *name, char *dest, int destlen);
|
|
||||||
int cfe_getfwinfo(struct cfe_fwinfo *info);
|
|
||||||
int cfe_getstdhandle(int handletype);
|
|
||||||
int cfe_inpstat(int handle);
|
|
||||||
int cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
|
|
||||||
int length, int *retlen, u64 offset);
|
|
||||||
int cfe_open(char *name);
|
|
||||||
int cfe_read(int handle, unsigned char *buffer, int length);
|
|
||||||
int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length);
|
|
||||||
int cfe_setenv(char *name, char *val);
|
|
||||||
int cfe_write(int handle, unsigned char *buffer, int length);
|
|
||||||
int cfe_writeblk(int handle, s64 offset, unsigned char *buffer,
|
|
||||||
int length);
|
|
||||||
|
|
||||||
|
|
||||||
/* High level API */
|
|
||||||
|
|
||||||
/* Print some information to CFE's console (most likely serial line) */
|
|
||||||
int cfe_printk(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
|
||||||
int cfe_vprintk(const char *fmt, va_list args);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Error codes returned by the low API functions */
|
|
||||||
|
|
||||||
#define CFE_ISERR(errcode) (errcode < 0)
|
|
||||||
|
|
||||||
#define CFE_OK 0
|
|
||||||
#define CFE_ERR -1 /* generic error */
|
|
||||||
#define CFE_ERR_INV_COMMAND -2
|
|
||||||
#define CFE_ERR_EOF -3
|
|
||||||
#define CFE_ERR_IOERR -4
|
|
||||||
#define CFE_ERR_NOMEM -5
|
|
||||||
#define CFE_ERR_DEVNOTFOUND -6
|
|
||||||
#define CFE_ERR_DEVOPEN -7
|
|
||||||
#define CFE_ERR_INV_PARAM -8
|
|
||||||
#define CFE_ERR_ENVNOTFOUND -9
|
|
||||||
#define CFE_ERR_ENVREADONLY -10
|
|
||||||
|
|
||||||
#define CFE_ERR_NOTELF -11
|
|
||||||
#define CFE_ERR_NOT32BIT -12
|
|
||||||
#define CFE_ERR_WRONGENDIAN -13
|
|
||||||
#define CFE_ERR_BADELFVERS -14
|
|
||||||
#define CFE_ERR_NOTMIPS -15
|
|
||||||
#define CFE_ERR_BADELFFMT -16
|
|
||||||
#define CFE_ERR_BADADDR -17
|
|
||||||
|
|
||||||
#define CFE_ERR_FILENOTFOUND -18
|
|
||||||
#define CFE_ERR_UNSUPPORTED -19
|
|
||||||
|
|
||||||
#define CFE_ERR_HOSTUNKNOWN -20
|
|
||||||
|
|
||||||
#define CFE_ERR_TIMEOUT -21
|
|
||||||
|
|
||||||
#define CFE_ERR_PROTOCOLERR -22
|
|
||||||
|
|
||||||
#define CFE_ERR_NETDOWN -23
|
|
||||||
#define CFE_ERR_NONAMESERVER -24
|
|
||||||
|
|
||||||
#define CFE_ERR_NOHANDLES -25
|
|
||||||
#define CFE_ERR_ALREADYBOUND -26
|
|
||||||
|
|
||||||
#define CFE_ERR_CANNOTSET -27
|
|
||||||
#define CFE_ERR_NOMORE -28
|
|
||||||
#define CFE_ERR_BADFILESYS -29
|
|
||||||
#define CFE_ERR_FSNOTAVAIL -30
|
|
||||||
|
|
||||||
#define CFE_ERR_INVBOOTBLOCK -31
|
|
||||||
#define CFE_ERR_WRONGDEVTYPE -32
|
|
||||||
#define CFE_ERR_BBCHECKSUM -33
|
|
||||||
#define CFE_ERR_BOOTPROGCHKSUM -34
|
|
||||||
|
|
||||||
#define CFE_ERR_LDRNOTAVAIL -35
|
|
||||||
|
|
||||||
#define CFE_ERR_NOTREADY -36
|
|
||||||
|
|
||||||
#define CFE_ERR_GETMEM -37
|
|
||||||
#define CFE_ERR_SETMEM -38
|
|
||||||
|
|
||||||
#define CFE_ERR_NOTCONN -39
|
|
||||||
#define CFE_ERR_ADDRINUSE -40
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LINUX_CFE_API_H_ */
|
|
|
@ -1,67 +0,0 @@
|
||||||
#ifndef __BCM947XX_GPIO_H
|
|
||||||
#define __BCM947XX_GPIO_H
|
|
||||||
|
|
||||||
#include <linux/ssb/ssb_embedded.h>
|
|
||||||
|
|
||||||
extern struct ssb_bus ssb;
|
|
||||||
|
|
||||||
static inline int gpio_request(unsigned gpio, const char *label)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpio_free(unsigned gpio)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int gpio_direction_input(unsigned gpio)
|
|
||||||
{
|
|
||||||
ssb_gpio_outen(&ssb, 1 << gpio, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
|
||||||
{
|
|
||||||
ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0));
|
|
||||||
ssb_gpio_outen(&ssb, 1 << gpio, 1 << gpio);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int gpio_to_irq(unsigned gpio)
|
|
||||||
{
|
|
||||||
struct ssb_device *dev;
|
|
||||||
|
|
||||||
dev = ssb.chipco.dev;
|
|
||||||
if (!dev)
|
|
||||||
dev = ssb.extif.dev;
|
|
||||||
if (!dev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return ssb_mips_irq(dev) + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int irq_to_gpio(unsigned gpio)
|
|
||||||
{
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int gpio_get_value(unsigned gpio)
|
|
||||||
{
|
|
||||||
return !!ssb_gpio_in(&ssb, 1 << gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int gpio_set_value(unsigned gpio, int value)
|
|
||||||
{
|
|
||||||
ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* cansleep wrappers */
|
|
||||||
#include <asm-generic/gpio.h>
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __BCM947XX_GPIO_H */
|
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:06.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:08.000000000 +0100
|
|
||||||
@@ -39,12 +39,14 @@ static inline void chipco_write32(struct
|
|
||||||
ssb_write32(cc->dev, offset, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
|
|
||||||
- u32 mask, u32 value)
|
|
||||||
+static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
|
|
||||||
+ u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
value &= mask;
|
|
||||||
value |= chipco_read32(cc, offset) & ~mask;
|
|
||||||
chipco_write32(cc, offset, value);
|
|
||||||
+
|
|
||||||
+ return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
|
|
||||||
@@ -355,16 +357,37 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco
|
|
||||||
{
|
|
||||||
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_in);
|
|
||||||
+
|
|
||||||
+u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_out);
|
|
||||||
+
|
|
||||||
+u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_outen);
|
|
||||||
+
|
|
||||||
+u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_control);
|
|
||||||
|
|
||||||
-void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
+u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
|
|
||||||
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_intmask);
|
|
||||||
|
|
||||||
-void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
+u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
- chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
|
|
||||||
+ return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_chipco_gpio_polarity);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 14:37:06.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 14:37:08.000000000 +0100
|
|
||||||
@@ -27,12 +27,14 @@ static inline void extif_write32(struct
|
|
||||||
ssb_write32(extif->dev, offset, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
|
|
||||||
- u32 mask, u32 value)
|
|
||||||
+static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset,
|
|
||||||
+ u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
value &= mask;
|
|
||||||
value |= extif_read32(extif, offset) & ~mask;
|
|
||||||
extif_write32(extif, offset, value);
|
|
||||||
+
|
|
||||||
+ return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
@@ -114,16 +116,30 @@ u32 ssb_extif_gpio_in(struct ssb_extif *
|
|
||||||
{
|
|
||||||
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_extif_gpio_in);
|
|
||||||
|
|
||||||
-void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
+u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
|
|
||||||
mask, value);
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_extif_gpio_out);
|
|
||||||
|
|
||||||
-void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
+u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
|
|
||||||
mask, value);
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ssb_extif_gpio_outen);
|
|
||||||
+
|
|
||||||
+u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_extif_gpio_polarity);
|
|
||||||
|
|
||||||
+u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_extif_gpio_intmask);
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:06.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:08.000000000 +0100
|
|
||||||
@@ -382,11 +382,13 @@ extern void ssb_chipco_set_clockmode(str
|
|
||||||
extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
|
|
||||||
u32 ticks);
|
|
||||||
|
|
||||||
+/* Chipcommon GPIO pin access. */
|
|
||||||
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask);
|
|
||||||
-
|
|
||||||
-void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
-
|
|
||||||
-void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
+u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
+u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
+u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
+u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
+u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h 2008-02-19 14:37:06.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h 2008-02-19 14:37:08.000000000 +0100
|
|
||||||
@@ -171,11 +171,12 @@ extern void ssb_extif_get_clockcontrol(s
|
|
||||||
extern void ssb_extif_timing_init(struct ssb_extif *extif,
|
|
||||||
unsigned long ns);
|
|
||||||
|
|
||||||
+/* Extif GPIO pin access */
|
|
||||||
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
|
|
||||||
-
|
|
||||||
-void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
-
|
|
||||||
-void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
+u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
+u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
+u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
+u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
extern int ssb_extif_serial_init(struct ssb_extif *extif,
|
|
|
@ -1,154 +1,33 @@
|
||||||
Index: linux-2.6.23/arch/mips/Kconfig
|
Index: linux-2.6.25/arch/mips/Kconfig
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:06.662507926 +0200
|
--- linux-2.6.25.orig/arch/mips/Kconfig 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200
|
+++ linux-2.6.25/arch/mips/Kconfig 2008-04-26 22:08:17.000000000 +0100
|
||||||
@@ -4,6 +4,10 @@
|
@@ -50,8 +50,10 @@ config BCM47XX
|
||||||
# Horrible source of confusion. Die, die, die ...
|
select SYS_SUPPORTS_32BIT_KERNEL
|
||||||
select EMBEDDED
|
select SYS_SUPPORTS_LITTLE_ENDIAN
|
||||||
|
select SSB
|
||||||
+config CFE
|
|
||||||
+ bool
|
|
||||||
+ # Common Firmware Environment
|
|
||||||
+
|
|
||||||
mainmenu "Linux/MIPS Kernel Configuration"
|
|
||||||
|
|
||||||
menu "Machine selection"
|
|
||||||
@@ -44,6 +48,23 @@
|
|
||||||
note that a kernel built with this option selected will not be
|
|
||||||
able to run on normal units.
|
|
||||||
|
|
||||||
+config BCM947XX
|
|
||||||
+ bool "Support for BCM947xx based boards"
|
|
||||||
+ select DMA_NONCOHERENT
|
|
||||||
+ select HW_HAS_PCI
|
|
||||||
+ select IRQ_CPU
|
|
||||||
+ select SYS_HAS_CPU_MIPS32_R1
|
|
||||||
+ select SYS_SUPPORTS_32BIT_KERNEL
|
|
||||||
+ select SYS_SUPPORTS_LITTLE_ENDIAN
|
|
||||||
+ select SSB
|
|
||||||
+ select SSB_SERIAL
|
+ select SSB_SERIAL
|
||||||
|
select SSB_DRIVER_MIPS
|
||||||
|
select SSB_DRIVER_EXTIF
|
||||||
+ select SSB_DRIVER_PCICORE
|
+ select SSB_DRIVER_PCICORE
|
||||||
+ select SSB_PCICORE_HOSTMODE
|
select SSB_PCICORE_HOSTMODE if PCI
|
||||||
+ select CFE
|
select GENERIC_GPIO
|
||||||
+ select GENERIC_GPIO
|
select SYS_HAS_EARLY_PRINTK
|
||||||
+ help
|
@@ -790,6 +792,7 @@ config CSRC_SB1250
|
||||||
+ Support for BCM947xx based boards
|
|
||||||
+
|
|
||||||
config MIPS_COBALT
|
|
||||||
bool "Cobalt Server"
|
|
||||||
select DMA_NONCOHERENT
|
|
||||||
Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:06.666508151 +0200
|
|
||||||
+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200
|
|
||||||
@@ -793,6 +793,28 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
|
config CFE
|
||||||
|
bool
|
||||||
|
+ # Common Firmware Environment
|
||||||
|
|
||||||
+static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
|
config DMA_COHERENT
|
||||||
+{
|
bool
|
||||||
+ decode_config1(c);
|
Index: linux-2.6.25/include/asm-mips/bootinfo.h
|
||||||
+ switch (c->processor_id & 0xff00) {
|
|
||||||
+ case PRID_IMP_BCM3302:
|
|
||||||
+ c->cputype = CPU_BCM3302;
|
|
||||||
+ c->isa_level = MIPS_CPU_ISA_M32R1;
|
|
||||||
+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
|
|
||||||
+ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
|
|
||||||
+ break;
|
|
||||||
+ case PRID_IMP_BCM4710:
|
|
||||||
+ c->cputype = CPU_BCM4710;
|
|
||||||
+ c->isa_level = MIPS_CPU_ISA_M32R1;
|
|
||||||
+ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
|
|
||||||
+ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ c->cputype = CPU_UNKNOWN;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
__init void cpu_probe(void)
|
|
||||||
{
|
|
||||||
struct cpuinfo_mips *c = ¤t_cpu_data;
|
|
||||||
@@ -815,6 +837,9 @@
|
|
||||||
case PRID_COMP_SIBYTE:
|
|
||||||
cpu_probe_sibyte(c);
|
|
||||||
break;
|
|
||||||
+ case PRID_COMP_BROADCOM:
|
|
||||||
+ cpu_probe_broadcom(c);
|
|
||||||
+ break;
|
|
||||||
case PRID_COMP_SANDCRAFT:
|
|
||||||
cpu_probe_sandcraft(c);
|
|
||||||
break;
|
|
||||||
Index: linux-2.6.23/arch/mips/kernel/proc.c
|
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/kernel/proc.c 2007-10-13 02:23:06.678508839 +0200
|
--- linux-2.6.25.orig/include/asm-mips/bootinfo.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/kernel/proc.c 2007-10-13 02:23:11.210767122 +0200
|
+++ linux-2.6.25/include/asm-mips/bootinfo.h 2008-04-26 21:57:10.000000000 +0100
|
||||||
@@ -82,6 +82,8 @@
|
@@ -94,6 +94,12 @@
|
||||||
[CPU_VR4181] = "NEC VR4181",
|
#define MACH_MSP7120_FPGA 5 /* PMC-Sierra MSP7120 Emulation */
|
||||||
[CPU_VR4181A] = "NEC VR4181A",
|
#define MACH_MSP_OTHER 255 /* PMC-Sierra unknown board type */
|
||||||
[CPU_SR71000] = "Sandcraft SR71000",
|
|
||||||
+ [CPU_BCM3302] = "Broadcom BCM3302",
|
|
||||||
+ [CPU_BCM4710] = "Broadcom BCM4710",
|
|
||||||
[CPU_PR4450] = "Philips PR4450",
|
|
||||||
[CPU_LOONGSON2] = "ICT Loongson-2",
|
|
||||||
};
|
|
||||||
Index: linux-2.6.23/arch/mips/Makefile
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/arch/mips/Makefile 2007-10-13 02:23:06.682509066 +0200
|
|
||||||
+++ linux-2.6.23/arch/mips/Makefile 2007-10-13 02:23:11.210767122 +0200
|
|
||||||
@@ -533,6 +533,18 @@
|
|
||||||
load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
|
|
||||||
|
|
||||||
#
|
|
||||||
+# Broadcom BCM47XX boards
|
|
||||||
+#
|
|
||||||
+core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/
|
|
||||||
+cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include -Iinclude/asm-mips/mach-bcm947xx
|
|
||||||
+load-$(CONFIG_BCM947XX) := 0xffffffff80001000
|
|
||||||
+
|
|
||||||
+#
|
|
||||||
+# Common Firmware Environment
|
|
||||||
+#
|
|
||||||
+core-$(CONFIG_CFE) += arch/mips/cfe/
|
|
||||||
+
|
|
||||||
+#
|
|
||||||
# SNI RM
|
|
||||||
#
|
|
||||||
core-$(CONFIG_SNI_RM) += arch/mips/sni/
|
|
||||||
Index: linux-2.6.23/arch/mips/mm/tlbex.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 02:23:06.694509748 +0200
|
|
||||||
+++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 02:26:00.272401391 +0200
|
|
||||||
@@ -895,6 +895,8 @@
|
|
||||||
case CPU_AU1550:
|
|
||||||
case CPU_AU1200:
|
|
||||||
case CPU_PR4450:
|
|
||||||
+ case CPU_BCM3302:
|
|
||||||
+ case CPU_BCM4710:
|
|
||||||
i_nop(p);
|
|
||||||
tlbw(p);
|
|
||||||
break;
|
|
||||||
Index: linux-2.6.23/drivers/Kconfig
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/drivers/Kconfig 2007-10-13 02:23:06.702510206 +0200
|
|
||||||
+++ linux-2.6.23/drivers/Kconfig 2007-10-13 02:23:11.214767346 +0200
|
|
||||||
@@ -58,6 +58,8 @@
|
|
||||||
|
|
||||||
source "drivers/hwmon/Kconfig"
|
|
||||||
|
|
||||||
+source "drivers/ssb/Kconfig"
|
|
||||||
+
|
|
||||||
source "drivers/mfd/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/media/Kconfig"
|
|
||||||
Index: linux-2.6.23/include/asm-mips/bootinfo.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/include/asm-mips/bootinfo.h 2007-10-13 02:23:06.718511119 +0200
|
|
||||||
+++ linux-2.6.23/include/asm-mips/bootinfo.h 2007-10-13 02:23:11.214767346 +0200
|
|
||||||
@@ -208,6 +208,12 @@
|
|
||||||
#define MACH_GROUP_WINDRIVER 28 /* Windriver boards */
|
|
||||||
#define MACH_WRPPMC 1
|
|
||||||
|
|
||||||
+/*
|
+/*
|
||||||
+ * Valid machtype for group Broadcom
|
+ * Valid machtype for group Broadcom
|
||||||
|
@ -158,51 +37,12 @@ Index: linux-2.6.23/include/asm-mips/bootinfo.h
|
||||||
+
|
+
|
||||||
#define CL_SIZE COMMAND_LINE_SIZE
|
#define CL_SIZE COMMAND_LINE_SIZE
|
||||||
|
|
||||||
const char *get_system_type(void);
|
extern char *system_type;
|
||||||
Index: linux-2.6.23/include/asm-mips/cpu.h
|
Index: linux-2.6.25/include/linux/pci_ids.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/cpu.h 2007-10-13 02:23:06.726511570 +0200
|
--- linux-2.6.25.orig/include/linux/pci_ids.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/cpu.h 2007-10-13 02:27:43.994312161 +0200
|
+++ linux-2.6.25/include/linux/pci_ids.h 2008-04-26 21:57:10.000000000 +0100
|
||||||
@@ -106,6 +106,13 @@
|
@@ -2000,6 +2000,7 @@
|
||||||
#define PRID_IMP_SR71000 0x0400
|
|
||||||
|
|
||||||
/*
|
|
||||||
+ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define PRID_IMP_BCM4710 0x4000
|
|
||||||
+#define PRID_IMP_BCM3302 0x9000
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
* Definitions for 7:0 on legacy processors
|
|
||||||
*/
|
|
||||||
|
|
||||||
@@ -217,8 +224,10 @@
|
|
||||||
#define CPU_R14000 64
|
|
||||||
#define CPU_LOONGSON1 65
|
|
||||||
#define CPU_LOONGSON2 66
|
|
||||||
+#define CPU_BCM3302 67
|
|
||||||
+#define CPU_BCM4710 68
|
|
||||||
|
|
||||||
-#define CPU_LAST 66
|
|
||||||
+#define CPU_LAST 68
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ISA Level encodings
|
|
||||||
Index: linux-2.6.23.1/drivers/Makefile
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.1.orig/drivers/Makefile 2008-01-27 04:34:31.000000000 +0100
|
|
||||||
+++ linux-2.6.23.1/drivers/Makefile 2008-01-27 04:39:57.000000000 +0100
|
|
||||||
@@ -89,3 +89,4 @@
|
|
||||||
obj-$(CONFIG_PPC_PS3) += ps3/
|
|
||||||
obj-$(CONFIG_OF) += of/
|
|
||||||
obj-$(CONFIG_GPIO_DEVICE) += gpio/
|
|
||||||
+obj-$(CONFIG_SSB) += ssb/
|
|
||||||
Index: linux-2.6.23.1/include/linux/pci_ids.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.1.orig/include/linux/pci_ids.h 2008-01-27 04:55:18.000000000 +0100
|
|
||||||
+++ linux-2.6.23.1/include/linux/pci_ids.h 2008-01-27 04:55:22.000000000 +0100
|
|
||||||
@@ -1972,6 +1972,7 @@
|
|
||||||
#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
|
#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
|
||||||
#define PCI_DEVICE_ID_BCM4401 0x4401
|
#define PCI_DEVICE_ID_BCM4401 0x4401
|
||||||
#define PCI_DEVICE_ID_BCM4401B0 0x4402
|
#define PCI_DEVICE_ID_BCM4401B0 0x4402
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
Index: linux-2.6.23/drivers/mtd/maps/Kconfig
|
Index: linux-2.6.25/drivers/mtd/maps/Kconfig
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/drivers/mtd/maps/Kconfig 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/drivers/mtd/maps/Kconfig 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/drivers/mtd/maps/Kconfig 2007-10-13 02:28:13.644001805 +0200
|
+++ linux-2.6.25/drivers/mtd/maps/Kconfig 2008-04-26 21:57:12.000000000 +0100
|
||||||
@@ -352,6 +352,12 @@
|
@@ -337,6 +337,12 @@ config MTD_CFI_FLAGADM
|
||||||
Mapping for the Flaga digital module. If you don't have one, ignore
|
Mapping for the Flaga digital module. If you don't have one, ignore
|
||||||
this setting.
|
this setting.
|
||||||
|
|
||||||
+config MTD_BCM47XX
|
+config MTD_BCM47XX
|
||||||
+ tristate "BCM47xx flash device"
|
+ tristate "BCM47xx flash device"
|
||||||
+ depends on MIPS && MTD_CFI && BCM947XX
|
+ depends on MIPS && MTD_CFI && BCM47XX
|
||||||
+ help
|
+ help
|
||||||
+ Support for the flash chips on the BCM947xx board.
|
+ Support for the flash chips on the BCM947xx board.
|
||||||
+
|
+
|
||||||
config MTD_WALNUT
|
config MTD_WALNUT
|
||||||
tristate "Flash device mapped on IBM 405GP Walnut"
|
tristate "Flash device mapped on IBM 405GP Walnut"
|
||||||
depends on MTD_JEDECPROBE && WALNUT
|
depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
|
||||||
Index: linux-2.6.23/drivers/mtd/maps/Makefile
|
Index: linux-2.6.25/drivers/mtd/maps/Makefile
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/drivers/mtd/maps/Makefile 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/drivers/mtd/maps/Makefile 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/drivers/mtd/maps/Makefile 2007-10-13 02:27:56.727037761 +0200
|
+++ linux-2.6.25/drivers/mtd/maps/Makefile 2008-04-26 21:57:12.000000000 +0100
|
||||||
@@ -33,6 +33,7 @@
|
@@ -31,6 +31,7 @@ obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcm
|
||||||
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
|
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
|
||||||
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
|
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
|
||||||
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
|
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,15 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/net/b44.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/net/b44.c 2008-03-22 19:52:40.000000000 -0700
|
|
||||||
+++ linux-2.6.23.16/drivers/net/b44.c 2008-03-22 19:52:41.000000000 -0700
|
|
||||||
@@ -2273,6 +2273,10 @@
|
|
||||||
bp->phy_addr = sdev->bus->sprom.et1phyaddr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+ /* Some ROMs have buggy PHY addresses with the high
|
|
||||||
+ * bits set (sign extension?). Truncate them to a
|
|
||||||
+ * valid PHY address. */
|
|
||||||
+ bp->phy_addr &= 0x1F;
|
|
||||||
|
|
||||||
memcpy(bp->dev->dev_addr, addr, 6);
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Index: linux-2.6.23/arch/mips/Kconfig
|
Index: linux-2.6.25/arch/mips/Kconfig
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/Kconfig 2007-10-13 02:23:41.484492317 +0200
|
--- linux-2.6.25.orig/arch/mips/Kconfig 2008-04-26 21:57:10.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/Kconfig 2007-10-13 02:47:02.784347843 +0200
|
+++ linux-2.6.25/arch/mips/Kconfig 2008-04-26 21:57:13.000000000 +0100
|
||||||
@@ -192,7 +192,6 @@
|
@@ -228,7 +228,6 @@ config MIPS_MALTA
|
||||||
select I8259
|
select I8259
|
||||||
select MIPS_BOARDS_GEN
|
select MIPS_BOARDS_GEN
|
||||||
select MIPS_BONITO64
|
select MIPS_BONITO64
|
||||||
|
@ -10,7 +10,7 @@ Index: linux-2.6.23/arch/mips/Kconfig
|
||||||
select PCI_GT64XXX_PCI0
|
select PCI_GT64XXX_PCI0
|
||||||
select MIPS_MSC
|
select MIPS_MSC
|
||||||
select SWAP_IO_SPACE
|
select SWAP_IO_SPACE
|
||||||
@@ -1281,13 +1280,6 @@
|
@@ -1421,13 +1420,6 @@ config IP22_CPU_SCACHE
|
||||||
bool
|
bool
|
||||||
select BOARD_SCACHE
|
select BOARD_SCACHE
|
||||||
|
|
||||||
|
@ -24,11 +24,11 @@ Index: linux-2.6.23/arch/mips/Kconfig
|
||||||
config R5000_CPU_SCACHE
|
config R5000_CPU_SCACHE
|
||||||
bool
|
bool
|
||||||
select BOARD_SCACHE
|
select BOARD_SCACHE
|
||||||
Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
|
Index: linux-2.6.25/arch/mips/kernel/cpu-probe.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:23:11.210767122 +0200
|
--- linux-2.6.25.orig/arch/mips/kernel/cpu-probe.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200
|
+++ linux-2.6.25/arch/mips/kernel/cpu-probe.c 2008-04-26 21:57:13.000000000 +0100
|
||||||
@@ -701,6 +701,8 @@
|
@@ -704,6 +704,8 @@ static inline void cpu_probe_mips(struct
|
||||||
break;
|
break;
|
||||||
case PRID_IMP_25KF:
|
case PRID_IMP_25KF:
|
||||||
c->cputype = CPU_25KF;
|
c->cputype = CPU_25KF;
|
||||||
|
@ -37,19 +37,19 @@ Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
|
||||||
break;
|
break;
|
||||||
case PRID_IMP_34K:
|
case PRID_IMP_34K:
|
||||||
c->cputype = CPU_34K;
|
c->cputype = CPU_34K;
|
||||||
Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
Index: linux-2.6.25/arch/mips/mm/c-r4k.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/c-r4k.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 02:47:02.792348301 +0200
|
+++ linux-2.6.25/arch/mips/mm/c-r4k.c 2008-04-26 22:08:15.000000000 +0100
|
||||||
@@ -1086,7 +1086,6 @@
|
@@ -1103,7 +1103,6 @@ static void __init loongson2_sc_init(voi
|
||||||
|
|
||||||
extern int r5k_sc_init(void);
|
extern int r5k_sc_init(void);
|
||||||
extern int rm7k_sc_init(void);
|
extern int rm7k_sc_init(void);
|
||||||
-extern int mips_sc_init(void);
|
-extern int mips_sc_init(void);
|
||||||
|
|
||||||
static void __init setup_scache(void)
|
static void __cpuinit setup_scache(void)
|
||||||
{
|
{
|
||||||
@@ -1140,29 +1139,17 @@
|
@@ -1157,29 +1156,17 @@ static void __cpuinit setup_scache(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -84,11 +84,11 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
/* compute a couple of other cache variables */
|
/* compute a couple of other cache variables */
|
||||||
c->scache.waysize = scache_size / c->scache.ways;
|
c->scache.waysize = scache_size / c->scache.ways;
|
||||||
|
|
||||||
Index: linux-2.6.23/arch/mips/mm/Makefile
|
Index: linux-2.6.25/arch/mips/mm/Makefile
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/Makefile 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/Makefile 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/Makefile 2007-10-13 02:47:23.393522295 +0200
|
+++ linux-2.6.25/arch/mips/mm/Makefile 2008-04-26 21:57:13.000000000 +0100
|
||||||
@@ -31,6 +31,5 @@
|
@@ -32,6 +32,5 @@ obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-
|
||||||
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
|
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
|
||||||
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
|
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
|
||||||
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
|
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
Index: linux-2.6.23/arch/mips/kernel/genex.S
|
Index: linux-2.6.25/arch/mips/kernel/genex.S
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/kernel/genex.S 2007-10-13 11:29:46.219648163 +0200
|
--- linux-2.6.25.orig/arch/mips/kernel/genex.S 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/kernel/genex.S 2007-10-13 11:29:49.619841933 +0200
|
+++ linux-2.6.25/arch/mips/kernel/genex.S 2008-04-26 21:57:14.000000000 +0100
|
||||||
@@ -51,6 +51,10 @@
|
@@ -51,6 +51,10 @@ NESTED(except_vec1_generic, 0, sp)
|
||||||
NESTED(except_vec3_generic, 0, sp)
|
NESTED(except_vec3_generic, 0, sp)
|
||||||
.set push
|
.set push
|
||||||
.set noat
|
.set noat
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ nop
|
+ nop
|
||||||
+ nop
|
+ nop
|
||||||
+#endif
|
+#endif
|
||||||
#if R5432_CP0_INTERRUPT_WAR
|
#if R5432_CP0_INTERRUPT_WAR
|
||||||
mfc0 k0, CP0_INDEX
|
mfc0 k0, CP0_INDEX
|
||||||
#endif
|
#endif
|
||||||
Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
Index: linux-2.6.25/arch/mips/mm/c-r4k.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/c-r4k.c 2007-10-13 11:29:46.227648623 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/c-r4k.c 2008-04-26 21:57:13.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/c-r4k.c 2007-10-13 11:29:49.619841933 +0200
|
+++ linux-2.6.25/arch/mips/mm/c-r4k.c 2008-04-26 21:57:14.000000000 +0100
|
||||||
@@ -30,6 +30,9 @@
|
@@ -33,6 +33,9 @@
|
||||||
#include <asm/cacheflush.h> /* for run_uncached() */
|
#include <asm/cacheflush.h> /* for run_uncached() */
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
/*
|
/*
|
||||||
* Special Variant of smp_call_function for use by cache functions:
|
* Special Variant of smp_call_function for use by cache functions:
|
||||||
*
|
*
|
||||||
@@ -94,6 +97,9 @@
|
@@ -97,6 +100,9 @@ static void __cpuinit r4k_blast_dcache_p
|
||||||
{
|
{
|
||||||
unsigned long dc_lsize = cpu_dcache_line_size();
|
unsigned long dc_lsize = cpu_dcache_line_size();
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
if (dc_lsize == 0)
|
if (dc_lsize == 0)
|
||||||
r4k_blast_dcache_page = (void *)cache_noop;
|
r4k_blast_dcache_page = (void *)cache_noop;
|
||||||
else if (dc_lsize == 16)
|
else if (dc_lsize == 16)
|
||||||
@@ -108,6 +114,9 @@
|
@@ -111,6 +117,9 @@ static void __cpuinit r4k_blast_dcache_p
|
||||||
{
|
{
|
||||||
unsigned long dc_lsize = cpu_dcache_line_size();
|
unsigned long dc_lsize = cpu_dcache_line_size();
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
if (dc_lsize == 0)
|
if (dc_lsize == 0)
|
||||||
r4k_blast_dcache_page_indexed = (void *)cache_noop;
|
r4k_blast_dcache_page_indexed = (void *)cache_noop;
|
||||||
else if (dc_lsize == 16)
|
else if (dc_lsize == 16)
|
||||||
@@ -122,6 +131,9 @@
|
@@ -125,6 +134,9 @@ static void __cpuinit r4k_blast_dcache_s
|
||||||
{
|
{
|
||||||
unsigned long dc_lsize = cpu_dcache_line_size();
|
unsigned long dc_lsize = cpu_dcache_line_size();
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
if (dc_lsize == 0)
|
if (dc_lsize == 0)
|
||||||
r4k_blast_dcache = (void *)cache_noop;
|
r4k_blast_dcache = (void *)cache_noop;
|
||||||
else if (dc_lsize == 16)
|
else if (dc_lsize == 16)
|
||||||
@@ -623,6 +635,8 @@
|
@@ -630,6 +642,8 @@ static void local_r4k_flush_cache_sigtra
|
||||||
unsigned long addr = (unsigned long) arg;
|
unsigned long addr = (unsigned long) arg;
|
||||||
|
|
||||||
R4600_HIT_CACHEOP_WAR_IMPL;
|
R4600_HIT_CACHEOP_WAR_IMPL;
|
||||||
|
@ -66,10 +66,10 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
if (dc_lsize)
|
if (dc_lsize)
|
||||||
protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
|
protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
|
||||||
if (!cpu_icache_snoops_remote_store && scache_size)
|
if (!cpu_icache_snoops_remote_store && scache_size)
|
||||||
@@ -1198,6 +1212,17 @@
|
@@ -1215,6 +1229,17 @@ static void __cpuinit coherency_setup(vo
|
||||||
* silly idea of putting something else there ...
|
* silly idea of putting something else there ...
|
||||||
*/
|
*/
|
||||||
switch (current_cpu_data.cputype) {
|
switch (current_cpu_type()) {
|
||||||
+ case CPU_BCM3302:
|
+ case CPU_BCM3302:
|
||||||
+ {
|
+ {
|
||||||
+ u32 cm;
|
+ u32 cm;
|
||||||
|
@ -84,12 +84,12 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
case CPU_R4000PC:
|
case CPU_R4000PC:
|
||||||
case CPU_R4000SC:
|
case CPU_R4000SC:
|
||||||
case CPU_R4000MC:
|
case CPU_R4000MC:
|
||||||
@@ -1228,6 +1253,15 @@
|
@@ -1254,6 +1279,15 @@ void __cpuinit r4k_cache_init(void)
|
||||||
/* Default cache error handler for R4000 and R5000 family */
|
break;
|
||||||
set_uncached_handler (0x100, &except_vec2_generic, 0x80);
|
}
|
||||||
|
|
||||||
+ /* Check if special workarounds are required */
|
+ /* Check if special workarounds are required */
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
|
+ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
|
||||||
+ printk("Enabling BCM4710A0 cache workarounds.\n");
|
+ printk("Enabling BCM4710A0 cache workarounds.\n");
|
||||||
+ bcm4710 = 1;
|
+ bcm4710 = 1;
|
||||||
|
@ -100,11 +100,11 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
probe_pcache();
|
probe_pcache();
|
||||||
setup_scache();
|
setup_scache();
|
||||||
|
|
||||||
@@ -1273,5 +1307,13 @@
|
@@ -1303,5 +1337,13 @@ void __cpuinit r4k_cache_init(void)
|
||||||
build_clear_page();
|
build_clear_page();
|
||||||
build_copy_page();
|
build_copy_page();
|
||||||
local_r4k___flush_cache_all(NULL);
|
local_r4k___flush_cache_all(NULL);
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ {
|
+ {
|
||||||
+ static void (*_coherency_setup)(void);
|
+ static void (*_coherency_setup)(void);
|
||||||
+ _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
|
+ _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
|
||||||
|
@ -114,39 +114,39 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
|
||||||
coherency_setup();
|
coherency_setup();
|
||||||
+#endif
|
+#endif
|
||||||
}
|
}
|
||||||
Index: linux-2.6.23/arch/mips/mm/tlbex.c
|
Index: linux-2.6.25/arch/mips/mm/tlbex.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/tlbex.c 2007-10-13 11:29:46.235649074 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/tlbex.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/tlbex.c 2007-10-13 11:35:46.076155216 +0200
|
+++ linux-2.6.25/arch/mips/mm/tlbex.c 2008-04-26 21:57:14.000000000 +0100
|
||||||
@@ -1273,6 +1273,9 @@
|
@@ -677,6 +677,9 @@ static void __cpuinit build_r4000_tlb_re
|
||||||
/* No need for i_nop */
|
/* No need for uasm_i_nop */
|
||||||
}
|
}
|
||||||
|
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ i_nop(&p);
|
+ uasm_i_nop(&p);
|
||||||
+#endif
|
+#endif
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
|
build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
|
||||||
#else
|
#else
|
||||||
@@ -1708,6 +1711,9 @@
|
@@ -1084,6 +1087,9 @@ build_r4000_tlbchange_handler_head(u32 *
|
||||||
struct reloc **r, unsigned int pte,
|
struct uasm_reloc **r, unsigned int pte,
|
||||||
unsigned int ptr)
|
unsigned int ptr)
|
||||||
{
|
{
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ i_nop(p);
|
+ uasm_i_nop(p);
|
||||||
+#endif
|
+#endif
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
|
build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
|
||||||
#else
|
#else
|
||||||
Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
Index: linux-2.6.25/include/asm-mips/r4kcache.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/r4kcache.h 2007-10-13 11:29:46.255650214 +0200
|
--- linux-2.6.25.orig/include/asm-mips/r4kcache.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/r4kcache.h 2007-10-13 11:29:49.631842613 +0200
|
+++ linux-2.6.25/include/asm-mips/r4kcache.h 2008-04-26 21:57:14.000000000 +0100
|
||||||
@@ -17,6 +17,20 @@
|
@@ -17,6 +17,20 @@
|
||||||
#include <asm/cpu-features.h>
|
#include <asm/cpu-features.h>
|
||||||
#include <asm/mipsmtregs.h>
|
#include <asm/mipsmtregs.h>
|
||||||
|
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+#include <asm/paccess.h>
|
+#include <asm/paccess.h>
|
||||||
+#include <linux/ssb/ssb.h>
|
+#include <linux/ssb/ssb.h>
|
||||||
+#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
|
+#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
|
||||||
|
@ -163,7 +163,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
/*
|
/*
|
||||||
* This macro return a properly sign-extended address suitable as base address
|
* This macro return a properly sign-extended address suitable as base address
|
||||||
* for indexed cache operations. Two issues here:
|
* for indexed cache operations. Two issues here:
|
||||||
@@ -150,6 +164,7 @@
|
@@ -150,6 +164,7 @@ static inline void flush_icache_line_ind
|
||||||
static inline void flush_dcache_line_indexed(unsigned long addr)
|
static inline void flush_dcache_line_indexed(unsigned long addr)
|
||||||
{
|
{
|
||||||
__dflush_prologue
|
__dflush_prologue
|
||||||
|
@ -171,7 +171,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
cache_op(Index_Writeback_Inv_D, addr);
|
cache_op(Index_Writeback_Inv_D, addr);
|
||||||
__dflush_epilogue
|
__dflush_epilogue
|
||||||
}
|
}
|
||||||
@@ -169,6 +184,7 @@
|
@@ -169,6 +184,7 @@ static inline void flush_icache_line(uns
|
||||||
static inline void flush_dcache_line(unsigned long addr)
|
static inline void flush_dcache_line(unsigned long addr)
|
||||||
{
|
{
|
||||||
__dflush_prologue
|
__dflush_prologue
|
||||||
|
@ -179,7 +179,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
cache_op(Hit_Writeback_Inv_D, addr);
|
cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
__dflush_epilogue
|
__dflush_epilogue
|
||||||
}
|
}
|
||||||
@@ -176,6 +192,7 @@
|
@@ -176,6 +192,7 @@ static inline void flush_dcache_line(uns
|
||||||
static inline void invalidate_dcache_line(unsigned long addr)
|
static inline void invalidate_dcache_line(unsigned long addr)
|
||||||
{
|
{
|
||||||
__dflush_prologue
|
__dflush_prologue
|
||||||
|
@ -187,7 +187,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
cache_op(Hit_Invalidate_D, addr);
|
cache_op(Hit_Invalidate_D, addr);
|
||||||
__dflush_epilogue
|
__dflush_epilogue
|
||||||
}
|
}
|
||||||
@@ -208,6 +225,7 @@
|
@@ -208,6 +225,7 @@ static inline void flush_scache_line(uns
|
||||||
*/
|
*/
|
||||||
static inline void protected_flush_icache_line(unsigned long addr)
|
static inline void protected_flush_icache_line(unsigned long addr)
|
||||||
{
|
{
|
||||||
|
@ -195,7 +195,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
protected_cache_op(Hit_Invalidate_I, addr);
|
protected_cache_op(Hit_Invalidate_I, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +237,7 @@
|
@@ -219,6 +237,7 @@ static inline void protected_flush_icach
|
||||||
*/
|
*/
|
||||||
static inline void protected_writeback_dcache_line(unsigned long addr)
|
static inline void protected_writeback_dcache_line(unsigned long addr)
|
||||||
{
|
{
|
||||||
|
@ -203,7 +203,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
protected_cache_op(Hit_Writeback_Inv_D, addr);
|
protected_cache_op(Hit_Writeback_Inv_D, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,8 +358,52 @@
|
@@ -339,8 +358,52 @@ static inline void invalidate_tcache_pag
|
||||||
: "r" (base), \
|
: "r" (base), \
|
||||||
"i" (op));
|
"i" (op));
|
||||||
|
|
||||||
|
@ -257,23 +257,23 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
static inline void blast_##pfx##cache##lsize(void) \
|
static inline void blast_##pfx##cache##lsize(void) \
|
||||||
{ \
|
{ \
|
||||||
unsigned long start = INDEX_BASE; \
|
unsigned long start = INDEX_BASE; \
|
||||||
@@ -352,6 +415,7 @@
|
@@ -352,6 +415,7 @@ static inline void blast_##pfx##cache##l
|
||||||
\
|
\
|
||||||
__##pfx##flush_prologue \
|
__##pfx##flush_prologue \
|
||||||
\
|
\
|
||||||
+ war \
|
+ war \
|
||||||
for (ws = 0; ws < ws_end; ws += ws_inc) \
|
for (ws = 0; ws < ws_end; ws += ws_inc) \
|
||||||
for (addr = start; addr < end; addr += lsize * 32) \
|
for (addr = start; addr < end; addr += lsize * 32) \
|
||||||
cache##lsize##_unroll32(addr|ws,indexop); \
|
cache##lsize##_unroll32(addr|ws, indexop); \
|
||||||
@@ -366,6 +430,7 @@
|
@@ -366,6 +430,7 @@ static inline void blast_##pfx##cache##l
|
||||||
\
|
\
|
||||||
__##pfx##flush_prologue \
|
__##pfx##flush_prologue \
|
||||||
\
|
\
|
||||||
+ war \
|
+ war \
|
||||||
do { \
|
do { \
|
||||||
cache##lsize##_unroll32(start,hitop); \
|
cache##lsize##_unroll32(start, hitop); \
|
||||||
start += lsize * 32; \
|
start += lsize * 32; \
|
||||||
@@ -384,6 +449,8 @@
|
@@ -384,6 +449,8 @@ static inline void blast_##pfx##cache##l
|
||||||
current_cpu_data.desc.waybit; \
|
current_cpu_data.desc.waybit; \
|
||||||
unsigned long ws, addr; \
|
unsigned long ws, addr; \
|
||||||
\
|
\
|
||||||
|
@ -282,7 +282,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
__##pfx##flush_prologue \
|
__##pfx##flush_prologue \
|
||||||
\
|
\
|
||||||
for (ws = 0; ws < ws_end; ws += ws_inc) \
|
for (ws = 0; ws < ws_end; ws += ws_inc) \
|
||||||
@@ -393,28 +460,30 @@
|
@@ -393,35 +460,37 @@ static inline void blast_##pfx##cache##l
|
||||||
__##pfx##flush_epilogue \
|
__##pfx##flush_epilogue \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,6 +295,13 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
|
-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
|
||||||
-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
|
-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
|
||||||
-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
|
-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
|
||||||
|
-
|
||||||
|
-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
|
||||||
|
-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
|
||||||
|
-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
|
||||||
|
-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
|
||||||
|
-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
|
||||||
|
-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
|
||||||
+__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
|
+__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
|
||||||
+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
|
+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
|
||||||
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
|
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
|
||||||
|
@ -304,6 +311,13 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
|
+__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
|
||||||
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
|
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
|
||||||
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
|
+__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
|
||||||
|
+
|
||||||
|
+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
|
||||||
|
+__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
|
||||||
|
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
|
||||||
|
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
|
||||||
|
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
|
||||||
|
+__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
|
||||||
|
|
||||||
/* build blast_xxx_range, protected_blast_xxx_range */
|
/* build blast_xxx_range, protected_blast_xxx_range */
|
||||||
-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
|
-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
|
||||||
|
@ -323,7 +337,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
prot##cache_op(hitop, addr); \
|
prot##cache_op(hitop, addr); \
|
||||||
if (addr == aend) \
|
if (addr == aend) \
|
||||||
break; \
|
break; \
|
||||||
@@ -424,13 +493,13 @@
|
@@ -431,13 +500,13 @@ static inline void prot##blast_##pfx##ca
|
||||||
__##pfx##flush_epilogue \
|
__##pfx##flush_epilogue \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,15 +358,15 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
|
||||||
+__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
|
+__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
|
||||||
|
|
||||||
#endif /* _ASM_R4KCACHE_H */
|
#endif /* _ASM_R4KCACHE_H */
|
||||||
Index: linux-2.6.23/include/asm-mips/stackframe.h
|
Index: linux-2.6.25/include/asm-mips/stackframe.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/stackframe.h 2007-10-13 11:29:46.263650671 +0200
|
--- linux-2.6.25.orig/include/asm-mips/stackframe.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/stackframe.h 2007-10-13 11:33:38.504885346 +0200
|
+++ linux-2.6.25/include/asm-mips/stackframe.h 2008-04-26 21:57:14.000000000 +0100
|
||||||
@@ -350,6 +350,10 @@
|
@@ -359,6 +359,10 @@
|
||||||
.macro RESTORE_SP_AND_RET
|
.macro RESTORE_SP_AND_RET
|
||||||
LONG_L sp, PT_R29(sp)
|
LONG_L sp, PT_R29(sp)
|
||||||
.set mips3
|
.set mips3
|
||||||
+#ifdef CONFIG_BCM947XX
|
+#ifdef CONFIG_BCM47XX
|
||||||
+ nop
|
+ nop
|
||||||
+ nop
|
+ nop
|
||||||
+#endif
|
+#endif
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
Index: linux-2.6.23/arch/mips/mm/init.c
|
Index: linux-2.6.25/arch/mips/mm/init.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/init.c 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/init.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/init.c 2007-10-13 02:57:18.483434538 +0200
|
+++ linux-2.6.25/arch/mips/mm/init.c 2008-04-26 22:07:48.000000000 +0100
|
||||||
@@ -211,7 +211,7 @@
|
@@ -211,7 +211,7 @@ void copy_user_highpage(struct page *to,
|
||||||
void *vfrom, *vto;
|
void *vfrom, *vto;
|
||||||
|
|
||||||
vto = kmap_atomic(to, KM_USER1);
|
vto = kmap_atomic(to, KM_USER1);
|
||||||
- if (cpu_has_dc_aliases && !Page_dcache_dirty(from)) {
|
- if (cpu_has_dc_aliases &&
|
||||||
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) {
|
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
|
||||||
|
page_mapped(from) && !Page_dcache_dirty(from)) {
|
||||||
vfrom = kmap_coherent(from, vaddr);
|
vfrom = kmap_coherent(from, vaddr);
|
||||||
copy_page(vto, vfrom);
|
copy_page(vto, vfrom);
|
||||||
kunmap_coherent();
|
@@ -235,7 +235,7 @@ void copy_to_user_page(struct vm_area_st
|
||||||
@@ -234,7 +234,7 @@
|
|
||||||
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
- if (cpu_has_dc_aliases) {
|
- if (cpu_has_dc_aliases &&
|
||||||
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) {
|
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
|
||||||
|
page_mapped(page) && !Page_dcache_dirty(page)) {
|
||||||
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||||
memcpy(vto, src, len);
|
memcpy(vto, src, len);
|
||||||
kunmap_coherent();
|
@@ -255,7 +255,7 @@ void copy_from_user_page(struct vm_area_
|
||||||
@@ -250,7 +250,7 @@
|
|
||||||
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
- if (cpu_has_dc_aliases) {
|
- if (cpu_has_dc_aliases &&
|
||||||
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent) {
|
+ if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
|
||||||
void *vfrom =
|
page_mapped(page) && !Page_dcache_dirty(page)) {
|
||||||
kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||||
memcpy(dst, vfrom, len);
|
memcpy(dst, vfrom, len);
|
||||||
Index: linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h
|
Index: linux-2.6.25/include/asm-mips/mach-bcm47xx/cpu-feature-overrides.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||||
+++ linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h 2007-10-13 02:56:22.020216880 +0200
|
+++ linux-2.6.25/include/asm-mips/mach-bcm47xx/cpu-feature-overrides.h 2008-04-26 21:57:15.000000000 +0100
|
||||||
@@ -0,0 +1,13 @@
|
@@ -0,0 +1,13 @@
|
||||||
+/*
|
+/*
|
||||||
+ * This file is subject to the terms and conditions of the GNU General Public
|
+ * This file is subject to the terms and conditions of the GNU General Public
|
||||||
|
@ -41,16 +41,16 @@ Index: linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h
|
||||||
+ *
|
+ *
|
||||||
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
|
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
|
||||||
+ */
|
+ */
|
||||||
+#ifndef __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H
|
+#ifndef __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
|
||||||
+#define __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H
|
+#define __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
|
||||||
+
|
+
|
||||||
+#define cpu_use_kmap_coherent 0
|
+#define cpu_use_kmap_coherent 0
|
||||||
+
|
+
|
||||||
+#endif /* __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H */
|
+#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */
|
||||||
Index: linux-2.6.23/include/asm-mips/cpu-features.h
|
Index: linux-2.6.25/include/asm-mips/cpu-features.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/cpu-features.h 2007-10-09 22:31:38.000000000 +0200
|
--- linux-2.6.25.orig/include/asm-mips/cpu-features.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/cpu-features.h 2007-10-13 02:56:22.028217337 +0200
|
+++ linux-2.6.25/include/asm-mips/cpu-features.h 2008-04-26 21:57:15.000000000 +0100
|
||||||
@@ -101,6 +101,9 @@
|
@@ -101,6 +101,9 @@
|
||||||
#ifndef cpu_has_pindexed_dcache
|
#ifndef cpu_has_pindexed_dcache
|
||||||
#define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
|
#define cpu_has_pindexed_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c 2007-10-13 02:47:02.788348072 +0200
|
|
||||||
+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c 2007-10-13 02:57:46.293019312 +0200
|
|
||||||
@@ -159,6 +159,7 @@
|
|
||||||
case CPU_5KC:
|
|
||||||
case CPU_25KF:
|
|
||||||
case CPU_PR4450:
|
|
||||||
+ case CPU_BCM3302:
|
|
||||||
cpu_wait = r4k_wait;
|
|
||||||
break;
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
|
Index: linux-2.6.25/drivers/ssb/driver_chipcommon.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 13:46:08.000000000 +0100
|
--- linux-2.6.25.orig/drivers/ssb/driver_chipcommon.c 2008-04-27 21:36:52.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 13:46:17.000000000 +0100
|
+++ linux-2.6.25/drivers/ssb/driver_chipcommon.c 2008-04-27 21:43:50.000000000 +0100
|
||||||
@@ -270,6 +270,8 @@ void ssb_chipco_resume(struct ssb_chipco
|
@@ -270,6 +270,8 @@ void ssb_chipco_resume(struct ssb_chipco
|
||||||
void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
|
void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
|
||||||
u32 *plltype, u32 *n, u32 *m)
|
u32 *plltype, u32 *n, u32 *m)
|
||||||
|
@ -20,11 +20,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
|
||||||
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
|
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
|
||||||
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
||||||
switch (*plltype) {
|
switch (*plltype) {
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
|
Index: linux-2.6.25/drivers/ssb/driver_mipscore.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-02-19 13:46:08.000000000 +0100
|
--- linux-2.6.25.orig/drivers/ssb/driver_mipscore.c 2008-04-17 03:49:44.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c 2008-02-19 13:46:17.000000000 +0100
|
+++ linux-2.6.25/drivers/ssb/driver_mipscore.c 2008-04-27 21:43:50.000000000 +0100
|
||||||
@@ -160,6 +160,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
|
@@ -161,6 +161,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
|
||||||
|
|
||||||
if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
|
if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
|
||||||
rate = 200000000;
|
rate = 200000000;
|
||||||
|
@ -33,11 +33,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
|
||||||
} else {
|
} else {
|
||||||
rate = ssb_calc_clock_rate(pll_type, n, m);
|
rate = ssb_calc_clock_rate(pll_type, n, m);
|
||||||
}
|
}
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
Index: linux-2.6.25/drivers/ssb/main.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 13:46:08.000000000 +0100
|
--- linux-2.6.25.orig/drivers/ssb/main.c 2008-04-17 03:49:44.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 13:46:17.000000000 +0100
|
+++ linux-2.6.25/drivers/ssb/main.c 2008-04-27 21:43:50.000000000 +0100
|
||||||
@@ -862,6 +862,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
|
@@ -867,6 +867,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
|
||||||
|
|
||||||
if (bus->chip_id == 0x5365) {
|
if (bus->chip_id == 0x5365) {
|
||||||
rate = 100000000;
|
rate = 100000000;
|
||||||
|
|
|
@ -1,345 +0,0 @@
|
||||||
From: Michael Buesch <mb@bu3sch.de>
|
|
||||||
Date: Wed, 10 Oct 2007 06:47:17 +0000 (-0700)
|
|
||||||
Subject: USB: ohci SSB bus glue
|
|
||||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=c604e851486eabcbeb73e984279d436ce121fd5d
|
|
||||||
|
|
||||||
USB: ohci SSB bus glue
|
|
||||||
|
|
||||||
This adds SSB bus glue for the USB OHCI HCD.
|
|
||||||
|
|
||||||
Signed-off-by: Michael Buesch <mb@bu3sch.de>
|
|
||||||
Signed-off-by: John W. Linville <linville@tuxdriver.com>
|
|
||||||
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
|
|
||||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
|
||||||
---
|
|
||||||
|
|
||||||
Index: linux-2.6.23.16/drivers/usb/host/Kconfig
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/usb/host/Kconfig 2008-02-19 00:47:29.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/usb/host/Kconfig 2008-02-19 00:47:51.000000000 +0100
|
|
||||||
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
|
|
||||||
Enables support for PCI-bus plug-in USB controller cards.
|
|
||||||
If unsure, say Y.
|
|
||||||
|
|
||||||
+config USB_OHCI_HCD_SSB
|
|
||||||
+ bool "OHCI support for Broadcom SSB OHCI core"
|
|
||||||
+ depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
|
|
||||||
+ default n
|
|
||||||
+ ---help---
|
|
||||||
+ Support for the Sonics Silicon Backplane (SSB) attached
|
|
||||||
+ Broadcom USB OHCI core.
|
|
||||||
+
|
|
||||||
+ This device is present in some embedded devices with
|
|
||||||
+ Broadcom based SSB bus.
|
|
||||||
+
|
|
||||||
+ If unsure, say N.
|
|
||||||
+
|
|
||||||
config USB_OHCI_BIG_ENDIAN_DESC
|
|
||||||
bool
|
|
||||||
depends on USB_OHCI_HCD
|
|
||||||
Index: linux-2.6.23.16/drivers/usb/host/ohci-hcd.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/usb/host/ohci-hcd.c 2008-02-19 00:47:29.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/usb/host/ohci-hcd.c 2008-02-19 00:47:51.000000000 +0100
|
|
||||||
@@ -926,11 +926,17 @@ MODULE_LICENSE ("GPL");
|
|
||||||
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#ifdef CONFIG_USB_OHCI_HCD_SSB
|
|
||||||
+#include "ohci-ssb.c"
|
|
||||||
+#define SSB_OHCI_DRIVER ssb_ohci_driver
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#if !defined(PCI_DRIVER) && \
|
|
||||||
!defined(PLATFORM_DRIVER) && \
|
|
||||||
!defined(OF_PLATFORM_DRIVER) && \
|
|
||||||
!defined(SA1111_DRIVER) && \
|
|
||||||
- !defined(PS3_SYSTEM_BUS_DRIVER)
|
|
||||||
+ !defined(PS3_SYSTEM_BUS_DRIVER) && \
|
|
||||||
+ !defined(SSB_OHCI_DRIVER)
|
|
||||||
#error "missing bus glue for ohci-hcd"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -975,10 +981,20 @@ static int __init ohci_hcd_mod_init(void
|
|
||||||
goto error_pci;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+#ifdef SSB_OHCI_DRIVER
|
|
||||||
+ retval = ssb_driver_register(&SSB_OHCI_DRIVER);
|
|
||||||
+ if (retval)
|
|
||||||
+ goto error_ssb;
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
/* Error path */
|
|
||||||
+#ifdef SSB_OHCI_DRIVER
|
|
||||||
+ error_ssb:
|
|
||||||
+#endif
|
|
||||||
#ifdef PCI_DRIVER
|
|
||||||
+ pci_unregister_driver(&PCI_DRIVER);
|
|
||||||
error_pci:
|
|
||||||
#endif
|
|
||||||
#ifdef SA1111_DRIVER
|
|
||||||
@@ -1003,6 +1019,9 @@ module_init(ohci_hcd_mod_init);
|
|
||||||
|
|
||||||
static void __exit ohci_hcd_mod_exit(void)
|
|
||||||
{
|
|
||||||
+#ifdef SSB_OHCI_DRIVER
|
|
||||||
+ ssb_driver_unregister(&SSB_OHCI_DRIVER);
|
|
||||||
+#endif
|
|
||||||
#ifdef PCI_DRIVER
|
|
||||||
pci_unregister_driver(&PCI_DRIVER);
|
|
||||||
#endif
|
|
||||||
Index: linux-2.6.23.16/drivers/usb/host/ohci-ssb.c
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
||||||
+++ linux-2.6.23.16/drivers/usb/host/ohci-ssb.c 2008-02-19 00:47:51.000000000 +0100
|
|
||||||
@@ -0,0 +1,247 @@
|
|
||||||
+/*
|
|
||||||
+ * Sonics Silicon Backplane
|
|
||||||
+ * Broadcom USB-core OHCI driver
|
|
||||||
+ *
|
|
||||||
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
|
|
||||||
+ *
|
|
||||||
+ * Derived from the OHCI-PCI driver
|
|
||||||
+ * Copyright 1999 Roman Weissgaerber
|
|
||||||
+ * Copyright 2000-2002 David Brownell
|
|
||||||
+ * Copyright 1999 Linus Torvalds
|
|
||||||
+ * Copyright 1999 Gregory P. Smith
|
|
||||||
+ *
|
|
||||||
+ * Derived from the USBcore related parts of Broadcom-SB
|
|
||||||
+ * Copyright 2005 Broadcom Corporation
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the GNU/GPL. See COPYING for details.
|
|
||||||
+ */
|
|
||||||
+#include <linux/ssb/ssb.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
|
|
||||||
+
|
|
||||||
+struct ssb_ohci_device {
|
|
||||||
+ struct ohci_hcd ohci; /* _must_ be at the beginning. */
|
|
||||||
+
|
|
||||||
+ u32 enable_flags;
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static inline
|
|
||||||
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
|
|
||||||
+{
|
|
||||||
+ return (struct ssb_ohci_device *)(hcd->hcd_priv);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_reset(struct usb_hcd *hcd)
|
|
||||||
+{
|
|
||||||
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
|
|
||||||
+ struct ohci_hcd *ohci = &ohcidev->ohci;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ ohci_hcd_init(ohci);
|
|
||||||
+ err = ohci_init(ohci);
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_start(struct usb_hcd *hcd)
|
|
||||||
+{
|
|
||||||
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
|
|
||||||
+ struct ohci_hcd *ohci = &ohcidev->ohci;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = ohci_run(ohci);
|
|
||||||
+ if (err < 0) {
|
|
||||||
+ ohci_err(ohci, "can't start\n");
|
|
||||||
+ ohci_stop(hcd);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_PM
|
|
||||||
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
|
|
||||||
+{
|
|
||||||
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
|
|
||||||
+ struct ohci_hcd *ohci = &ohcidev->ohci;
|
|
||||||
+ unsigned long flags;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&ohci->lock, flags);
|
|
||||||
+
|
|
||||||
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
|
||||||
+ ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
|
|
||||||
+
|
|
||||||
+ /* make sure snapshot being resumed re-enumerates everything */
|
|
||||||
+ if (message.event == PM_EVENT_PRETHAW)
|
|
||||||
+ ohci_usb_reset(ohci);
|
|
||||||
+
|
|
||||||
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
|
||||||
+
|
|
||||||
+ spin_unlock_irqrestore(&ohci->lock, flags);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
|
|
||||||
+{
|
|
||||||
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
|
||||||
+ usb_hcd_resume_root_hub(hcd);
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+#endif /* CONFIG_PM */
|
|
||||||
+
|
|
||||||
+static const struct hc_driver ssb_ohci_hc_driver = {
|
|
||||||
+ .description = "ssb-usb-ohci",
|
|
||||||
+ .product_desc = "SSB OHCI Controller",
|
|
||||||
+ .hcd_priv_size = sizeof(struct ssb_ohci_device),
|
|
||||||
+
|
|
||||||
+ .irq = ohci_irq,
|
|
||||||
+ .flags = HCD_MEMORY | HCD_USB11,
|
|
||||||
+
|
|
||||||
+ .reset = ssb_ohci_reset,
|
|
||||||
+ .start = ssb_ohci_start,
|
|
||||||
+ .stop = ohci_stop,
|
|
||||||
+ .shutdown = ohci_shutdown,
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_PM
|
|
||||||
+ .suspend = ssb_ohci_hcd_suspend,
|
|
||||||
+ .resume = ssb_ohci_hcd_resume,
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+ .urb_enqueue = ohci_urb_enqueue,
|
|
||||||
+ .urb_dequeue = ohci_urb_dequeue,
|
|
||||||
+ .endpoint_disable = ohci_endpoint_disable,
|
|
||||||
+
|
|
||||||
+ .get_frame_number = ohci_get_frame,
|
|
||||||
+
|
|
||||||
+ .hub_status_data = ohci_hub_status_data,
|
|
||||||
+ .hub_control = ohci_hub_control,
|
|
||||||
+ .hub_irq_enable = ohci_rhsc_enable,
|
|
||||||
+ .bus_suspend = ohci_bus_suspend,
|
|
||||||
+ .bus_resume = ohci_bus_resume,
|
|
||||||
+
|
|
||||||
+ .start_port_reset = ohci_start_port_reset,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static void ssb_ohci_detach(struct ssb_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
|
|
||||||
+
|
|
||||||
+ usb_remove_hcd(hcd);
|
|
||||||
+ iounmap(hcd->regs);
|
|
||||||
+ usb_put_hcd(hcd);
|
|
||||||
+ ssb_device_disable(dev, 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_attach(struct ssb_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct ssb_ohci_device *ohcidev;
|
|
||||||
+ struct usb_hcd *hcd;
|
|
||||||
+ int err = -ENOMEM;
|
|
||||||
+ u32 tmp, flags = 0;
|
|
||||||
+
|
|
||||||
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
|
|
||||||
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
|
|
||||||
+
|
|
||||||
+ ssb_device_enable(dev, flags);
|
|
||||||
+
|
|
||||||
+ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
|
||||||
+ dev->dev->bus_id);
|
|
||||||
+ if (!hcd)
|
|
||||||
+ goto err_dev_disable;
|
|
||||||
+ ohcidev = hcd_to_ssb_ohci(hcd);
|
|
||||||
+ ohcidev->enable_flags = flags;
|
|
||||||
+
|
|
||||||
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
|
|
||||||
+ hcd->rsrc_start = ssb_admatch_base(tmp);
|
|
||||||
+ hcd->rsrc_len = ssb_admatch_size(tmp);
|
|
||||||
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
|
||||||
+ if (!hcd->regs)
|
|
||||||
+ goto err_put_hcd;
|
|
||||||
+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
|
|
||||||
+ if (err)
|
|
||||||
+ goto err_iounmap;
|
|
||||||
+
|
|
||||||
+ ssb_set_drvdata(dev, hcd);
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+
|
|
||||||
+err_iounmap:
|
|
||||||
+ iounmap(hcd->regs);
|
|
||||||
+err_put_hcd:
|
|
||||||
+ usb_put_hcd(hcd);
|
|
||||||
+err_dev_disable:
|
|
||||||
+ ssb_device_disable(dev, flags);
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_probe(struct ssb_device *dev,
|
|
||||||
+ const struct ssb_device_id *id)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+ u16 chipid_top;
|
|
||||||
+
|
|
||||||
+ /* USBcores are only connected on embedded devices. */
|
|
||||||
+ chipid_top = (dev->bus->chip_id & 0xFF00);
|
|
||||||
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ /* TODO: Probably need checks here; is the core connected? */
|
|
||||||
+
|
|
||||||
+ if (usb_disabled())
|
|
||||||
+ return -ENODEV;
|
|
||||||
+
|
|
||||||
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
|
|
||||||
+ * as HOST OHCI. If we want to attach it as Client device,
|
|
||||||
+ * we must branch here and call into the (yet to
|
|
||||||
+ * be written) Client mode driver. Same for remove(). */
|
|
||||||
+
|
|
||||||
+ err = ssb_ohci_attach(dev);
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void ssb_ohci_remove(struct ssb_device *dev)
|
|
||||||
+{
|
|
||||||
+ ssb_ohci_detach(dev);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#ifdef CONFIG_PM
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
|
|
||||||
+{
|
|
||||||
+ ssb_device_disable(dev, 0);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int ssb_ohci_resume(struct ssb_device *dev)
|
|
||||||
+{
|
|
||||||
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
|
|
||||||
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
|
|
||||||
+
|
|
||||||
+ ssb_device_enable(dev, ohcidev->enable_flags);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#else /* !CONFIG_PM */
|
|
||||||
+#define ssb_ohci_suspend NULL
|
|
||||||
+#define ssb_ohci_resume NULL
|
|
||||||
+#endif /* CONFIG_PM */
|
|
||||||
+
|
|
||||||
+static const struct ssb_device_id ssb_ohci_table[] = {
|
|
||||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
|
||||||
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
|
||||||
+ SSB_DEVTABLE_END
|
|
||||||
+};
|
|
||||||
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
|
|
||||||
+
|
|
||||||
+static struct ssb_driver ssb_ohci_driver = {
|
|
||||||
+ .name = KBUILD_MODNAME,
|
|
||||||
+ .id_table = ssb_ohci_table,
|
|
||||||
+ .probe = ssb_ohci_probe,
|
|
||||||
+ .remove = ssb_ohci_remove,
|
|
||||||
+ .suspend = ssb_ohci_suspend,
|
|
||||||
+ .resume = ssb_ohci_resume,
|
|
||||||
+};
|
|
|
@ -1,30 +0,0 @@
|
||||||
From: Al Viro <viro@ftp.linux.org.uk>
|
|
||||||
Date: Sat, 13 Oct 2007 21:29:47 +0000 (+0100)
|
|
||||||
Subject: Fix ohci-ssb with !CONFIG_PM
|
|
||||||
X-Git-Tag: linux-2.6.24-rc1~57^2~38
|
|
||||||
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=4735b37cf434175c2b7b36b3b68f1e60e8ec8527;hp=d773b33972a663cfaf066e966f87922a74088a1e
|
|
||||||
|
|
||||||
Fix ohci-ssb with !CONFIG_PM
|
|
||||||
|
|
||||||
ohci_bus_{suspend,resume} exists only if we have CONFIG_PM; do the same
|
|
||||||
thing as other subdrivers...
|
|
||||||
|
|
||||||
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
|
|
||||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
|
|
||||||
index bc3e785..fe70e72 100644
|
|
||||||
--- a/drivers/usb/host/ohci-ssb.c
|
|
||||||
+++ b/drivers/usb/host/ohci-ssb.c
|
|
||||||
@@ -117,8 +117,10 @@ static const struct hc_driver ssb_ohci_hc_driver = {
|
|
||||||
.hub_status_data = ohci_hub_status_data,
|
|
||||||
.hub_control = ohci_hub_control,
|
|
||||||
.hub_irq_enable = ohci_rhsc_enable,
|
|
||||||
+#ifdef CONFIG_PM
|
|
||||||
.bus_suspend = ohci_bus_suspend,
|
|
||||||
.bus_resume = ohci_bus_resume,
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
.start_port_reset = ohci_start_port_reset,
|
|
||||||
};
|
|
|
@ -1,6 +1,8 @@
|
||||||
--- a/drivers/usb/host/ohci-ssb.c 2007-11-05 07:56:56.000000000 -0800
|
Index: linux-2.6.25/drivers/usb/host/ohci-ssb.c
|
||||||
+++ b/drivers/usb/host/ohci-ssb.c 2007-11-05 08:26:15.000000000 -0800
|
===================================================================
|
||||||
@@ -142,10 +142,59 @@
|
--- linux-2.6.25.orig/drivers/usb/host/ohci-ssb.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
|
+++ linux-2.6.25/drivers/usb/host/ohci-ssb.c 2008-04-26 22:07:53.000000000 +0100
|
||||||
|
@@ -142,10 +142,59 @@ static int ssb_ohci_attach(struct ssb_de
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
u32 tmp, flags = 0;
|
u32 tmp, flags = 0;
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@
|
||||||
|
|
||||||
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
|
||||||
dev->dev->bus_id);
|
dev->dev->bus_id);
|
||||||
@@ -235,6 +284,7 @@
|
@@ -235,6 +284,7 @@ static int ssb_ohci_resume(struct ssb_de
|
||||||
static const struct ssb_device_id ssb_ohci_table[] = {
|
static const struct ssb_device_id ssb_ohci_table[] = {
|
||||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
|
||||||
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
--- linux-2.6.23.1/drivers/usb/host/ohci-ssb.c 2007-11-26 14:01:22.000000000 -0500
|
Index: linux-2.6.25/drivers/usb/host/ohci-ssb.c
|
||||||
+++ linux-2.6.23.1.new/drivers/usb/host/ohci-ssb.c 2007-11-26 14:16:08.000000000 -0500
|
===================================================================
|
||||||
@@ -195,6 +195,11 @@
|
--- linux-2.6.25.orig/drivers/usb/host/ohci-ssb.c 2008-04-26 21:57:17.000000000 +0100
|
||||||
|
+++ linux-2.6.25/drivers/usb/host/ohci-ssb.c 2008-04-26 21:57:17.000000000 +0100
|
||||||
|
@@ -195,6 +195,11 @@ static int ssb_ohci_attach(struct ssb_de
|
||||||
else
|
else
|
||||||
ssb_device_enable(dev, 0);
|
ssb_device_enable(dev, 0);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Index: linux-2.6.23/include/asm-mips/cacheflush.h
|
Index: linux-2.6.25/include/asm-mips/cacheflush.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/cacheflush.h 2007-10-13 11:01:52.780284289 +0200
|
--- linux-2.6.25.orig/include/asm-mips/cacheflush.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/cacheflush.h 2007-10-13 11:02:16.289624011 +0200
|
+++ linux-2.6.25/include/asm-mips/cacheflush.h 2008-04-26 21:57:18.000000000 +0100
|
||||||
@@ -32,7 +32,7 @@
|
@@ -32,7 +32,7 @@
|
||||||
extern void (*flush_cache_all)(void);
|
extern void (*flush_cache_all)(void);
|
||||||
extern void (*__flush_cache_all)(void);
|
extern void (*__flush_cache_all)(void);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Index: linux-2.6.23/arch/mips/mm/init.c
|
Index: linux-2.6.25/arch/mips/mm/init.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/arch/mips/mm/init.c 2007-10-13 11:46:58.762489429 +0200
|
--- linux-2.6.25.orig/arch/mips/mm/init.c 2008-04-26 21:57:15.000000000 +0100
|
||||||
+++ linux-2.6.23/arch/mips/mm/init.c 2007-10-13 11:47:36.092616749 +0200
|
+++ linux-2.6.25/arch/mips/mm/init.c 2008-04-26 21:57:19.000000000 +0100
|
||||||
@@ -205,31 +205,6 @@
|
@@ -205,32 +205,6 @@ void kunmap_coherent(void)
|
||||||
preempt_check_resched();
|
preempt_check_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ Index: linux-2.6.23/arch/mips/mm/init.c
|
||||||
- void *vfrom, *vto;
|
- void *vfrom, *vto;
|
||||||
-
|
-
|
||||||
- vto = kmap_atomic(to, KM_USER1);
|
- vto = kmap_atomic(to, KM_USER1);
|
||||||
- if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) {
|
- if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
|
||||||
|
- page_mapped(from) && !Page_dcache_dirty(from)) {
|
||||||
- vfrom = kmap_coherent(from, vaddr);
|
- vfrom = kmap_coherent(from, vaddr);
|
||||||
- copy_page(vto, vfrom);
|
- copy_page(vto, vfrom);
|
||||||
- kunmap_coherent();
|
- kunmap_coherent();
|
||||||
|
@ -34,11 +35,11 @@ Index: linux-2.6.23/arch/mips/mm/init.c
|
||||||
void copy_to_user_page(struct vm_area_struct *vma,
|
void copy_to_user_page(struct vm_area_struct *vma,
|
||||||
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
struct page *page, unsigned long vaddr, void *dst, const void *src,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
Index: linux-2.6.23/include/asm-mips/page.h
|
Index: linux-2.6.25/include/asm-mips/page.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.orig/include/asm-mips/page.h 2007-10-13 11:45:50.518600430 +0200
|
--- linux-2.6.25.orig/include/asm-mips/page.h 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23/include/asm-mips/page.h 2007-10-13 11:47:26.472068504 +0200
|
+++ linux-2.6.25/include/asm-mips/page.h 2008-04-26 21:57:19.000000000 +0100
|
||||||
@@ -35,6 +35,7 @@
|
@@ -32,6 +32,7 @@
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
|
@ -46,7 +47,7 @@ Index: linux-2.6.23/include/asm-mips/page.h
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,13 +68,16 @@
|
@@ -64,13 +65,16 @@ static inline void clear_user_page(void
|
||||||
flush_data_cache_page((unsigned long)addr);
|
flush_data_cache_page((unsigned long)addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
384
target/linux/brcm47xx/patches-2.6.25/400-arch-bcm47xx.patch
Normal file
384
target/linux/brcm47xx/patches-2.6.25/400-arch-bcm47xx.patch
Normal file
|
@ -0,0 +1,384 @@
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/irq.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/irq.c 2008-05-14 14:36:58.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/irq.c 2008-05-14 14:37:06.000000000 +0100
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
|
||||||
|
+ * Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
@@ -23,10 +24,19 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
+#include <linux/pci.h>
|
||||||
|
+#include <linux/ssb/ssb.h>
|
||||||
|
+
|
||||||
|
#include <asm/irq_cpu.h>
|
||||||
|
|
||||||
|
+
|
||||||
|
+extern struct ssb_bus ssb_bcm47xx;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void plat_irq_dispatch(void)
|
||||||
|
{
|
||||||
|
u32 cause;
|
||||||
|
@@ -53,3 +63,19 @@ void __init arch_init_irq(void)
|
||||||
|
{
|
||||||
|
mips_cpu_irq_init();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||||
|
+{
|
||||||
|
+ int res;
|
||||||
|
+
|
||||||
|
+ res = ssb_pcibios_map_irq(dev, slot, pin);
|
||||||
|
+ if (res < 0) {
|
||||||
|
+ printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
|
||||||
|
+ dev->dev.bus_id);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ /* IRQ-0 and IRQ-1 are software interrupts. */
|
||||||
|
+ WARN_ON((res == 0) || (res == 1));
|
||||||
|
+
|
||||||
|
+ return res;
|
||||||
|
+}
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/setup.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/setup.c 2008-05-14 14:36:58.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/setup.c 2008-05-14 14:37:06.000000000 +0100
|
||||||
|
@@ -2,7 +2,7 @@
|
||||||
|
* Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
|
||||||
|
* Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
|
||||||
|
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
- * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
|
||||||
|
+ * Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
@@ -25,23 +25,52 @@
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#include <linux/init.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
-#include <linux/ssb/ssb.h>
|
||||||
|
+#include <linux/tty.h>
|
||||||
|
+#include <linux/serial.h>
|
||||||
|
+#include <linux/serial_core.h>
|
||||||
|
+#include <linux/serial_reg.h>
|
||||||
|
+#include <linux/serial_8250.h>
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
-#include <asm/reboot.h>
|
||||||
|
#include <asm/time.h>
|
||||||
|
-#include <bcm47xx.h>
|
||||||
|
+#include <asm/reboot.h>
|
||||||
|
#include <asm/fw/cfe/cfe_api.h>
|
||||||
|
+#include <linux/pm.h>
|
||||||
|
+#include <linux/ssb/ssb.h>
|
||||||
|
+#include <linux/ssb/ssb_embedded.h>
|
||||||
|
+
|
||||||
|
+#include "include/nvram.h"
|
||||||
|
|
||||||
|
struct ssb_bus ssb_bcm47xx;
|
||||||
|
EXPORT_SYMBOL(ssb_bcm47xx);
|
||||||
|
|
||||||
|
+extern void bcm47xx_pci_init(void);
|
||||||
|
+
|
||||||
|
+int pcibios_plat_dev_init(struct pci_dev *dev)
|
||||||
|
+{
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ err = ssb_pcibios_plat_dev_init(dev);
|
||||||
|
+ if (err) {
|
||||||
|
+ printk(KERN_ALERT "PCI: Failed to init device %s\n",
|
||||||
|
+ pci_name(dev));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void bcm47xx_machine_restart(char *command)
|
||||||
|
{
|
||||||
|
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
|
||||||
|
local_irq_disable();
|
||||||
|
+ /* CFE has a reboot callback, but that does not work.
|
||||||
|
+ * Oopses with: Reserved instruction in kernel code.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
/* Set the watchdog timer to reset immediately */
|
||||||
|
- ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1);
|
||||||
|
+ if (ssb_watchdog_timer_set(&ssb_bcm47xx, 1))
|
||||||
|
+ printk(KERN_EMERG "SSB watchdog-triggered reboot failed!\n");
|
||||||
|
while (1)
|
||||||
|
cpu_relax();
|
||||||
|
}
|
||||||
|
@@ -50,12 +79,13 @@ static void bcm47xx_machine_halt(void)
|
||||||
|
{
|
||||||
|
/* Disable interrupts and watchdog and spin forever */
|
||||||
|
local_irq_disable();
|
||||||
|
- ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0);
|
||||||
|
+ if (ssb_watchdog_timer_set(&ssb_bcm47xx, 0))
|
||||||
|
+ printk(KERN_EMERG "Failed to disable SSB watchdog!\n");
|
||||||
|
while (1)
|
||||||
|
cpu_relax();
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void str2eaddr(char *str, char *dest)
|
||||||
|
+static void e_aton(char *str, char *dest)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
@@ -72,52 +102,141 @@ static void str2eaddr(char *str, char *d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int bcm47xx_get_invariants(struct ssb_bus *bus,
|
||||||
|
- struct ssb_init_invariants *iv)
|
||||||
|
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
|
||||||
|
{
|
||||||
|
- char buf[100];
|
||||||
|
+ char *s;
|
||||||
|
|
||||||
|
- /* Fill boardinfo structure */
|
||||||
|
- memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
|
||||||
|
+ memset(sprom, 0xFF, sizeof(struct ssb_sprom));
|
||||||
|
|
||||||
|
- if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||||
|
- if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
|
||||||
|
- if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
|
||||||
|
-
|
||||||
|
- /* Fill sprom structure */
|
||||||
|
- memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
|
||||||
|
- iv->sprom.revision = 3;
|
||||||
|
-
|
||||||
|
- if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
|
||||||
|
- str2eaddr(buf, iv->sprom.et0mac);
|
||||||
|
- if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
|
||||||
|
- str2eaddr(buf, iv->sprom.et1mac);
|
||||||
|
- if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10);
|
||||||
|
- if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10);
|
||||||
|
- if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
|
||||||
|
- if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
|
||||||
|
- iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
|
||||||
|
+ sprom->revision = 1;
|
||||||
|
+ if ((s = nvram_get("il0macaddr")))
|
||||||
|
+ e_aton(s, sprom->il0mac);
|
||||||
|
+ if ((s = nvram_get("et0macaddr")))
|
||||||
|
+ e_aton(s, sprom->et0mac);
|
||||||
|
+ if ((s = nvram_get("et1macaddr")))
|
||||||
|
+ e_aton(s, sprom->et1mac);
|
||||||
|
+ if ((s = nvram_get("et0phyaddr")))
|
||||||
|
+ sprom->et0phyaddr = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("et1phyaddr")))
|
||||||
|
+ sprom->et1phyaddr = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("et0mdcport")))
|
||||||
|
+ sprom->et0mdcport = !!simple_strtoul(s, NULL, 10);
|
||||||
|
+ if ((s = nvram_get("et1mdcport")))
|
||||||
|
+ sprom->et1mdcport = !!simple_strtoul(s, NULL, 10);
|
||||||
|
+ if ((s = nvram_get("pa0b0")))
|
||||||
|
+ sprom->pa0b0 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa0b1")))
|
||||||
|
+ sprom->pa0b1 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa0b2")))
|
||||||
|
+ sprom->pa0b2 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa1b0")))
|
||||||
|
+ sprom->pa1b0 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa1b1")))
|
||||||
|
+ sprom->pa1b1 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa1b2")))
|
||||||
|
+ sprom->pa1b2 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("wl0gpio0")))
|
||||||
|
+ sprom->gpio0 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("wl0gpio1")))
|
||||||
|
+ sprom->gpio1 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("wl0gpio2")))
|
||||||
|
+ sprom->gpio2 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("wl0gpio3")))
|
||||||
|
+ sprom->gpio3 = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa0maxpwr")))
|
||||||
|
+ sprom->maxpwr_bg = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa1maxpwr")))
|
||||||
|
+ sprom->maxpwr_a = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa0itssit")))
|
||||||
|
+ sprom->itssi_bg = simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("pa1itssit")))
|
||||||
|
+ sprom->itssi_a = simple_strtoul(s, NULL, 0);
|
||||||
|
+ sprom->boardflags_lo = 0;
|
||||||
|
+ if ((s = nvram_get("boardflags")))
|
||||||
|
+ sprom->boardflags_lo = simple_strtoul(s, NULL, 0);
|
||||||
|
+ sprom->boardflags_hi = 0;
|
||||||
|
+ if ((s = nvram_get("boardflags2")))
|
||||||
|
+ sprom->boardflags_hi = simple_strtoul(s, NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv)
|
||||||
|
+{
|
||||||
|
+ char *s;
|
||||||
|
+
|
||||||
|
+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
|
||||||
|
+ if ((s = nvram_get("boardtype")))
|
||||||
|
+ iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0);
|
||||||
|
+ if ((s = nvram_get("boardrev")))
|
||||||
|
+ iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0);
|
||||||
|
+
|
||||||
|
+ bcm47xx_fill_sprom(&iv->sprom);
|
||||||
|
+
|
||||||
|
+ if ((s = nvram_get("cardbus")))
|
||||||
|
+ iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __init plat_mem_setup(void)
|
||||||
|
{
|
||||||
|
- int err;
|
||||||
|
+ int i, err;
|
||||||
|
+ char *s;
|
||||||
|
+ struct ssb_mipscore *mcore;
|
||||||
|
+
|
||||||
|
+ err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants);
|
||||||
|
+ if (err) {
|
||||||
|
+ const char *msg = "Failed to initialize SSB bus (err %d)\n";
|
||||||
|
+ printk(msg, err); /* Make sure the message gets out of the box. */
|
||||||
|
+ panic(msg, err);
|
||||||
|
+ }
|
||||||
|
+ mcore = &ssb_bcm47xx.mipscore;
|
||||||
|
+
|
||||||
|
+ s = nvram_get("kernel_args");
|
||||||
|
+ if (s && !strncmp(s, "console=ttyS1", 13)) {
|
||||||
|
+ struct ssb_serial_port port;
|
||||||
|
+
|
||||||
|
+ printk("Swapping serial ports!\n");
|
||||||
|
+ /* swap serial ports */
|
||||||
|
+ memcpy(&port, &mcore->serial_ports[0], sizeof(port));
|
||||||
|
+ memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
|
||||||
|
+ memcpy(&mcore->serial_ports[1], &port, sizeof(port));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
|
||||||
|
- bcm47xx_get_invariants);
|
||||||
|
- if (err)
|
||||||
|
- panic("Failed to initialize SSB bus (err %d)\n", err);
|
||||||
|
+ for (i = 0; i < mcore->nr_serial_ports; i++) {
|
||||||
|
+ struct ssb_serial_port *port = &(mcore->serial_ports[i]);
|
||||||
|
+ struct uart_port s;
|
||||||
|
+
|
||||||
|
+ memset(&s, 0, sizeof(s));
|
||||||
|
+ s.line = i;
|
||||||
|
+ s.membase = port->regs;
|
||||||
|
+ s.irq = port->irq + 2;
|
||||||
|
+ s.uartclk = port->baud_base;
|
||||||
|
+ s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
|
||||||
|
+ s.iotype = SERIAL_IO_MEM;
|
||||||
|
+ s.regshift = port->reg_shift;
|
||||||
|
+
|
||||||
|
+ early_serial_setup(&s);
|
||||||
|
+ }
|
||||||
|
+ printk("Serial init done.\n");
|
||||||
|
|
||||||
|
_machine_restart = bcm47xx_machine_restart;
|
||||||
|
_machine_halt = bcm47xx_machine_halt;
|
||||||
|
pm_power_off = bcm47xx_machine_halt;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int __init bcm47xx_register_gpiodev(void)
|
||||||
|
+{
|
||||||
|
+ static struct resource res = {
|
||||||
|
+ .start = 0xFFFFFFFF,
|
||||||
|
+ };
|
||||||
|
+ struct platform_device *pdev;
|
||||||
|
+
|
||||||
|
+ pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
|
||||||
|
+ if (!pdev) {
|
||||||
|
+ printk(KERN_ERR "bcm47xx: GPIODEV init failed\n");
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+device_initcall(bcm47xx_register_gpiodev);
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/time.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/time.c 2008-05-14 14:36:58.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/time.c 2008-05-14 14:37:06.000000000 +0100
|
||||||
|
@@ -22,11 +22,17 @@
|
||||||
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
-
|
||||||
|
#include <linux/init.h>
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/sched.h>
|
||||||
|
+#include <linux/serial_reg.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
#include <linux/ssb/ssb.h>
|
||||||
|
+#include <asm/addrspace.h>
|
||||||
|
+#include <asm/io.h>
|
||||||
|
#include <asm/time.h>
|
||||||
|
-#include <bcm47xx.h>
|
||||||
|
+
|
||||||
|
+extern struct ssb_bus ssb_bcm47xx;
|
||||||
|
|
||||||
|
void __init plat_time_init(void)
|
||||||
|
{
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/nvram.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/nvram.c 2008-05-14 14:36:58.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/nvram.c 2008-05-14 14:37:06.000000000 +0100
|
||||||
|
@@ -24,10 +24,10 @@
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
-#include <nvram.h>
|
||||||
|
+#include "include/nvram.h"
|
||||||
|
|
||||||
|
#define MB * 1048576
|
||||||
|
-extern struct ssb_bus ssb;
|
||||||
|
+extern struct ssb_bus ssb_bcm47xx;
|
||||||
|
|
||||||
|
static char nvram_buf[NVRAM_SPACE];
|
||||||
|
static int cfe_env;
|
||||||
|
@@ -36,7 +36,7 @@ extern char *cfe_env_get(char *nv_buf, c
|
||||||
|
/* Probe for NVRAM header */
|
||||||
|
static void __init early_nvram_init(void)
|
||||||
|
{
|
||||||
|
- struct ssb_mipscore *mcore = &ssb.mipscore;
|
||||||
|
+ struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
|
||||||
|
struct nvram_header *header;
|
||||||
|
int i;
|
||||||
|
u32 base, lim, off;
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/Makefile
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/Makefile 2008-05-14 14:36:58.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/Makefile 2008-05-14 14:37:06.000000000 +0100
|
||||||
|
@@ -3,4 +3,4 @@
|
||||||
|
# under Linux.
|
||||||
|
#
|
||||||
|
|
||||||
|
-obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o
|
||||||
|
+obj-y := cfe_env.o gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
|
||||||
|
Index: linux-2.6.25.1/arch/mips/Kconfig
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/Kconfig 2008-05-14 14:47:43.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/Kconfig 2008-05-14 14:48:15.000000000 +0100
|
||||||
|
@@ -54,6 +54,7 @@ config BCM47XX
|
||||||
|
select SSB_DRIVER_MIPS
|
||||||
|
select SSB_DRIVER_EXTIF
|
||||||
|
select SSB_DRIVER_PCICORE
|
||||||
|
+ select SSB_B43_PCI_BRIDGE
|
||||||
|
select SSB_PCICORE_HOSTMODE if PCI
|
||||||
|
select GENERIC_GPIO
|
||||||
|
select SYS_HAS_EARLY_PRINTK
|
|
@ -1,32 +0,0 @@
|
||||||
diff -Naur a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
|
|
||||||
--- a/drivers/ide/pci/aec62xx.c 2007-10-12 18:43:44.000000000 +0200
|
|
||||||
+++ b/drivers/ide/pci/aec62xx.c 2007-11-14 14:12:51.000000000 +0100
|
|
||||||
@@ -248,7 +248,14 @@
|
|
||||||
|
|
||||||
static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d)
|
|
||||||
{
|
|
||||||
- unsigned long dma_base = pci_resource_start(dev, 4);
|
|
||||||
+ unsigned long dma_base;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ err = pci_enable_device(dev);
|
|
||||||
+ if (err)
|
|
||||||
+ return err;
|
|
||||||
+
|
|
||||||
+ dma_base = pci_resource_start(dev, 4);
|
|
||||||
|
|
||||||
if (inb(dma_base + 2) & 0x10) {
|
|
||||||
d->name = (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) ?
|
|
||||||
@@ -256,7 +263,11 @@
|
|
||||||
d->udma_mask = 0x7f; /* udma0-6 */
|
|
||||||
}
|
|
||||||
|
|
||||||
- return ide_setup_pci_device(dev, d);
|
|
||||||
+ err = ide_setup_pci_device(dev, d);
|
|
||||||
+ if(err)
|
|
||||||
+ pci_disable_device(dev);
|
|
||||||
+
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
|
|
|
@ -1,8 +1,8 @@
|
||||||
Index: linux-2.6.23.1/scripts/gen_initramfs_list.sh
|
Index: linux-2.6.25/scripts/gen_initramfs_list.sh
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.1.orig/scripts/gen_initramfs_list.sh 2007-11-16 02:26:47.821227881 +0100
|
--- linux-2.6.25.orig/scripts/gen_initramfs_list.sh 2008-04-26 21:57:00.000000000 +0100
|
||||||
+++ linux-2.6.23.1/scripts/gen_initramfs_list.sh 2007-11-16 02:45:42.753904007 +0100
|
+++ linux-2.6.25/scripts/gen_initramfs_list.sh 2008-04-26 21:57:20.000000000 +0100
|
||||||
@@ -287,7 +287,7 @@
|
@@ -287,7 +287,7 @@ if [ ! -z ${output_file} ]; then
|
||||||
if [ "${is_cpio_compressed}" = "compressed" ]; then
|
if [ "${is_cpio_compressed}" = "compressed" ]; then
|
||||||
cat ${cpio_tfile} > ${output_file}
|
cat ${cpio_tfile} > ${output_file}
|
||||||
else
|
else
|
||||||
|
@ -11,11 +11,11 @@ Index: linux-2.6.23.1/scripts/gen_initramfs_list.sh
|
||||||
fi
|
fi
|
||||||
[ -z ${cpio_file} ] && rm ${cpio_tfile}
|
[ -z ${cpio_file} ] && rm ${cpio_tfile}
|
||||||
fi
|
fi
|
||||||
Index: linux-2.6.23.1/init/initramfs.c
|
Index: linux-2.6.25/init/initramfs.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.1.orig/init/initramfs.c 2007-11-16 02:26:47.829228332 +0100
|
--- linux-2.6.25.orig/init/initramfs.c 2008-04-26 21:56:21.000000000 +0100
|
||||||
+++ linux-2.6.23.1/init/initramfs.c 2007-11-16 03:03:09.661563882 +0100
|
+++ linux-2.6.25/init/initramfs.c 2008-04-26 21:57:20.000000000 +0100
|
||||||
@@ -441,6 +441,69 @@
|
@@ -441,6 +441,69 @@ static void __init flush_window(void)
|
||||||
outcnt = 0;
|
outcnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ Index: linux-2.6.23.1/init/initramfs.c
|
||||||
static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
|
static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
|
||||||
{
|
{
|
||||||
int written;
|
int written;
|
||||||
@@ -475,12 +538,28 @@
|
@@ -475,12 +538,28 @@ static char * __init unpack_to_rootfs(ch
|
||||||
inptr = 0;
|
inptr = 0;
|
||||||
outcnt = 0; /* bytes in output buffer */
|
outcnt = 0; /* bytes in output buffer */
|
||||||
bytes_out = 0;
|
bytes_out = 0;
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-02-16 17:55:20.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-02-16 17:55:35.000000000 +0100
|
|
||||||
@@ -66,6 +66,7 @@ int pcibios_plat_dev_init(struct pci_dev
|
|
||||||
base = &ssb_pcicore_pcibus_iobase;
|
|
||||||
else
|
|
||||||
base = &ssb_pcicore_pcibus_membase;
|
|
||||||
+ res->flags |= IORESOURCE_PCI_FIXED;
|
|
||||||
if (res->end) {
|
|
||||||
size = res->end - res->start + 1;
|
|
||||||
if (*base & (size - 1))
|
|
||||||
@@ -88,10 +89,12 @@ int pcibios_plat_dev_init(struct pci_dev
|
|
||||||
|
|
||||||
static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
+ u8 lat;
|
|
||||||
+
|
|
||||||
if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
- ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
|
|
||||||
+ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
|
|
||||||
|
|
||||||
/* Enable PCI bridge bus mastering and memory space */
|
|
||||||
pci_set_master(dev);
|
|
||||||
@@ -101,7 +104,10 @@ static void __init ssb_fixup_pcibridge(s
|
|
||||||
pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
|
|
||||||
|
|
||||||
/* Make sure our latency is high enough to handle the devices behind us */
|
|
||||||
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
|
|
||||||
+ lat = 168;
|
|
||||||
+ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
|
|
||||||
+ pci_name(dev), lat);
|
|
||||||
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
|
|
||||||
}
|
|
||||||
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
|
|
||||||
|
|
||||||
@@ -279,14 +285,14 @@ static struct resource ssb_pcicore_mem_r
|
|
||||||
.name = "SSB PCIcore external memory",
|
|
||||||
.start = SSB_PCI_DMA,
|
|
||||||
.end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
|
|
||||||
- .flags = IORESOURCE_MEM,
|
|
||||||
+ .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct resource ssb_pcicore_io_resource = {
|
|
||||||
.name = "SSB PCIcore external I/O",
|
|
||||||
.start = 0x100,
|
|
||||||
.end = 0x7FF,
|
|
||||||
- .flags = IORESOURCE_IO,
|
|
||||||
+ .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct pci_controller ssb_pcicore_controller = {
|
|
||||||
@@ -344,7 +350,8 @@ static void ssb_pcicore_init_hostmode(st
|
|
||||||
/* Ok, ready to run, register it to the system.
|
|
||||||
* The following needs change, if we want to port hostmode
|
|
||||||
* to non-MIPS platform. */
|
|
||||||
- set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
|
|
||||||
+ ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000);
|
|
||||||
+ set_io_port_base(ssb_pcicore_controller.io_map_base);
|
|
||||||
/* Give some time to the PCI controller to configure itself with the new
|
|
||||||
* values. Not waiting at this point causes crashes of the machine. */
|
|
||||||
mdelay(10);
|
|
|
@ -2,20 +2,23 @@ The SSB pcicore driver does create some MMIO resource collisions.
|
||||||
However, the pcicore PCI-fixup routine fixes these collisions afterwards.
|
However, the pcicore PCI-fixup routine fixes these collisions afterwards.
|
||||||
Remove this sanity check for now until we find a better solution.
|
Remove this sanity check for now until we find a better solution.
|
||||||
--mb
|
--mb
|
||||||
Index: linux-2.6.23.16/arch/mips/pci/pci.c
|
Index: linux-2.6.25.1/arch/mips/pci/pci.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/arch/mips/pci/pci.c 2008-02-16 17:55:20.000000000 +0100
|
--- linux-2.6.25.1.orig/arch/mips/pci/pci.c 2008-05-08 22:37:55.000000000 +0100
|
||||||
+++ linux-2.6.23.16/arch/mips/pci/pci.c 2008-02-16 17:57:39.000000000 +0100
|
+++ linux-2.6.25.1/arch/mips/pci/pci.c 2008-05-09 07:39:55.000000000 +0100
|
||||||
@@ -177,10 +177,8 @@ static int pcibios_enable_resources(stru
|
@@ -182,12 +182,10 @@ static int pcibios_enable_resources(stru
|
||||||
|
if ((idx == PCI_ROM_RESOURCE) &&
|
||||||
|
(!(r->flags & IORESOURCE_ROM_ENABLE)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = &dev->resource[idx];
|
|
||||||
- if (!r->start && r->end) {
|
- if (!r->start && r->end) {
|
||||||
- printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
|
- printk(KERN_ERR "PCI: Device %s not available "
|
||||||
|
- "because of resource collisions\n",
|
||||||
|
+ if (!r->start && r->end)
|
||||||
|
+ printk(KERN_WARNING "PCI: Device %s resource"
|
||||||
|
+ "collisions detected. Ignoring...\n",
|
||||||
|
pci_name(dev));
|
||||||
- return -EINVAL;
|
- return -EINVAL;
|
||||||
- }
|
- }
|
||||||
+ if (!r->start && r->end)
|
|
||||||
+ printk(KERN_WARNING "PCI: Device %s resource collisions detected. Ignoring...\n", pci_name(dev));
|
|
||||||
if (r->flags & IORESOURCE_IO)
|
if (r->flags & IORESOURCE_IO)
|
||||||
cmd |= PCI_COMMAND_IO;
|
cmd |= PCI_COMMAND_IO;
|
||||||
if (r->flags & IORESOURCE_MEM)
|
if (r->flags & IORESOURCE_MEM)
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:26.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 14:37:27.000000000 +0100
|
|
||||||
@@ -403,6 +403,7 @@ int ssb_chipco_serial_init(struct ssb_ch
|
|
||||||
unsigned int irq;
|
|
||||||
u32 baud_base, div;
|
|
||||||
u32 i, n;
|
|
||||||
+ unsigned int ccrev = cc->dev->id.revision;
|
|
||||||
|
|
||||||
plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
|
|
||||||
irq = ssb_mips_irq(cc->dev);
|
|
||||||
@@ -414,14 +415,39 @@ int ssb_chipco_serial_init(struct ssb_ch
|
|
||||||
chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
|
|
||||||
div = 1;
|
|
||||||
} else {
|
|
||||||
- if (cc->dev->id.revision >= 11) {
|
|
||||||
+ if (ccrev == 20) {
|
|
||||||
+ /* BCM5354 uses constant 25MHz clock */
|
|
||||||
+ baud_base = 25000000;
|
|
||||||
+ div = 48;
|
|
||||||
+ /* Set the override bit so we don't divide it */
|
|
||||||
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
|
|
||||||
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
|
|
||||||
+ | SSB_CHIPCO_CORECTL_UARTCLK0);
|
|
||||||
+ } else if ((ccrev >= 11) && (ccrev != 15)) {
|
|
||||||
/* Fixed ALP clock */
|
|
||||||
baud_base = 20000000;
|
|
||||||
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
|
|
||||||
+ /* FIXME: baud_base is different for devices with a PMU */
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ }
|
|
||||||
div = 1;
|
|
||||||
+ if (ccrev >= 21) {
|
|
||||||
+ /* Turn off UART clock before switching clocksource. */
|
|
||||||
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
|
|
||||||
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
|
|
||||||
+ & ~SSB_CHIPCO_CORECTL_UARTCLKEN);
|
|
||||||
+ }
|
|
||||||
/* Set the override bit so we don't divide it */
|
|
||||||
chipco_write32(cc, SSB_CHIPCO_CORECTL,
|
|
||||||
- SSB_CHIPCO_CORECTL_UARTCLK0);
|
|
||||||
- } else if (cc->dev->id.revision >= 3) {
|
|
||||||
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
|
|
||||||
+ | SSB_CHIPCO_CORECTL_UARTCLK0);
|
|
||||||
+ if (ccrev >= 21) {
|
|
||||||
+ /* Re-enable the UART clock. */
|
|
||||||
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
|
|
||||||
+ chipco_read32(cc, SSB_CHIPCO_CORECTL)
|
|
||||||
+ | SSB_CHIPCO_CORECTL_UARTCLKEN);
|
|
||||||
+ }
|
|
||||||
+ } else if (ccrev >= 3) {
|
|
||||||
/* Internal backplane clock */
|
|
||||||
baud_base = ssb_clockspeed(bus);
|
|
||||||
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
|
|
||||||
@@ -433,7 +459,7 @@ int ssb_chipco_serial_init(struct ssb_ch
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clock source depends on strapping if UartClkOverride is unset */
|
|
||||||
- if ((cc->dev->id.revision > 0) &&
|
|
||||||
+ if ((ccrev > 0) &&
|
|
||||||
!(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
|
|
||||||
if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
|
|
||||||
SSB_CHIPCO_CAP_UARTCLK_INT) {
|
|
||||||
@@ -455,7 +481,7 @@ int ssb_chipco_serial_init(struct ssb_ch
|
|
||||||
cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
|
|
||||||
uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
|
|
||||||
/* Offset changed at after rev 0 */
|
|
||||||
- if (cc->dev->id.revision == 0)
|
|
||||||
+ if (ccrev == 0)
|
|
||||||
uart_regs += (i * 8);
|
|
||||||
else
|
|
||||||
uart_regs += (i * 256);
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:26.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 14:37:27.000000000 +0100
|
|
||||||
@@ -51,9 +51,12 @@
|
|
||||||
#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */
|
|
||||||
#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */
|
|
||||||
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
|
|
||||||
+#define SSB_CHIPCO_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
|
|
||||||
+#define SSB_CHIPCO_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
|
|
||||||
#define SSB_CHIPCO_CORECTL 0x0008
|
|
||||||
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
|
|
||||||
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
|
|
||||||
+#define SSB_CHIPCO_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */
|
|
||||||
#define SSB_CHIPCO_BIST 0x000C
|
|
||||||
#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */
|
|
||||||
#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000
|
|
|
@ -1,133 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/Kconfig
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/Kconfig 2008-02-19 13:46:05.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/Kconfig 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -105,6 +105,12 @@ config SSB_DRIVER_MIPS
|
|
||||||
|
|
||||||
If unsure, say N
|
|
||||||
|
|
||||||
+# Assumption: We are on embedded, if we compile the MIPS core.
|
|
||||||
+config SSB_EMBEDDED
|
|
||||||
+ bool
|
|
||||||
+ depends on SSB_DRIVER_MIPS
|
|
||||||
+ default y
|
|
||||||
+
|
|
||||||
config SSB_DRIVER_EXTIF
|
|
||||||
bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
|
|
||||||
depends on SSB_DRIVER_MIPS && EXPERIMENTAL
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/Makefile
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/Makefile 2008-02-19 13:46:05.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/Makefile 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -1,5 +1,6 @@
|
|
||||||
# core
|
|
||||||
ssb-y += main.o scan.o
|
|
||||||
+ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o
|
|
||||||
|
|
||||||
# host support
|
|
||||||
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 13:46:05.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -37,6 +37,12 @@ static inline u32 extif_write32_masked(s
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
+void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
|
|
||||||
+ u32 ticks)
|
|
||||||
+{
|
|
||||||
+ extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
static bool serial_exists(u8 *regs)
|
|
||||||
{
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/embedded.c
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -0,0 +1,26 @@
|
|
||||||
+/*
|
|
||||||
+ * Sonics Silicon Backplane
|
|
||||||
+ * Embedded systems support code
|
|
||||||
+ *
|
|
||||||
+ * Copyright 2005-2008, Broadcom Corporation
|
|
||||||
+ * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
|
|
||||||
+ *
|
|
||||||
+ * Licensed under the GNU/GPL. See COPYING for details.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include <linux/ssb/ssb.h>
|
|
||||||
+#include <linux/ssb/ssb_embedded.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)
|
|
||||||
+{
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco)) {
|
|
||||||
+ ssb_chipco_watchdog_timer_set(&bus->chipco, ticks);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ if (ssb_extif_available(&bus->extif)) {
|
|
||||||
+ ssb_extif_watchdog_timer_set(&bus->extif, ticks);
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ return -ENODEV;
|
|
||||||
+}
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 13:46:29.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -360,6 +360,11 @@ struct ssb_chipcommon {
|
|
||||||
u16 fast_pwrup_delay;
|
|
||||||
};
|
|
||||||
|
|
||||||
+static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
|
|
||||||
+{
|
|
||||||
+ return (cc->dev != NULL);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
extern void ssb_chipcommon_init(struct ssb_chipcommon *cc);
|
|
||||||
|
|
||||||
#include <linux/pm.h>
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h 2008-02-19 13:46:05.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -178,6 +178,9 @@ u32 ssb_extif_gpio_outen(struct ssb_exti
|
|
||||||
u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value);
|
|
||||||
|
|
||||||
+extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
|
|
||||||
+ u32 ticks);
|
|
||||||
+
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
extern int ssb_extif_serial_init(struct ssb_extif *extif,
|
|
||||||
struct ssb_serial_port *ports);
|
|
||||||
@@ -201,5 +204,11 @@ void ssb_extif_get_clockcontrol(struct s
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline
|
|
||||||
+void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
|
|
||||||
+ u32 ticks)
|
|
||||||
+{
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#endif /* CONFIG_SSB_DRIVER_EXTIF */
|
|
||||||
#endif /* LINUX_SSB_EXTIFCORE_H_ */
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h 2008-02-19 13:46:33.000000000 +0100
|
|
||||||
@@ -0,0 +1,10 @@
|
|
||||||
+#ifndef LINUX_SSB_EMBEDDED_H_
|
|
||||||
+#define LINUX_SSB_EMBEDDED_H_
|
|
||||||
+
|
|
||||||
+#include <linux/types.h>
|
|
||||||
+#include <linux/ssb/ssb.h>
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks);
|
|
||||||
+
|
|
||||||
+#endif /* LINUX_SSB_EMBEDDED_H_ */
|
|
|
@ -1,8 +1,8 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
Index: linux-2.6.25.1/drivers/ssb/main.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 12:38:34.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/main.c 2008-05-10 08:35:23.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 12:48:25.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/main.c 2008-05-10 09:04:53.000000000 +0100
|
||||||
@@ -1163,7 +1163,9 @@ static int __init ssb_modinit(void)
|
@@ -1173,7 +1173,9 @@ static int __init ssb_modinit(void)
|
||||||
/* ssb must be initialized after PCI but before the ssb drivers.
|
/* ssb must be initialized after PCI but before the ssb drivers.
|
||||||
* That means we must use some initcall between subsys_initcall
|
* That means we must use some initcall between subsys_initcall
|
||||||
* and device_initcall. */
|
* and device_initcall. */
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
@@ -361,37 +361,31 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco
|
|
||||||
{
|
|
||||||
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_in);
|
|
||||||
|
|
||||||
u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_out);
|
|
||||||
|
|
||||||
u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_outen);
|
|
||||||
|
|
||||||
u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_control);
|
|
||||||
|
|
||||||
u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_intmask);
|
|
||||||
|
|
||||||
u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_chipco_gpio_polarity);
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_SERIAL
|
|
||||||
int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
@@ -122,30 +122,25 @@ u32 ssb_extif_gpio_in(struct ssb_extif *
|
|
||||||
{
|
|
||||||
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_extif_gpio_in);
|
|
||||||
|
|
||||||
u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
|
|
||||||
mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_extif_gpio_out);
|
|
||||||
|
|
||||||
u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
|
|
||||||
mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_extif_gpio_outen);
|
|
||||||
|
|
||||||
u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_extif_gpio_polarity);
|
|
||||||
|
|
||||||
u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
|
|
||||||
{
|
|
||||||
return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
|
|
||||||
}
|
|
||||||
-EXPORT_SYMBOL(ssb_extif_gpio_intmask);
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/embedded.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/embedded.c 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-02-19 15:51:01.000000000 +0100
|
|
||||||
@@ -11,6 +11,8 @@
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
#include <linux/ssb/ssb_embedded.h>
|
|
||||||
|
|
||||||
+#include "ssb_private.h"
|
|
||||||
+
|
|
||||||
|
|
||||||
int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)
|
|
||||||
{
|
|
||||||
@@ -24,3 +26,107 @@ int ssb_watchdog_timer_set(struct ssb_bu
|
|
||||||
}
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_in(&bus->chipco, mask);
|
|
||||||
+ else if (ssb_extif_available(&bus->extif))
|
|
||||||
+ res = ssb_extif_gpio_in(&bus->extif, mask);
|
|
||||||
+ else
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_in);
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_out(&bus->chipco, mask, value);
|
|
||||||
+ else if (ssb_extif_available(&bus->extif))
|
|
||||||
+ res = ssb_extif_gpio_out(&bus->extif, mask, value);
|
|
||||||
+ else
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_out);
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_outen(&bus->chipco, mask, value);
|
|
||||||
+ else if (ssb_extif_available(&bus->extif))
|
|
||||||
+ res = ssb_extif_gpio_outen(&bus->extif, mask, value);
|
|
||||||
+ else
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_outen);
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_control(&bus->chipco, mask, value);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_control);
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value);
|
|
||||||
+ else if (ssb_extif_available(&bus->extif))
|
|
||||||
+ res = ssb_extif_gpio_intmask(&bus->extif, mask, value);
|
|
||||||
+ else
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_intmask);
|
|
||||||
+
|
|
||||||
+u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value)
|
|
||||||
+{
|
|
||||||
+ unsigned long flags;
|
|
||||||
+ u32 res = 0;
|
|
||||||
+
|
|
||||||
+ spin_lock_irqsave(&bus->gpio_lock, flags);
|
|
||||||
+ if (ssb_chipco_available(&bus->chipco))
|
|
||||||
+ res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value);
|
|
||||||
+ else if (ssb_extif_available(&bus->extif))
|
|
||||||
+ res = ssb_extif_gpio_polarity(&bus->extif, mask, value);
|
|
||||||
+ else
|
|
||||||
+ SSB_WARN_ON(1);
|
|
||||||
+ spin_unlock_irqrestore(&bus->gpio_lock, flags);
|
|
||||||
+
|
|
||||||
+ return res;
|
|
||||||
+}
|
|
||||||
+EXPORT_SYMBOL(ssb_gpio_polarity);
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
@@ -283,6 +283,11 @@ struct ssb_bus {
|
|
||||||
/* Contents of the SPROM. */
|
|
||||||
struct ssb_sprom sprom;
|
|
||||||
|
|
||||||
+#ifdef CONFIG_SSB_EMBEDDED
|
|
||||||
+ /* Lock for GPIO register access. */
|
|
||||||
+ spinlock_t gpio_lock;
|
|
||||||
+#endif /* EMBEDDED */
|
|
||||||
+
|
|
||||||
/* Internal-only stuff follows. Do not touch. */
|
|
||||||
struct list_head list;
|
|
||||||
#ifdef CONFIG_SSB_DEBUG
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_embedded.h 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
@@ -7,4 +7,12 @@
|
|
||||||
|
|
||||||
extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks);
|
|
||||||
|
|
||||||
+/* Generic GPIO API */
|
|
||||||
+u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask);
|
|
||||||
+u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value);
|
|
||||||
+u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value);
|
|
||||||
+u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value);
|
|
||||||
+u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value);
|
|
||||||
+u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value);
|
|
||||||
+
|
|
||||||
#endif /* LINUX_SSB_EMBEDDED_H_ */
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 15:50:42.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
@@ -571,6 +571,9 @@ static int ssb_bus_register(struct ssb_b
|
|
||||||
|
|
||||||
spin_lock_init(&bus->bar_lock);
|
|
||||||
INIT_LIST_HEAD(&bus->list);
|
|
||||||
+#ifdef CONFIG_SSB_EMBEDDED
|
|
||||||
+ spin_lock_init(&bus->gpio_lock);
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
/* Powerup the bus */
|
|
||||||
err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
|
|
|
@ -1,116 +0,0 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-02-19 16:37:14.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-02-19 17:25:26.000000000 +0100
|
|
||||||
@@ -11,6 +11,7 @@
|
|
||||||
#include <linux/ssb/ssb.h>
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
+#include <linux/ssb/ssb_embedded.h>
|
|
||||||
|
|
||||||
#include "ssb_private.h"
|
|
||||||
|
|
||||||
@@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore
|
|
||||||
ssb_write32(pc->dev, offset, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline
|
|
||||||
+u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset)
|
|
||||||
+{
|
|
||||||
+ return ssb_read16(pc->dev, offset);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static inline
|
|
||||||
+void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value)
|
|
||||||
+{
|
|
||||||
+ ssb_write16(pc->dev, offset, value);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/**************************************************
|
|
||||||
* Code for hostmode operation.
|
|
||||||
**************************************************/
|
|
||||||
@@ -123,8 +136,10 @@ static u32 get_cfgspace_addr(struct ssb_
|
|
||||||
u32 addr = 0;
|
|
||||||
u32 tmp;
|
|
||||||
|
|
||||||
- if (unlikely(pc->cardbusmode && dev > 1))
|
|
||||||
+ /* We do only have one cardbus device behind the bridge. */
|
|
||||||
+ if (pc->cardbusmode && (dev >= 1))
|
|
||||||
goto out;
|
|
||||||
+
|
|
||||||
if (bus == 0) {
|
|
||||||
/* Type 0 transaction */
|
|
||||||
if (unlikely(dev >= SSB_PCI_SLOT_MAX))
|
|
||||||
@@ -324,7 +339,16 @@ static void ssb_pcicore_init_hostmode(st
|
|
||||||
pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
|
|
||||||
udelay(1); /* Assertion time demanded by the PCI standard */
|
|
||||||
|
|
||||||
- /*TODO cardbus mode */
|
|
||||||
+ if (pc->dev->bus->has_cardbus_slot) {
|
|
||||||
+ ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
|
|
||||||
+ pc->cardbusmode = 1;
|
|
||||||
+ /* GPIO 1 resets the bridge */
|
|
||||||
+ ssb_gpio_out(pc->dev->bus, 1, 1);
|
|
||||||
+ ssb_gpio_outen(pc->dev->bus, 1, 1);
|
|
||||||
+ pcicore_write16(pc, SSB_PCICORE_SPROM(0),
|
|
||||||
+ pcicore_read16(pc, SSB_PCICORE_SPROM(0))
|
|
||||||
+ | 0x0400);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* 64MB I/O window */
|
|
||||||
pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
|
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 16:38:31.000000000 +0100
|
|
||||||
@@ -559,6 +559,7 @@ static int ssb_fetch_invariants(struct s
|
|
||||||
goto out;
|
|
||||||
memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
|
|
||||||
memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
|
|
||||||
+ bus->has_cardbus_slot = iv.has_cardbus_slot;
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-19 15:50:44.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-19 16:38:31.000000000 +0100
|
|
||||||
@@ -282,6 +282,8 @@ struct ssb_bus {
|
|
||||||
struct ssb_boardinfo boardinfo;
|
|
||||||
/* Contents of the SPROM. */
|
|
||||||
struct ssb_sprom sprom;
|
|
||||||
+ /* If the board has a cardbus slot, this is set to true. */
|
|
||||||
+ bool has_cardbus_slot;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SSB_EMBEDDED
|
|
||||||
/* Lock for GPIO register access. */
|
|
||||||
@@ -299,8 +301,13 @@ struct ssb_bus {
|
|
||||||
|
|
||||||
/* The initialization-invariants. */
|
|
||||||
struct ssb_init_invariants {
|
|
||||||
+ /* Versioning information about the PCB. */
|
|
||||||
struct ssb_boardinfo boardinfo;
|
|
||||||
+ /* The SPROM information. That's either stored in an
|
|
||||||
+ * EEPROM or NVRAM on the board. */
|
|
||||||
struct ssb_sprom sprom;
|
|
||||||
+ /* If the board has a cardbus slot, this is set to true. */
|
|
||||||
+ bool has_cardbus_slot;
|
|
||||||
};
|
|
||||||
/* Type of function to fetch the invariants. */
|
|
||||||
typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus,
|
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
|
|
||||||
===================================================================
|
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h 2008-02-13 20:27:17.000000000 +0100
|
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-02-19 17:31:47.000000000 +0100
|
|
||||||
@@ -51,6 +51,11 @@
|
|
||||||
#define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000
|
|
||||||
#define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */
|
|
||||||
#define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000
|
|
||||||
+#define SSB_PCICORE_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */
|
|
||||||
+#define SSB_PCICORE_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */
|
|
||||||
+#define SSB_PCICORE_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */
|
|
||||||
+#define SSB_PCICORE_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */
|
|
||||||
+#define SSB_PCICORE_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */
|
|
||||||
|
|
||||||
/* SBtoPCIx */
|
|
||||||
#define SSB_PCICORE_SBTOPCI_MEM 0x00000000
|
|
|
@ -1,9 +1,9 @@
|
||||||
Add support for 8bit reads/writes to SSB.
|
Add support for 8bit reads/writes to SSB.
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
Index: linux-2.6.25.1/drivers/ssb/main.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-20 14:10:07.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/main.c 2008-05-10 09:04:53.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:34:48.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/main.c 2008-05-10 09:05:38.000000000 +0100
|
||||||
@@ -507,6 +507,14 @@ error:
|
@@ -508,6 +508,14 @@ error:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
|
static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
struct ssb_bus *bus = dev->bus;
|
||||||
@@ -523,6 +531,14 @@ static u32 ssb_ssb_read32(struct ssb_dev
|
@@ -524,6 +532,14 @@ static u32 ssb_ssb_read32(struct ssb_dev
|
||||||
return readl(bus->mmio + offset);
|
return readl(bus->mmio + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
|
static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
struct ssb_bus *bus = dev->bus;
|
||||||
@@ -541,8 +557,10 @@ static void ssb_ssb_write32(struct ssb_d
|
@@ -542,8 +558,10 @@ static void ssb_ssb_write32(struct ssb_d
|
||||||
|
|
||||||
/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
|
/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
|
||||||
static const struct ssb_bus_ops ssb_ssb_ops = {
|
static const struct ssb_bus_ops ssb_ssb_ops = {
|
||||||
|
@ -44,11 +44,11 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
.write16 = ssb_ssb_write16,
|
.write16 = ssb_ssb_write16,
|
||||||
.write32 = ssb_ssb_write32,
|
.write32 = ssb_ssb_write32,
|
||||||
};
|
};
|
||||||
Index: linux-2.6.23.16/drivers/ssb/pci.c
|
Index: linux-2.6.25.1/drivers/ssb/pci.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/pci.c 2008-02-20 14:10:03.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/pci.c 2008-05-10 09:04:53.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/pci.c 2008-02-20 14:10:07.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/pci.c 2008-05-10 09:05:38.000000000 +0100
|
||||||
@@ -572,6 +572,19 @@ static inline int ssb_pci_assert_buspowe
|
@@ -577,6 +577,19 @@ static inline int ssb_pci_assert_buspowe
|
||||||
}
|
}
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
|
||||||
static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
|
static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
struct ssb_bus *bus = dev->bus;
|
||||||
@@ -598,6 +611,19 @@ static u32 ssb_pci_read32(struct ssb_dev
|
@@ -603,6 +616,19 @@ static u32 ssb_pci_read32(struct ssb_dev
|
||||||
return ioread32(bus->mmio + offset);
|
return ioread32(bus->mmio + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
|
||||||
static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
|
static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
struct ssb_bus *bus = dev->bus;
|
||||||
@@ -626,8 +652,10 @@ static void ssb_pci_write32(struct ssb_d
|
@@ -631,8 +657,10 @@ static void ssb_pci_write32(struct ssb_d
|
||||||
|
|
||||||
/* Not "static", as it's used in main.c */
|
/* Not "static", as it's used in main.c */
|
||||||
const struct ssb_bus_ops ssb_pci_ops = {
|
const struct ssb_bus_ops ssb_pci_ops = {
|
||||||
|
@ -99,10 +99,10 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
|
||||||
.write16 = ssb_pci_write16,
|
.write16 = ssb_pci_write16,
|
||||||
.write32 = ssb_pci_write32,
|
.write32 = ssb_pci_write32,
|
||||||
};
|
};
|
||||||
Index: linux-2.6.23.16/drivers/ssb/pcmcia.c
|
Index: linux-2.6.25.1/drivers/ssb/pcmcia.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/pcmcia.c 2008-02-20 14:10:03.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/pcmcia.c 2008-05-10 09:04:53.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/pcmcia.c 2008-02-20 14:10:07.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/pcmcia.c 2008-05-10 09:05:38.000000000 +0100
|
||||||
@@ -172,6 +172,22 @@ static int select_core_and_segment(struc
|
@@ -172,6 +172,22 @@ static int select_core_and_segment(struc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -158,10 +158,10 @@ Index: linux-2.6.23.16/drivers/ssb/pcmcia.c
|
||||||
.write16 = ssb_pcmcia_write16,
|
.write16 = ssb_pcmcia_write16,
|
||||||
.write32 = ssb_pcmcia_write32,
|
.write32 = ssb_pcmcia_write32,
|
||||||
};
|
};
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
Index: linux-2.6.25.1/include/linux/ssb/ssb.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-02-20 14:10:07.000000000 +0100
|
--- linux-2.6.25.1.orig/include/linux/ssb/ssb.h 2008-05-10 09:04:53.000000000 +0100
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-02-20 18:33:21.000000000 +0100
|
+++ linux-2.6.25.1/include/linux/ssb/ssb.h 2008-05-10 09:05:38.000000000 +0100
|
||||||
@@ -72,8 +72,10 @@ struct ssb_device;
|
@@ -72,8 +72,10 @@ struct ssb_device;
|
||||||
/* Lowlevel read/write operations on the device MMIO.
|
/* Lowlevel read/write operations on the device MMIO.
|
||||||
* Internal, don't use that outside of ssb. */
|
* Internal, don't use that outside of ssb. */
|
||||||
|
@ -173,7 +173,7 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
||||||
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
|
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
|
||||||
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
|
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
|
||||||
};
|
};
|
||||||
@@ -344,6 +346,10 @@ void ssb_device_disable(struct ssb_devic
|
@@ -348,6 +350,10 @@ void ssb_device_disable(struct ssb_devic
|
||||||
|
|
||||||
|
|
||||||
/* Device MMIO register read/write functions. */
|
/* Device MMIO register read/write functions. */
|
||||||
|
@ -184,7 +184,7 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
||||||
static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
|
static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
|
||||||
{
|
{
|
||||||
return dev->ops->read16(dev, offset);
|
return dev->ops->read16(dev, offset);
|
||||||
@@ -352,6 +358,10 @@ static inline u32 ssb_read32(struct ssb_
|
@@ -356,6 +362,10 @@ static inline u32 ssb_read32(struct ssb_
|
||||||
{
|
{
|
||||||
return dev->ops->read32(dev, offset);
|
return dev->ops->read32(dev, offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
Allow registering PCI devices after early boot.
|
Allow registering PCI devices after early boot.
|
||||||
|
|
||||||
This is an ugly hack and needs to be rewritten before going upstream.
|
This is an ugly hack and needs to be rewritten before going upstream.
|
||||||
Index: linux-2.6.23.16/arch/mips/pci/pci.c
|
Index: linux-2.6.25/arch/mips/pci/pci.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/arch/mips/pci/pci.c 2008-02-20 16:06:36.000000000 +0100
|
--- linux-2.6.25.orig/arch/mips/pci/pci.c 2008-04-27 21:49:19.000000000 +0100
|
||||||
+++ linux-2.6.23.16/arch/mips/pci/pci.c 2008-02-20 16:09:33.000000000 +0100
|
+++ linux-2.6.25/arch/mips/pci/pci.c 2008-04-27 21:58:31.000000000 +0100
|
||||||
@@ -21,6 +21,17 @@
|
@@ -21,6 +21,17 @@
|
||||||
*/
|
*/
|
||||||
int pci_probe_only;
|
int pci_probe_only;
|
||||||
|
@ -146,11 +146,11 @@ Index: linux-2.6.23.16/arch/mips/pci/pci.c
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
Index: linux-2.6.25/drivers/ssb/main.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-02-20 16:06:36.000000000 +0100
|
--- linux-2.6.25.orig/drivers/ssb/main.c 2008-04-27 21:55:32.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:33:21.000000000 +0100
|
+++ linux-2.6.25/drivers/ssb/main.c 2008-04-27 21:58:31.000000000 +0100
|
||||||
@@ -1185,9 +1185,7 @@ static int __init ssb_modinit(void)
|
@@ -1191,9 +1191,7 @@ static int __init ssb_modinit(void)
|
||||||
/* ssb must be initialized after PCI but before the ssb drivers.
|
/* ssb must be initialized after PCI but before the ssb drivers.
|
||||||
* That means we must use some initcall between subsys_initcall
|
* That means we must use some initcall between subsys_initcall
|
||||||
* and device_initcall. */
|
* and device_initcall. */
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Index: linux-2.6.23.16/drivers/ssb/Kconfig
|
Index: linux-2.6.25.1/drivers/ssb/Kconfig
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/Kconfig 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/Kconfig 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/Kconfig 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/Kconfig 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -120,4 +120,13 @@ config SSB_DRIVER_EXTIF
|
@@ -125,4 +125,13 @@ config SSB_DRIVER_EXTIF
|
||||||
|
|
||||||
If unsure, say N
|
If unsure, say N
|
||||||
|
|
||||||
|
@ -16,10 +16,10 @@ Index: linux-2.6.23.16/drivers/ssb/Kconfig
|
||||||
+ If unsure, say N
|
+ If unsure, say N
|
||||||
+
|
+
|
||||||
endmenu
|
endmenu
|
||||||
Index: linux-2.6.23.16/drivers/ssb/Makefile
|
Index: linux-2.6.25.1/drivers/ssb/Makefile
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/Makefile 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/Makefile 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/Makefile 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/Makefile 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o
|
@@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o
|
||||||
ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
|
ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
|
||||||
ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
|
ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
|
||||||
|
@ -28,10 +28,10 @@ Index: linux-2.6.23.16/drivers/ssb/Makefile
|
||||||
|
|
||||||
# b43 pci-ssb-bridge driver
|
# b43 pci-ssb-bridge driver
|
||||||
# Not strictly a part of SSB, but kept here for convenience
|
# Not strictly a part of SSB, but kept here for convenience
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_gige.c
|
Index: linux-2.6.25.1/drivers/ssb/driver_gige.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_gige.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/driver_gige.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -0,0 +1,294 @@
|
@@ -0,0 +1,294 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Sonics Silicon Backplane
|
+ * Sonics Silicon Backplane
|
||||||
|
@ -327,10 +327,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_gige.c
|
||||||
+{
|
+{
|
||||||
+ return ssb_driver_register(&ssb_gige_driver);
|
+ return ssb_driver_register(&ssb_gige_driver);
|
||||||
+}
|
+}
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h
|
Index: linux-2.6.25.1/include/linux/ssb/ssb_driver_gige.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/include/linux/ssb/ssb_driver_gige.h 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -0,0 +1,174 @@
|
@@ -0,0 +1,174 @@
|
||||||
+#ifndef LINUX_SSB_DRIVER_GIGE_H_
|
+#ifndef LINUX_SSB_DRIVER_GIGE_H_
|
||||||
+#define LINUX_SSB_DRIVER_GIGE_H_
|
+#define LINUX_SSB_DRIVER_GIGE_H_
|
||||||
|
@ -506,11 +506,11 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h
|
||||||
+
|
+
|
||||||
+#endif /* CONFIG_SSB_DRIVER_GIGE */
|
+#endif /* CONFIG_SSB_DRIVER_GIGE */
|
||||||
+#endif /* LINUX_SSB_DRIVER_GIGE_H_ */
|
+#endif /* LINUX_SSB_DRIVER_GIGE_H_ */
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
Index: linux-2.6.25.1/drivers/ssb/driver_pcicore.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/driver_pcicore.c 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/driver_pcicore.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -60,74 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock);
|
@@ -60,78 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock);
|
||||||
/* Core to access the external PCI config space. Can only have one. */
|
/* Core to access the external PCI config space. Can only have one. */
|
||||||
static struct ssb_pcicore *extpci_core;
|
static struct ssb_pcicore *extpci_core;
|
||||||
|
|
||||||
|
@ -565,7 +565,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
||||||
-
|
-
|
||||||
- /* Enable PCI bridge bus mastering and memory space */
|
- /* Enable PCI bridge bus mastering and memory space */
|
||||||
- pci_set_master(dev);
|
- pci_set_master(dev);
|
||||||
- pcibios_enable_device(dev, ~0);
|
- if (pcibios_enable_device(dev, ~0) < 0) {
|
||||||
|
- ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
-
|
-
|
||||||
- /* Enable PCI bridge BAR1 prefetch and burst */
|
- /* Enable PCI bridge BAR1 prefetch and burst */
|
||||||
- pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
|
- pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
|
||||||
|
@ -582,10 +585,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
||||||
-{
|
-{
|
||||||
- return ssb_mips_irq(extpci_core->dev) + 2;
|
- return ssb_mips_irq(extpci_core->dev) + 2;
|
||||||
-}
|
-}
|
||||||
|
-
|
||||||
static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
|
static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
|
||||||
unsigned int bus, unsigned int dev,
|
unsigned int bus, unsigned int dev,
|
||||||
@@ -317,6 +249,92 @@ static struct pci_controller ssb_pcicore
|
unsigned int func, unsigned int off)
|
||||||
|
@@ -320,6 +248,95 @@ static struct pci_controller ssb_pcicore
|
||||||
.mem_offset = 0x24000000,
|
.mem_offset = 0x24000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -652,7 +656,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
||||||
+
|
+
|
||||||
+ /* Enable PCI bridge bus mastering and memory space */
|
+ /* Enable PCI bridge bus mastering and memory space */
|
||||||
+ pci_set_master(dev);
|
+ pci_set_master(dev);
|
||||||
+ pcibios_enable_device(dev, ~0);
|
+ if (pcibios_enable_device(dev, ~0) < 0) {
|
||||||
|
+ ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Enable PCI bridge BAR1 prefetch and burst */
|
+ /* Enable PCI bridge BAR1 prefetch and burst */
|
||||||
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
|
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
|
||||||
|
@ -678,10 +685,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
|
||||||
static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
|
static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
Index: linux-2.6.23.16/drivers/ssb/embedded.c
|
Index: linux-2.6.25.1/drivers/ssb/embedded.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/embedded.c 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/embedded.c 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/embedded.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/embedded.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -10,6 +10,9 @@
|
@@ -10,6 +10,9 @@
|
||||||
|
|
||||||
#include <linux/ssb/ssb.h>
|
#include <linux/ssb/ssb.h>
|
||||||
|
@ -783,11 +790,11 @@ Index: linux-2.6.23.16/drivers/ssb/embedded.c
|
||||||
+
|
+
|
||||||
+ return -ENODEV;
|
+ return -ENODEV;
|
||||||
+}
|
+}
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
Index: linux-2.6.25.1/include/linux/ssb/ssb.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb.h 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/include/linux/ssb/ssb.h 2008-05-07 22:45:33.000000000 +0100
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb.h 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/include/linux/ssb/ssb.h 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -422,5 +422,12 @@ extern int ssb_bus_powerup(struct ssb_bu
|
@@ -426,5 +426,12 @@ extern int ssb_bus_powerup(struct ssb_bu
|
||||||
extern u32 ssb_admatch_base(u32 adm);
|
extern u32 ssb_admatch_base(u32 adm);
|
||||||
extern u32 ssb_admatch_size(u32 adm);
|
extern u32 ssb_admatch_size(u32 adm);
|
||||||
|
|
||||||
|
@ -800,10 +807,10 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
|
||||||
+#endif /* CONFIG_SSB_EMBEDDED */
|
+#endif /* CONFIG_SSB_EMBEDDED */
|
||||||
|
|
||||||
#endif /* LINUX_SSB_H_ */
|
#endif /* LINUX_SSB_H_ */
|
||||||
Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
|
Index: linux-2.6.25.1/include/linux/ssb/ssb_driver_pci.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/include/linux/ssb/ssb_driver_pci.h 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/include/linux/ssb/ssb_driver_pci.h 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -1,6 +1,11 @@
|
@@ -1,6 +1,11 @@
|
||||||
#ifndef LINUX_SSB_PCICORE_H_
|
#ifndef LINUX_SSB_PCICORE_H_
|
||||||
#define LINUX_SSB_PCICORE_H_
|
#define LINUX_SSB_PCICORE_H_
|
||||||
|
@ -843,10 +850,10 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
|
||||||
+
|
+
|
||||||
#endif /* CONFIG_SSB_DRIVER_PCICORE */
|
#endif /* CONFIG_SSB_DRIVER_PCICORE */
|
||||||
#endif /* LINUX_SSB_PCICORE_H_ */
|
#endif /* LINUX_SSB_PCICORE_H_ */
|
||||||
Index: linux-2.6.23.16/drivers/ssb/main.c
|
Index: linux-2.6.25.1/drivers/ssb/main.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/main.c 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/main.c 2008-05-07 22:45:33.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/main.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/main.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -14,6 +14,7 @@
|
@@ -14,6 +14,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/ssb/ssb.h>
|
#include <linux/ssb/ssb.h>
|
||||||
|
@ -881,7 +888,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
static struct ssb_device *ssb_device_get(struct ssb_device *dev)
|
static struct ssb_device *ssb_device_get(struct ssb_device *dev)
|
||||||
{
|
{
|
||||||
if (dev)
|
if (dev)
|
||||||
@@ -1175,7 +1195,14 @@ static int __init ssb_modinit(void)
|
@@ -1181,7 +1201,14 @@ static int __init ssb_modinit(void)
|
||||||
err = b43_pci_ssb_bridge_init();
|
err = b43_pci_ssb_bridge_init();
|
||||||
if (err) {
|
if (err) {
|
||||||
ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
|
ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
|
||||||
|
@ -897,7 +904,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
/* don't fail SSB init because of this */
|
/* don't fail SSB init because of this */
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
@@ -1189,6 +1216,7 @@ fs_initcall(ssb_modinit);
|
@@ -1195,6 +1222,7 @@ fs_initcall(ssb_modinit);
|
||||||
|
|
||||||
static void __exit ssb_modexit(void)
|
static void __exit ssb_modexit(void)
|
||||||
{
|
{
|
||||||
|
@ -905,10 +912,10 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
|
||||||
b43_pci_ssb_bridge_exit();
|
b43_pci_ssb_bridge_exit();
|
||||||
bus_unregister(&ssb_bustype);
|
bus_unregister(&ssb_bustype);
|
||||||
}
|
}
|
||||||
Index: linux-2.6.23.16/drivers/ssb/ssb_private.h
|
Index: linux-2.6.25.1/drivers/ssb/ssb_private.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/ssb_private.h 2008-03-19 11:16:15.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/ssb_private.h 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/ssb_private.h 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/ssb_private.h 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 pllty
|
@@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 pllty
|
||||||
extern int ssb_devices_freeze(struct ssb_bus *bus);
|
extern int ssb_devices_freeze(struct ssb_bus *bus);
|
||||||
extern int ssb_devices_thaw(struct ssb_bus *bus);
|
extern int ssb_devices_thaw(struct ssb_bus *bus);
|
||||||
|
@ -917,11 +924,11 @@ Index: linux-2.6.23.16/drivers/ssb/ssb_private.h
|
||||||
+ int (*func)(struct ssb_bus *bus, unsigned long data));
|
+ int (*func)(struct ssb_bus *bus, unsigned long data));
|
||||||
|
|
||||||
/* b43_pci_bridge.c */
|
/* b43_pci_bridge.c */
|
||||||
#ifdef CONFIG_SSB_PCIHOST
|
#ifdef CONFIG_SSB_B43_PCI_BRIDGE
|
||||||
Index: linux-2.6.23.16/drivers/net/tg3.c
|
Index: linux-2.6.25.1/drivers/net/tg3.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/net/tg3.c 2008-03-19 11:16:15.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/net/tg3.c 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/net/tg3.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/net/tg3.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -38,6 +38,7 @@
|
@@ -38,6 +38,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
|
@ -930,7 +937,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
|
|
||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
@@ -410,8 +411,9 @@ static void _tw32_flush(struct tg3 *tp,
|
@@ -425,8 +426,9 @@ static void _tw32_flush(struct tg3 *tp,
|
||||||
static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
|
static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
|
||||||
{
|
{
|
||||||
tp->write32_mbox(tp, off, val);
|
tp->write32_mbox(tp, off, val);
|
||||||
|
@ -942,7 +949,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
tp->read32_mbox(tp, off);
|
tp->read32_mbox(tp, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +625,7 @@ static void tg3_switch_clocks(struct tg3
|
@@ -706,7 +708,7 @@ static void tg3_switch_clocks(struct tg3
|
||||||
|
|
||||||
#define PHY_BUSY_LOOPS 5000
|
#define PHY_BUSY_LOOPS 5000
|
||||||
|
|
||||||
|
@ -951,7 +958,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
{
|
{
|
||||||
u32 frame_val;
|
u32 frame_val;
|
||||||
unsigned int loops;
|
unsigned int loops;
|
||||||
@@ -637,7 +639,7 @@ static int tg3_readphy(struct tg3 *tp, i
|
@@ -720,7 +722,7 @@ static int tg3_readphy(struct tg3 *tp, i
|
||||||
|
|
||||||
*val = 0x0;
|
*val = 0x0;
|
||||||
|
|
||||||
|
@ -960,7 +967,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
MI_COM_PHY_ADDR_MASK);
|
MI_COM_PHY_ADDR_MASK);
|
||||||
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
|
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
|
||||||
MI_COM_REG_ADDR_MASK);
|
MI_COM_REG_ADDR_MASK);
|
||||||
@@ -672,7 +674,12 @@ static int tg3_readphy(struct tg3 *tp, i
|
@@ -755,7 +757,12 @@ static int tg3_readphy(struct tg3 *tp, i
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,7 +981,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
{
|
{
|
||||||
u32 frame_val;
|
u32 frame_val;
|
||||||
unsigned int loops;
|
unsigned int loops;
|
||||||
@@ -688,7 +695,7 @@ static int tg3_writephy(struct tg3 *tp,
|
@@ -771,7 +778,7 @@ static int tg3_writephy(struct tg3 *tp,
|
||||||
udelay(80);
|
udelay(80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,8 +990,8 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
MI_COM_PHY_ADDR_MASK);
|
MI_COM_PHY_ADDR_MASK);
|
||||||
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
|
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
|
||||||
MI_COM_REG_ADDR_MASK);
|
MI_COM_REG_ADDR_MASK);
|
||||||
@@ -721,6 +728,11 @@ static int tg3_writephy(struct tg3 *tp,
|
@@ -810,6 +817,11 @@ static void tg3_phydsp_write(struct tg3
|
||||||
return ret;
|
tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
|
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
|
||||||
|
@ -995,22 +1002,22 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
|
static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
|
||||||
{
|
{
|
||||||
u32 phy;
|
u32 phy;
|
||||||
@@ -1988,6 +2000,14 @@ static int tg3_setup_copper_phy(struct t
|
@@ -2250,6 +2262,14 @@ static int tg3_setup_copper_phy(struct t
|
||||||
tp->link_config.active_duplex = current_duplex;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ if (tp->tg3_flags3 & TG3_FLG3_ROBOSWITCH) {
|
+ if (tp->tg3_flags & TG3_FLG3_ROBOSWITCH) {
|
||||||
+ current_link_up = 1;
|
+ current_link_up = 1;
|
||||||
+ current_speed = SPEED_1000; //FIXME
|
+ current_speed = SPEED_1000; //FIXME
|
||||||
+ current_duplex = DUPLEX_FULL;
|
+ current_duplex = DUPLEX_FULL;
|
||||||
+ tp->link_config.active_speed = current_speed;
|
+ tp->link_config.active_speed = current_speed;
|
||||||
+ tp->link_config.active_duplex = current_duplex;
|
+ tp->link_config.active_duplex = current_duplex;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
if (current_link_up == 1 &&
|
if (current_link_up == 1 &&
|
||||||
(tp->link_config.active_duplex == DUPLEX_FULL) &&
|
tp->link_config.active_duplex == DUPLEX_FULL)
|
||||||
(tp->link_config.autoneg == AUTONEG_ENABLE)) {
|
tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
|
||||||
@@ -4813,6 +4833,11 @@ static int tg3_poll_fw(struct tg3 *tp)
|
@@ -5197,6 +5217,11 @@ static int tg3_poll_fw(struct tg3 *tp)
|
||||||
int i;
|
int i;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
|
@ -1022,7 +1029,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
|
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
|
||||||
/* Wait up to 20ms for init done. */
|
/* Wait up to 20ms for init done. */
|
||||||
for (i = 0; i < 200; i++) {
|
for (i = 0; i < 200; i++) {
|
||||||
@@ -5040,6 +5065,14 @@ static int tg3_chip_reset(struct tg3 *tp
|
@@ -5435,6 +5460,14 @@ static int tg3_chip_reset(struct tg3 *tp
|
||||||
tw32(0x5000, 0x400);
|
tw32(0x5000, 0x400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,7 +1044,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
tw32(GRC_MODE, tp->grc_mode);
|
tw32(GRC_MODE, tp->grc_mode);
|
||||||
|
|
||||||
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
|
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
|
||||||
@@ -5308,9 +5341,12 @@ static int tg3_halt_cpu(struct tg3 *tp,
|
@@ -5704,9 +5737,12 @@ static int tg3_halt_cpu(struct tg3 *tp,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,7 +1060,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5391,6 +5427,11 @@ static int tg3_load_5701_a0_firmware_fix
|
@@ -5787,6 +5823,11 @@ static int tg3_load_5701_a0_firmware_fix
|
||||||
struct fw_info info;
|
struct fw_info info;
|
||||||
int err, i;
|
int err, i;
|
||||||
|
|
||||||
|
@ -1065,7 +1072,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
info.text_base = TG3_FW_TEXT_ADDR;
|
info.text_base = TG3_FW_TEXT_ADDR;
|
||||||
info.text_len = TG3_FW_TEXT_LEN;
|
info.text_len = TG3_FW_TEXT_LEN;
|
||||||
info.text_data = &tg3FwText[0];
|
info.text_data = &tg3FwText[0];
|
||||||
@@ -5949,6 +5990,11 @@ static int tg3_load_tso_firmware(struct
|
@@ -6345,6 +6386,11 @@ static int tg3_load_tso_firmware(struct
|
||||||
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
|
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
|
||||||
int err, i;
|
int err, i;
|
||||||
|
|
||||||
|
@ -1077,7 +1084,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
|
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -6850,6 +6896,11 @@ static void tg3_timer(unsigned long __op
|
@@ -7306,6 +7352,11 @@ static void tg3_timer(unsigned long __op
|
||||||
|
|
||||||
spin_lock(&tp->lock);
|
spin_lock(&tp->lock);
|
||||||
|
|
||||||
|
@ -1089,9 +1096,9 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
|
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
|
||||||
/* All of this garbage is because when using non-tagged
|
/* All of this garbage is because when using non-tagged
|
||||||
* IRQ status the mailbox/status_block protocol the chip
|
* IRQ status the mailbox/status_block protocol the chip
|
||||||
@@ -8432,6 +8483,11 @@ static int tg3_test_nvram(struct tg3 *tp
|
@@ -8906,6 +8957,11 @@ static int tg3_test_nvram(struct tg3 *tp
|
||||||
u32 *buf, csum, magic;
|
__le32 *buf;
|
||||||
int i, j, err = 0, size;
|
int i, j, k, err = 0, size;
|
||||||
|
|
||||||
+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
|
+ if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
|
||||||
+ /* We don't have NVRAM. */
|
+ /* We don't have NVRAM. */
|
||||||
|
@ -1101,7 +1108,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
|
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
@@ -9154,7 +9210,7 @@ static int tg3_ioctl(struct net_device *
|
@@ -9689,7 +9745,7 @@ static int tg3_ioctl(struct net_device *
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
spin_lock_bh(&tp->lock);
|
spin_lock_bh(&tp->lock);
|
||||||
|
@ -1110,7 +1117,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
spin_unlock_bh(&tp->lock);
|
spin_unlock_bh(&tp->lock);
|
||||||
|
|
||||||
data->val_out = mii_regval;
|
data->val_out = mii_regval;
|
||||||
@@ -9173,7 +9229,7 @@ static int tg3_ioctl(struct net_device *
|
@@ -9708,7 +9764,7 @@ static int tg3_ioctl(struct net_device *
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
spin_lock_bh(&tp->lock);
|
spin_lock_bh(&tp->lock);
|
||||||
|
@ -1119,7 +1126,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
spin_unlock_bh(&tp->lock);
|
spin_unlock_bh(&tp->lock);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -9571,6 +9627,12 @@ static void __devinit tg3_get_5906_nvram
|
@@ -10177,6 +10233,12 @@ static void __devinit tg3_get_5906_nvram
|
||||||
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
|
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
|
||||||
static void __devinit tg3_nvram_init(struct tg3 *tp)
|
static void __devinit tg3_nvram_init(struct tg3 *tp)
|
||||||
{
|
{
|
||||||
|
@ -1132,7 +1139,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
tw32_f(GRC_EEPROM_ADDR,
|
tw32_f(GRC_EEPROM_ADDR,
|
||||||
(EEPROM_ADDR_FSM_RESET |
|
(EEPROM_ADDR_FSM_RESET |
|
||||||
(EEPROM_DEFAULT_CLOCK_PERIOD <<
|
(EEPROM_DEFAULT_CLOCK_PERIOD <<
|
||||||
@@ -9706,6 +9768,9 @@ static int tg3_nvram_read(struct tg3 *tp
|
@@ -10317,6 +10379,9 @@ static int tg3_nvram_read(struct tg3 *tp
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1142,7 +1149,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
|
if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
|
||||||
return tg3_nvram_read_using_eeprom(tp, offset, val);
|
return tg3_nvram_read_using_eeprom(tp, offset, val);
|
||||||
|
|
||||||
@@ -9938,6 +10003,9 @@ static int tg3_nvram_write_block(struct
|
@@ -10563,6 +10628,9 @@ static int tg3_nvram_write_block(struct
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1152,7 +1159,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
|
if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
|
||||||
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
|
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
|
||||||
~GRC_LCLCTRL_GPIO_OUTPUT1);
|
~GRC_LCLCTRL_GPIO_OUTPUT1);
|
||||||
@@ -10804,7 +10872,6 @@ static int __devinit tg3_get_invariants(
|
@@ -11610,7 +11678,6 @@ static int __devinit tg3_get_invariants(
|
||||||
tp->write32 = tg3_write_flush_reg32;
|
tp->write32 = tg3_write_flush_reg32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1160,7 +1167,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
|
if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
|
||||||
(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
|
(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
|
||||||
tp->write32_tx_mbox = tg3_write32_tx_mbox;
|
tp->write32_tx_mbox = tg3_write32_tx_mbox;
|
||||||
@@ -10840,6 +10907,11 @@ static int __devinit tg3_get_invariants(
|
@@ -11646,6 +11713,11 @@ static int __devinit tg3_get_invariants(
|
||||||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
|
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
|
||||||
tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
|
tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
|
||||||
|
|
||||||
|
@ -1172,7 +1179,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
/* Get eeprom hw config before calling tg3_set_power_state().
|
/* Get eeprom hw config before calling tg3_set_power_state().
|
||||||
* In particular, the TG3_FLG2_IS_NIC flag must be
|
* In particular, the TG3_FLG2_IS_NIC flag must be
|
||||||
* determined before calling tg3_set_power_state() so that
|
* determined before calling tg3_set_power_state() so that
|
||||||
@@ -11184,6 +11256,10 @@ static int __devinit tg3_get_device_addr
|
@@ -12017,6 +12089,10 @@ static int __devinit tg3_get_device_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_valid_ether_addr(&dev->dev_addr[0])) {
|
if (!is_valid_ether_addr(&dev->dev_addr[0])) {
|
||||||
|
@ -1180,10 +1187,10 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
+ ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
|
+ ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
|
||||||
+ }
|
+ }
|
||||||
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
|
+ if (!is_valid_ether_addr(&dev->dev_addr[0])) {
|
||||||
#ifdef CONFIG_SPARC64
|
#ifdef CONFIG_SPARC
|
||||||
if (!tg3_get_default_macaddr_sparc(tp))
|
if (!tg3_get_default_macaddr_sparc(tp))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -11675,6 +11751,7 @@ static char * __devinit tg3_phy_string(s
|
@@ -12508,6 +12584,7 @@ static char * __devinit tg3_phy_string(s
|
||||||
case PHY_ID_BCM5704: return "5704";
|
case PHY_ID_BCM5704: return "5704";
|
||||||
case PHY_ID_BCM5705: return "5705";
|
case PHY_ID_BCM5705: return "5705";
|
||||||
case PHY_ID_BCM5750: return "5750";
|
case PHY_ID_BCM5750: return "5750";
|
||||||
|
@ -1191,7 +1198,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
case PHY_ID_BCM5752: return "5752";
|
case PHY_ID_BCM5752: return "5752";
|
||||||
case PHY_ID_BCM5714: return "5714";
|
case PHY_ID_BCM5714: return "5714";
|
||||||
case PHY_ID_BCM5780: return "5780";
|
case PHY_ID_BCM5780: return "5780";
|
||||||
@@ -11859,6 +11936,13 @@ static int __devinit tg3_init_one(struct
|
@@ -12695,6 +12772,13 @@ static int __devinit tg3_init_one(struct
|
||||||
tp->msg_enable = tg3_debug;
|
tp->msg_enable = tg3_debug;
|
||||||
else
|
else
|
||||||
tp->msg_enable = TG3_DEF_MSG_ENABLE;
|
tp->msg_enable = TG3_DEF_MSG_ENABLE;
|
||||||
|
@ -1205,44 +1212,42 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
|
||||||
|
|
||||||
/* The word/byte swap controls here control register access byte
|
/* The word/byte swap controls here control register access byte
|
||||||
* swapping. DMA data byte swapping is controlled in the GRC_MODE
|
* swapping. DMA data byte swapping is controlled in the GRC_MODE
|
||||||
Index: linux-2.6.23.16/drivers/net/tg3.h
|
Index: linux-2.6.25.1/drivers/net/tg3.h
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/net/tg3.h 2008-03-19 11:16:15.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/net/tg3.h 2008-05-07 22:45:24.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/net/tg3.h 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/net/tg3.h 2008-05-07 23:02:12.000000000 +0100
|
||||||
@@ -2279,6 +2279,10 @@ struct tg3 {
|
@@ -2477,6 +2477,9 @@ struct tg3 {
|
||||||
#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
|
#define TG3_FLG3_ENABLE_APE 0x00000002
|
||||||
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
|
#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004
|
||||||
#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
|
#define TG3_FLG3_5701_DMA_BUG 0x00000008
|
||||||
+ u32 tg3_flags3;
|
+#define TG3_FLG3_IS_SSB_CORE 0x00000010
|
||||||
+#define TG3_FLG3_IS_SSB_CORE 0x00000001
|
+#define TG3_FLG3_FLUSH_POSTED_WRITES 0x00000020
|
||||||
+#define TG3_FLG3_FLUSH_POSTED_WRITES 0x00000002
|
+#define TG3_FLG3_ROBOSWITCH 0x00000040
|
||||||
+#define TG3_FLG3_ROBOSWITCH 0x00000004
|
|
||||||
|
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
u16 timer_counter;
|
u16 timer_counter;
|
||||||
@@ -2333,6 +2337,7 @@ struct tg3 {
|
@@ -2532,6 +2535,7 @@ struct tg3 {
|
||||||
#define PHY_ID_BCM5714 0x60008340
|
#define PHY_ID_BCM5714 0x60008340
|
||||||
#define PHY_ID_BCM5780 0x60008350
|
#define PHY_ID_BCM5780 0x60008350
|
||||||
#define PHY_ID_BCM5755 0xbc050cc0
|
#define PHY_ID_BCM5755 0xbc050cc0
|
||||||
+#define PHY_ID_BCM5750_2 0xbc050cd0
|
+#define PHY_ID_BCM5750_2 0xbc050cd0
|
||||||
#define PHY_ID_BCM5787 0xbc050ce0
|
#define PHY_ID_BCM5787 0xbc050ce0
|
||||||
#define PHY_ID_BCM5756 0xbc050ed0
|
#define PHY_ID_BCM5756 0xbc050ed0
|
||||||
#define PHY_ID_BCM5906 0xdc00ac40
|
#define PHY_ID_BCM5784 0xbc050fa0
|
||||||
@@ -2364,7 +2369,8 @@ struct tg3 {
|
@@ -2568,7 +2572,7 @@ struct tg3 {
|
||||||
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
|
|
||||||
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
|
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
|
||||||
(X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
|
(X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
|
||||||
- (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
|
(X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
|
||||||
+ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002 || \
|
- (X) == PHY_ID_BCM8002)
|
||||||
+ (X) == PHY_ID_BCM5750_2)
|
+ (X) == PHY_ID_BCM8002 || (X) == PHY_ID_BCM5750_2)
|
||||||
|
|
||||||
struct tg3_hw_stats *hw_stats;
|
struct tg3_hw_stats *hw_stats;
|
||||||
dma_addr_t stats_mapping;
|
dma_addr_t stats_mapping;
|
||||||
Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
|
Index: linux-2.6.25.1/drivers/ssb/driver_mipscore.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-03-19 11:16:18.000000000 +0100
|
--- linux-2.6.25.1.orig/drivers/ssb/driver_mipscore.c 2008-05-07 22:45:33.000000000 +0100
|
||||||
+++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c 2008-03-19 11:16:18.000000000 +0100
|
+++ linux-2.6.25.1/drivers/ssb/driver_mipscore.c 2008-05-07 22:57:40.000000000 +0100
|
||||||
@@ -211,6 +211,7 @@ void ssb_mipscore_init(struct ssb_mipsco
|
@@ -212,6 +212,7 @@ void ssb_mipscore_init(struct ssb_mipsco
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case SSB_DEV_PCI:
|
case SSB_DEV_PCI:
|
||||||
case SSB_DEV_ETHERNET:
|
case SSB_DEV_ETHERNET:
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
Index: linux-2.6.25.1/arch/mips/bcm47xx/prom.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.1.orig/arch/mips/bcm47xx/prom.c 2008-05-14 14:46:44.000000000 +0100
|
||||||
|
+++ linux-2.6.25.1/arch/mips/bcm47xx/prom.c 2008-05-14 17:05:43.000000000 +0100
|
||||||
|
@@ -83,9 +83,18 @@ static __init void prom_init_cfe(void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (((unsigned int)prom_vec == 0x80300000) ||
|
||||||
|
+ ((unsigned int)prom_vec == 0x80400000)) {
|
||||||
|
+ /* WRT54G series workaround */
|
||||||
|
+ cfe_eptseal = CFE_EPTSEAL;
|
||||||
|
+ cfe_ept = 0xBFC00500;
|
||||||
|
+ cfe_handle = (uint32_t)argc;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (cfe_eptseal != CFE_EPTSEAL) {
|
||||||
|
/* too early for panic to do any good */
|
||||||
|
printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
|
||||||
|
+ *(unsigned int*)0xb8000064 = 0x1;
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
201
target/linux/generic-2.6/files-2.6.25/drivers/gpio/gpio_dev.c
Normal file
201
target/linux/generic-2.6/files-2.6.25/drivers/gpio/gpio_dev.c
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* character device wrapper for generic gpio layer
|
||||||
|
*
|
||||||
|
* 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, MA02111-1307USA
|
||||||
|
*
|
||||||
|
* Feedback, Bugs... blogic@openwrt.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
#include <asm/atomic.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/genhd.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/gpio_dev.h>
|
||||||
|
|
||||||
|
#define DRVNAME "gpiodev"
|
||||||
|
#define DEVNAME "gpio"
|
||||||
|
|
||||||
|
static int dev_major;
|
||||||
|
static unsigned int gpio_access_mask;
|
||||||
|
static struct class *gpio_class;
|
||||||
|
|
||||||
|
/* Counter is 1, if the device is not opened and zero (or less) if opened. */
|
||||||
|
static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
|
||||||
|
|
||||||
|
static int
|
||||||
|
gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (((1 << arg) & gpio_access_mask) != (1 << arg))
|
||||||
|
{
|
||||||
|
retval = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case GPIO_GET:
|
||||||
|
retval = gpio_get_value(arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPIO_SET:
|
||||||
|
gpio_set_value(arg, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPIO_CLEAR:
|
||||||
|
gpio_set_value(arg, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPIO_DIR_IN:
|
||||||
|
gpio_direction_input(arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPIO_DIR_OUT:
|
||||||
|
gpio_direction_output(arg, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
retval = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gpio_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
unsigned int dev_minor = MINOR(inode->i_rdev);
|
||||||
|
|
||||||
|
if (dev_minor != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor);
|
||||||
|
result = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: We should really allow multiple applications to open the device
|
||||||
|
* at the same time, as long as the apps access different IO pins.
|
||||||
|
* The generic gpio-registration functions can be used for that.
|
||||||
|
* Two new IOCTLs have to be introduced for that. Need to check userspace
|
||||||
|
* compatibility first. --mb */
|
||||||
|
if (!atomic_dec_and_test(&gpio_open_cnt)) {
|
||||||
|
atomic_inc(&gpio_open_cnt);
|
||||||
|
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
|
||||||
|
result = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gpio_close(struct inode * inode, struct file * file)
|
||||||
|
{
|
||||||
|
smp_mb__before_atomic_inc();
|
||||||
|
atomic_inc(&gpio_open_cnt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations gpio_fops = {
|
||||||
|
ioctl: gpio_ioctl,
|
||||||
|
open: gpio_open,
|
||||||
|
release: gpio_close
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
gpio_probe(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
dev_major = register_chrdev(0, DEVNAME, &gpio_fops);
|
||||||
|
if (!dev_major)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME);
|
||||||
|
result = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_class = class_create(THIS_MODULE, DEVNAME);
|
||||||
|
class_device_create(gpio_class, NULL, MKDEV(dev_major, 0), NULL, DEVNAME);
|
||||||
|
|
||||||
|
printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major);
|
||||||
|
|
||||||
|
if (dev->num_resources != 1)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR DRVNAME ": device may only have 1 resource\n");
|
||||||
|
result = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_access_mask = dev->resource[0].start;
|
||||||
|
|
||||||
|
printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask);
|
||||||
|
out:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gpio_remove(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
unregister_chrdev(dev_major, DEVNAME);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct
|
||||||
|
platform_driver gpio_driver = {
|
||||||
|
.probe = gpio_probe,
|
||||||
|
.remove = gpio_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "GPIODEV",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init
|
||||||
|
gpio_mod_init(void)
|
||||||
|
{
|
||||||
|
int ret = platform_driver_register(&gpio_driver);
|
||||||
|
if (ret)
|
||||||
|
printk(KERN_INFO DRVNAME ": Error registering platfom driver!");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit
|
||||||
|
gpio_mod_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&gpio_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init (gpio_mod_init);
|
||||||
|
module_exit (gpio_mod_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("John Crispin / OpenWrt");
|
||||||
|
MODULE_DESCRIPTION("Character device for for generic gpio api");
|
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* Driver for buttons on GPIO lines not capable of generating interrupts
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
|
||||||
|
*
|
||||||
|
* This file was based on: /drivers/input/misc/cobalt_btns.c
|
||||||
|
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||||
|
*
|
||||||
|
* also was based on: /drivers/input/keyboard/gpio_keys.c
|
||||||
|
* Copyright 2005 Phil Blundell
|
||||||
|
*
|
||||||
|
* 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/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/input-polldev.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <linux/gpio_buttons.h>
|
||||||
|
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
|
||||||
|
#define DRV_NAME "gpio-buttons"
|
||||||
|
#define DRV_VERSION "0.1.1"
|
||||||
|
#define PFX DRV_NAME ": "
|
||||||
|
|
||||||
|
struct gpio_buttons_dev {
|
||||||
|
struct input_polled_dev *poll_dev;
|
||||||
|
struct gpio_buttons_platform_data *pdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gpio_buttons_poll(struct input_polled_dev *dev)
|
||||||
|
{
|
||||||
|
struct gpio_buttons_dev *bdev = dev->private;
|
||||||
|
struct gpio_buttons_platform_data *pdata = bdev->pdata;
|
||||||
|
struct input_dev *input = dev->input;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < bdev->pdata->nbuttons; i++) {
|
||||||
|
struct gpio_button *button = &pdata->buttons[i];
|
||||||
|
unsigned int type = button->type ?: EV_KEY;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
state = gpio_get_value(button->gpio) ? 1 : 0;
|
||||||
|
state ^= button->active_low;
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
button->count++;
|
||||||
|
} else {
|
||||||
|
if (button->count >= button->threshold) {
|
||||||
|
input_event(input, type, button->code, 1);
|
||||||
|
input_sync(input);
|
||||||
|
}
|
||||||
|
button->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button->count == button->threshold) {
|
||||||
|
input_event(input, type, button->code, 0);
|
||||||
|
input_sync(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit gpio_buttons_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct gpio_buttons_dev *bdev;
|
||||||
|
struct input_polled_dev *poll_dev;
|
||||||
|
struct input_dev *input;
|
||||||
|
int error, i;
|
||||||
|
|
||||||
|
|
||||||
|
if (!pdata)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
|
||||||
|
if (!bdev) {
|
||||||
|
printk(KERN_ERR DRV_NAME "no memory for device\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_dev = input_allocate_polled_device();
|
||||||
|
if (!poll_dev) {
|
||||||
|
printk(KERN_ERR DRV_NAME "no memory for polled device\n");
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto err_free_bdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_dev->private = bdev;
|
||||||
|
poll_dev->poll = gpio_buttons_poll;
|
||||||
|
poll_dev->poll_interval = pdata->poll_interval;
|
||||||
|
|
||||||
|
input = poll_dev->input;
|
||||||
|
|
||||||
|
input->evbit[0] = BIT(EV_KEY);
|
||||||
|
input->name = pdev->name;
|
||||||
|
input->phys = "gpio-buttons/input0";
|
||||||
|
input->dev.parent = &pdev->dev;
|
||||||
|
|
||||||
|
input->id.bustype = BUS_HOST;
|
||||||
|
input->id.vendor = 0x0001;
|
||||||
|
input->id.product = 0x0001;
|
||||||
|
input->id.version = 0x0100;
|
||||||
|
|
||||||
|
for (i = 0; i < pdata->nbuttons; i++) {
|
||||||
|
struct gpio_button *button = &pdata->buttons[i];
|
||||||
|
unsigned int gpio = button->gpio;
|
||||||
|
unsigned int type = button->type ?: EV_KEY;
|
||||||
|
|
||||||
|
error = gpio_request(gpio, button->desc ?
|
||||||
|
button->desc : DRV_NAME);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR PFX "unable to claim gpio %u, "
|
||||||
|
"error %d\n", gpio, error);
|
||||||
|
goto err_free_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = gpio_direction_input(gpio);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR PFX "unable to set direction on "
|
||||||
|
"gpio %u, error %d\n", gpio, error);
|
||||||
|
goto err_free_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_set_capability(input, type, button->code);
|
||||||
|
button->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdev->poll_dev = poll_dev;
|
||||||
|
bdev->pdata = pdata;
|
||||||
|
platform_set_drvdata(pdev, bdev);
|
||||||
|
|
||||||
|
error = input_register_polled_device(poll_dev);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR PFX "unable to register polled device, "
|
||||||
|
"error %d\n", error);
|
||||||
|
goto err_free_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free_gpio:
|
||||||
|
for (i = i - 1; i >= 0; i--)
|
||||||
|
gpio_free(pdata->buttons[i].gpio);
|
||||||
|
|
||||||
|
input_free_polled_device(poll_dev);
|
||||||
|
|
||||||
|
err_free_bdev:
|
||||||
|
kfree(bdev);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit gpio_buttons_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
|
||||||
|
struct gpio_buttons_platform_data *pdata = bdev->pdata;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
input_unregister_polled_device(bdev->poll_dev);
|
||||||
|
|
||||||
|
for (i = 0; i < pdata->nbuttons; i++)
|
||||||
|
gpio_free(pdata->buttons[i].gpio);
|
||||||
|
|
||||||
|
input_free_polled_device(bdev->poll_dev);
|
||||||
|
|
||||||
|
kfree(bdev);
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver gpio_buttons_driver = {
|
||||||
|
.probe = gpio_buttons_probe,
|
||||||
|
.remove = __devexit_p(gpio_buttons_remove),
|
||||||
|
.driver = {
|
||||||
|
.name = DRV_NAME,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init gpio_buttons_init(void)
|
||||||
|
{
|
||||||
|
printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
|
||||||
|
return platform_driver_register(&gpio_buttons_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit gpio_buttons_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&gpio_buttons_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(gpio_buttons_init);
|
||||||
|
module_exit(gpio_buttons_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
|
||||||
|
MODULE_VERSION(DRV_VERSION);
|
||||||
|
MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");
|
||||||
|
|
172
target/linux/generic-2.6/files-2.6.25/drivers/leds/leds-alix.c
Normal file
172
target/linux/generic-2.6/files-2.6.25/drivers/leds/leds-alix.c
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* LEDs driver for PCEngines ALIX 2/3 series
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Petr Liebman
|
||||||
|
*
|
||||||
|
* Based on leds-wrap.c
|
||||||
|
*
|
||||||
|
* 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/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
#define DRVNAME "alix-led"
|
||||||
|
|
||||||
|
#define ALIX_LED1_PORT (0x6100)
|
||||||
|
#define ALIX_LED1_ON (1<<22)
|
||||||
|
#define ALIX_LED1_OFF (1<<6)
|
||||||
|
|
||||||
|
#define ALIX_LED2_PORT (0x6180)
|
||||||
|
#define ALIX_LED2_ON (1<<25)
|
||||||
|
#define ALIX_LED2_OFF (1<<9)
|
||||||
|
|
||||||
|
#define ALIX_LED3_PORT (0x6180)
|
||||||
|
#define ALIX_LED3_ON (1<<27)
|
||||||
|
#define ALIX_LED3_OFF (1<<11)
|
||||||
|
|
||||||
|
|
||||||
|
static struct platform_device *pdev;
|
||||||
|
|
||||||
|
static void alix_led_set_1(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
outl(ALIX_LED1_ON, ALIX_LED1_PORT);
|
||||||
|
else
|
||||||
|
outl(ALIX_LED1_OFF, ALIX_LED1_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alix_led_set_2(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
outl(ALIX_LED2_ON, ALIX_LED2_PORT);
|
||||||
|
else
|
||||||
|
outl(ALIX_LED2_OFF, ALIX_LED2_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alix_led_set_3(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
outl(ALIX_LED3_ON, ALIX_LED3_PORT);
|
||||||
|
else
|
||||||
|
outl(ALIX_LED3_OFF, ALIX_LED3_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_classdev alix_led_1 = {
|
||||||
|
.name = "alix:1",
|
||||||
|
.brightness_set = alix_led_set_1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct led_classdev alix_led_2 = {
|
||||||
|
.name = "alix:2",
|
||||||
|
.brightness_set = alix_led_set_2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct led_classdev alix_led_3 = {
|
||||||
|
.name = "alix:3",
|
||||||
|
.brightness_set = alix_led_set_3,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int alix_led_suspend(struct platform_device *dev,
|
||||||
|
pm_message_t state)
|
||||||
|
{
|
||||||
|
led_classdev_suspend(&alix_led_1);
|
||||||
|
led_classdev_suspend(&alix_led_2);
|
||||||
|
led_classdev_suspend(&alix_led_3);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alix_led_resume(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
led_classdev_resume(&alix_led_1);
|
||||||
|
led_classdev_resume(&alix_led_2);
|
||||||
|
led_classdev_resume(&alix_led_3);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define alix_led_suspend NULL
|
||||||
|
#define alix_led_resume NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int alix_led_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = led_classdev_register(&pdev->dev, &alix_led_1);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
ret = led_classdev_register(&pdev->dev, &alix_led_2);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
ret = led_classdev_register(&pdev->dev, &alix_led_3);
|
||||||
|
if (ret < 0)
|
||||||
|
led_classdev_unregister(&alix_led_2);
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
led_classdev_unregister(&alix_led_1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alix_led_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
led_classdev_unregister(&alix_led_1);
|
||||||
|
led_classdev_unregister(&alix_led_2);
|
||||||
|
led_classdev_unregister(&alix_led_3);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver alix_led_driver = {
|
||||||
|
.probe = alix_led_probe,
|
||||||
|
.remove = alix_led_remove,
|
||||||
|
.suspend = alix_led_suspend,
|
||||||
|
.resume = alix_led_resume,
|
||||||
|
.driver = {
|
||||||
|
.name = DRVNAME,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init alix_led_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = platform_driver_register(&alix_led_driver);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
|
||||||
|
if (IS_ERR(pdev)) {
|
||||||
|
ret = PTR_ERR(pdev);
|
||||||
|
platform_driver_unregister(&alix_led_driver);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit alix_led_exit(void)
|
||||||
|
{
|
||||||
|
platform_device_unregister(pdev);
|
||||||
|
platform_driver_unregister(&alix_led_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(alix_led_init);
|
||||||
|
module_exit(alix_led_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Petr Liebman");
|
||||||
|
MODULE_DESCRIPTION("PCEngines ALIX LED driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* LED Kernel Default ON Trigger
|
||||||
|
*
|
||||||
|
* Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
|
||||||
|
*
|
||||||
|
* Based on Richard Purdie's ledtrig-timer.c.
|
||||||
|
*
|
||||||
|
* 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/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
|
static void defon_trig_activate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
led_set_brightness(led_cdev, LED_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_trigger defon_led_trigger = {
|
||||||
|
.name = "default-on",
|
||||||
|
.activate = defon_trig_activate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init defon_trig_init(void)
|
||||||
|
{
|
||||||
|
return led_trigger_register(&defon_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit defon_trig_exit(void)
|
||||||
|
{
|
||||||
|
led_trigger_unregister(&defon_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(defon_trig_init);
|
||||||
|
module_exit(defon_trig_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
|
||||||
|
MODULE_DESCRIPTION("Default-ON LED trigger");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,365 @@
|
||||||
|
/*
|
||||||
|
* LED Morse Trigger
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
|
||||||
|
*
|
||||||
|
* This file was based on: drivers/led/ledtrig-timer.c
|
||||||
|
* Copyright 2005-2006 Openedhand Ltd.
|
||||||
|
* Author: Richard Purdie <rpurdie@openedhand.com>
|
||||||
|
*
|
||||||
|
* also based on the patch '[PATCH] 2.5.59 morse code panics' posted
|
||||||
|
* in the LKML by Tomas Szepe at Thu, 30 Jan 2003
|
||||||
|
* Copyright (C) 2002 Andrew Rodland <arodland@noln.com>
|
||||||
|
* Copyright (C) 2003 Tomas Szepe <szepe@pinerecords.com>
|
||||||
|
*
|
||||||
|
* 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/kernel.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/sysdev.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
|
#define MORSE_DELAY_BASE (HZ/2)
|
||||||
|
|
||||||
|
#define MORSE_STATE_BLINK_START 0
|
||||||
|
#define MORSE_STATE_BLINK_STOP 1
|
||||||
|
|
||||||
|
#define MORSE_DIT_LEN 1
|
||||||
|
#define MORSE_DAH_LEN 3
|
||||||
|
#define MORSE_SPACE_LEN 7
|
||||||
|
|
||||||
|
struct morse_trig_data {
|
||||||
|
unsigned long delay;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
|
unsigned char morse;
|
||||||
|
unsigned char state;
|
||||||
|
char *msgpos;
|
||||||
|
struct timer_list timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned char morsetable[] = {
|
||||||
|
0122, 0, 0310, 0, 0, 0163, /* "#$%&' */
|
||||||
|
055, 0155, 0, 0, 0163, 0141, 0152, 0051, /* ()*+,-./ */
|
||||||
|
077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */
|
||||||
|
0107, 0125, 0, 0061, 0, 0114, 0, /* :;<=>?@ */
|
||||||
|
006, 021, 025, 011, 002, 024, 013, 020, 004, /* A-I */
|
||||||
|
036, 015, 022, 007, 005, 017, 026, 033, 012, /* J-R */
|
||||||
|
010, 003, 014, 030, 016, 031, 035, 023, /* S-Z */
|
||||||
|
0, 0, 0, 0, 0154 /* [\]^_ */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline unsigned char tomorse(char c) {
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
c = c - 'a' + 'A';
|
||||||
|
if (c >= '"' && c <= '_') {
|
||||||
|
return morsetable[c - '"'];
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long dit_len(struct morse_trig_data *morse_data)
|
||||||
|
{
|
||||||
|
return MORSE_DIT_LEN*morse_data->delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long dah_len(struct morse_trig_data *morse_data)
|
||||||
|
{
|
||||||
|
return MORSE_DAH_LEN*morse_data->delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long space_len(struct morse_trig_data *morse_data)
|
||||||
|
{
|
||||||
|
return MORSE_SPACE_LEN*morse_data->delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void morse_timer_function(unsigned long data)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = (struct led_classdev *)data;
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
unsigned long brightness = LED_OFF;
|
||||||
|
unsigned long delay = 0;
|
||||||
|
|
||||||
|
if (!morse_data->msg)
|
||||||
|
goto set_led;
|
||||||
|
|
||||||
|
switch (morse_data->state) {
|
||||||
|
case MORSE_STATE_BLINK_START:
|
||||||
|
/* Starting a new blink. We have a valid code in morse. */
|
||||||
|
delay = (morse_data->morse & 001) ? dah_len(morse_data):
|
||||||
|
dit_len(morse_data);
|
||||||
|
brightness = LED_FULL;
|
||||||
|
morse_data->state = MORSE_STATE_BLINK_STOP;
|
||||||
|
morse_data->morse >>= 1;
|
||||||
|
break;
|
||||||
|
case MORSE_STATE_BLINK_STOP:
|
||||||
|
/* Coming off of a blink. */
|
||||||
|
morse_data->state = MORSE_STATE_BLINK_START;
|
||||||
|
|
||||||
|
if (morse_data->morse > 1) {
|
||||||
|
/* Not done yet, just a one-dit pause. */
|
||||||
|
delay = dit_len(morse_data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get a new char, figure out how much space. */
|
||||||
|
/* First time through */
|
||||||
|
if (!morse_data->msgpos)
|
||||||
|
morse_data->msgpos = (char *)morse_data->msg;
|
||||||
|
|
||||||
|
if (!*morse_data->msgpos) {
|
||||||
|
/* Repeating */
|
||||||
|
morse_data->msgpos = (char *)morse_data->msg;
|
||||||
|
delay = space_len(morse_data);
|
||||||
|
} else {
|
||||||
|
/* Inter-letter space */
|
||||||
|
delay = dah_len(morse_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(morse_data->morse = tomorse(*morse_data->msgpos))) {
|
||||||
|
delay = space_len(morse_data);
|
||||||
|
/* And get us back here */
|
||||||
|
morse_data->state = MORSE_STATE_BLINK_STOP;
|
||||||
|
}
|
||||||
|
morse_data->msgpos++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_timer(&morse_data->timer, jiffies + msecs_to_jiffies(delay));
|
||||||
|
|
||||||
|
set_led:
|
||||||
|
led_set_brightness(led_cdev, brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _morse_delay_show(struct led_classdev *led_cdev, char *buf)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
sprintf(buf, "%lu\n", morse_data->delay);
|
||||||
|
|
||||||
|
return strlen(buf) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _morse_delay_store(struct led_classdev *led_cdev,
|
||||||
|
const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
char *after;
|
||||||
|
unsigned long state = simple_strtoul(buf, &after, 10);
|
||||||
|
size_t count = after - buf;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (*after && isspace(*after))
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count == size) {
|
||||||
|
morse_data->delay = state;
|
||||||
|
mod_timer(&morse_data->timer, jiffies + 1);
|
||||||
|
ret = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _morse_msg_show(struct led_classdev *led_cdev, char *buf)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
if (!morse_data->msg)
|
||||||
|
sprintf(buf, "<none>\n");
|
||||||
|
else
|
||||||
|
sprintf(buf, "%s\n", morse_data->msg);
|
||||||
|
|
||||||
|
return strlen(buf) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _morse_msg_store(struct led_classdev *led_cdev,
|
||||||
|
const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
char *m;
|
||||||
|
|
||||||
|
m = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (!m)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(m,buf,size);
|
||||||
|
m[size]='\0';
|
||||||
|
|
||||||
|
if (morse_data->msg)
|
||||||
|
kfree(morse_data->msg);
|
||||||
|
|
||||||
|
morse_data->msg = m;
|
||||||
|
morse_data->msgpos = NULL;
|
||||||
|
morse_data->state = MORSE_STATE_BLINK_STOP;
|
||||||
|
|
||||||
|
mod_timer(&morse_data->timer, jiffies + 1);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
static ssize_t morse_delay_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return _morse_delay_show(led_cdev, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_delay_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return _morse_delay_store(led_cdev, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_msg_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return _morse_msg_show(led_cdev, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_msg_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return _morse_msg_store(led_cdev, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
|
||||||
|
static DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
|
||||||
|
|
||||||
|
#define led_device_create_file(leddev, attr) \
|
||||||
|
device_create_file(leddev->dev, &dev_attr_ ## attr)
|
||||||
|
#define led_device_remove_file(leddev, attr) \
|
||||||
|
device_remove_file(leddev->dev, &dev_attr_ ## attr)
|
||||||
|
|
||||||
|
#else
|
||||||
|
static ssize_t morse_delay_show(struct class_device *dev, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||||
|
|
||||||
|
return _morse_delay_show(led_cdev, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_delay_store(struct class_device *dev, const char *buf,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||||
|
|
||||||
|
return _morse_delay_store(led_cdev, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_msg_show(struct class_device *dev, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||||
|
|
||||||
|
return _morse_msg_show(led_cdev, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t morse_msg_store(struct class_device *dev, const char *buf,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = class_get_devdata(dev);
|
||||||
|
|
||||||
|
return _morse_msg_store(led_cdev, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CLASS_DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
|
||||||
|
static CLASS_DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
|
||||||
|
|
||||||
|
#define led_device_create_file(leddev, attr) \
|
||||||
|
class_device_create_file(leddev->class_dev, &class_device_attr_ ## attr)
|
||||||
|
#define led_device_remove_file(leddev, attr) \
|
||||||
|
class_device_remove_file(leddev->class_dev, &class_device_attr_ ## attr)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void morse_trig_activate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
morse_data = kzalloc(sizeof(*morse_data), GFP_KERNEL);
|
||||||
|
if (!morse_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
morse_data->delay = MORSE_DELAY_BASE;
|
||||||
|
init_timer(&morse_data->timer);
|
||||||
|
morse_data->timer.function = morse_timer_function;
|
||||||
|
morse_data->timer.data = (unsigned long)led_cdev;
|
||||||
|
|
||||||
|
rc = led_device_create_file(led_cdev, delay);
|
||||||
|
if (rc) goto err;
|
||||||
|
|
||||||
|
rc = led_device_create_file(led_cdev, message);
|
||||||
|
if (rc) goto err_delay;
|
||||||
|
|
||||||
|
led_cdev->trigger_data = morse_data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_delay:
|
||||||
|
led_device_remove_file(led_cdev, delay);
|
||||||
|
err:
|
||||||
|
kfree(morse_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void morse_trig_deactivate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct morse_trig_data *morse_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
if (!morse_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
led_device_remove_file(led_cdev, message);
|
||||||
|
led_device_remove_file(led_cdev, delay);
|
||||||
|
|
||||||
|
del_timer_sync(&morse_data->timer);
|
||||||
|
if (morse_data->msg)
|
||||||
|
kfree(morse_data->msg);
|
||||||
|
|
||||||
|
kfree(morse_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_trigger morse_led_trigger = {
|
||||||
|
.name = "morse",
|
||||||
|
.activate = morse_trig_activate,
|
||||||
|
.deactivate = morse_trig_deactivate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init morse_trig_init(void)
|
||||||
|
{
|
||||||
|
return led_trigger_register(&morse_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit morse_trig_exit(void)
|
||||||
|
{
|
||||||
|
led_trigger_unregister(&morse_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(morse_trig_init);
|
||||||
|
module_exit(morse_trig_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
|
||||||
|
MODULE_DESCRIPTION("Morse LED trigger");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,437 @@
|
||||||
|
/*
|
||||||
|
* LED Kernel Netdev Trigger
|
||||||
|
*
|
||||||
|
* Toggles the LED to reflect the link and traffic state of a named net device
|
||||||
|
*
|
||||||
|
* Copyright 2007 Oliver Jowett <oliver@opencloud.com>
|
||||||
|
*
|
||||||
|
* Derived from ledtrig-timer.c which is:
|
||||||
|
* Copyright 2005-2006 Openedhand Ltd.
|
||||||
|
* Author: Richard Purdie <rpurdie@openedhand.com>
|
||||||
|
*
|
||||||
|
* 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/module.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/sysdev.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configurable sysfs attributes:
|
||||||
|
*
|
||||||
|
* device_name - network device name to monitor
|
||||||
|
*
|
||||||
|
* interval - duration of LED blink, in milliseconds
|
||||||
|
*
|
||||||
|
* mode - either "none" (LED is off) or a space separated list of one or more of:
|
||||||
|
* link: LED's normal state reflects whether the link is up (has carrier) or not
|
||||||
|
* tx: LED blinks on transmitted data
|
||||||
|
* rx: LED blinks on receive data
|
||||||
|
*
|
||||||
|
* Some suggestions:
|
||||||
|
*
|
||||||
|
* Simple link status LED:
|
||||||
|
* $ echo netdev >someled/trigger
|
||||||
|
* $ echo eth0 >someled/device_name
|
||||||
|
* $ echo link >someled/mode
|
||||||
|
*
|
||||||
|
* Ethernet-style link/activity LED:
|
||||||
|
* $ echo netdev >someled/trigger
|
||||||
|
* $ echo eth0 >someled/device_name
|
||||||
|
* $ echo "link tx rx" >someled/mode
|
||||||
|
*
|
||||||
|
* Modem-style tx/rx LEDs:
|
||||||
|
* $ echo netdev >led1/trigger
|
||||||
|
* $ echo ppp0 >led1/device_name
|
||||||
|
* $ echo tx >led1/mode
|
||||||
|
* $ echo netdev >led2/trigger
|
||||||
|
* $ echo ppp0 >led2/device_name
|
||||||
|
* $ echo rx >led2/mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MODE_LINK 1
|
||||||
|
#define MODE_TX 2
|
||||||
|
#define MODE_RX 4
|
||||||
|
|
||||||
|
struct led_netdev_data {
|
||||||
|
rwlock_t lock;
|
||||||
|
|
||||||
|
struct timer_list timer;
|
||||||
|
struct notifier_block notifier;
|
||||||
|
|
||||||
|
struct led_classdev *led_cdev;
|
||||||
|
struct net_device *net_dev;
|
||||||
|
|
||||||
|
char device_name[IFNAMSIZ];
|
||||||
|
unsigned interval;
|
||||||
|
unsigned mode;
|
||||||
|
unsigned link_up;
|
||||||
|
unsigned last_activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||||
|
{
|
||||||
|
if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||||
|
else
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||||
|
|
||||||
|
if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
|
||||||
|
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
|
||||||
|
else
|
||||||
|
del_timer(&trigger_data->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_device_name_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
read_lock(&trigger_data->lock);
|
||||||
|
sprintf(buf, "%s\n", trigger_data->device_name);
|
||||||
|
read_unlock(&trigger_data->lock);
|
||||||
|
|
||||||
|
return strlen(buf) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_device_name_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
if (size < 0 || size >= IFNAMSIZ)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
|
||||||
|
strcpy(trigger_data->device_name, buf);
|
||||||
|
if (size > 0 && trigger_data->device_name[size-1] == '\n')
|
||||||
|
trigger_data->device_name[size-1] = 0;
|
||||||
|
|
||||||
|
if (trigger_data->device_name[0] != 0) {
|
||||||
|
/* check for existing device to update from */
|
||||||
|
trigger_data->net_dev = dev_get_by_name(trigger_data->device_name);
|
||||||
|
if (trigger_data->net_dev != NULL)
|
||||||
|
trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
|
||||||
|
set_baseline_state(trigger_data); /* updates LEDs, may start timers */
|
||||||
|
}
|
||||||
|
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
|
||||||
|
|
||||||
|
static ssize_t led_mode_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
read_lock(&trigger_data->lock);
|
||||||
|
|
||||||
|
if (trigger_data->mode == 0) {
|
||||||
|
strcpy(buf, "none\n");
|
||||||
|
} else {
|
||||||
|
if (trigger_data->mode & MODE_LINK)
|
||||||
|
strcat(buf, "link ");
|
||||||
|
if (trigger_data->mode & MODE_TX)
|
||||||
|
strcat(buf, "tx ");
|
||||||
|
if (trigger_data->mode & MODE_RX)
|
||||||
|
strcat(buf, "rx ");
|
||||||
|
strcat(buf, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
read_unlock(&trigger_data->lock);
|
||||||
|
|
||||||
|
return strlen(buf)+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_mode_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
char copybuf[1024];
|
||||||
|
int new_mode = -1;
|
||||||
|
char *p, *token;
|
||||||
|
|
||||||
|
/* take a copy since we don't want to trash the inbound buffer when using strsep */
|
||||||
|
strncpy(copybuf, buf, sizeof(copybuf));
|
||||||
|
copybuf[1023] = 0;
|
||||||
|
p = copybuf;
|
||||||
|
|
||||||
|
while ((token = strsep(&p, " \t\n")) != NULL) {
|
||||||
|
if (!*token)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (new_mode == -1)
|
||||||
|
new_mode = 0;
|
||||||
|
|
||||||
|
if (!strcmp(token, "none"))
|
||||||
|
new_mode = 0;
|
||||||
|
else if (!strcmp(token, "tx"))
|
||||||
|
new_mode |= MODE_TX;
|
||||||
|
else if (!strcmp(token, "rx"))
|
||||||
|
new_mode |= MODE_RX;
|
||||||
|
else if (!strcmp(token, "link"))
|
||||||
|
new_mode |= MODE_LINK;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_mode == -1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
trigger_data->mode = new_mode;
|
||||||
|
set_baseline_state(trigger_data);
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
|
||||||
|
|
||||||
|
static ssize_t led_interval_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
read_lock(&trigger_data->lock);
|
||||||
|
sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
|
||||||
|
read_unlock(&trigger_data->lock);
|
||||||
|
|
||||||
|
return strlen(buf) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_interval_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
char *after;
|
||||||
|
unsigned long value = simple_strtoul(buf, &after, 10);
|
||||||
|
size_t count = after - buf;
|
||||||
|
|
||||||
|
if (*after && isspace(*after))
|
||||||
|
count++;
|
||||||
|
|
||||||
|
/* impose some basic bounds on the timer interval */
|
||||||
|
if (count == size && value >= 5 && value <= 10000) {
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
trigger_data->interval = msecs_to_jiffies(value);
|
||||||
|
set_baseline_state(trigger_data); // resets timer
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
ret = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
|
||||||
|
|
||||||
|
static int netdev_trig_notify(struct notifier_block *nb,
|
||||||
|
unsigned long evt,
|
||||||
|
void *dv)
|
||||||
|
{
|
||||||
|
struct net_device *dev = dv;
|
||||||
|
struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
|
||||||
|
|
||||||
|
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
|
||||||
|
if (strcmp(dev->name, trigger_data->device_name))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (evt == NETDEV_REGISTER) {
|
||||||
|
if (trigger_data->net_dev != NULL)
|
||||||
|
dev_put(trigger_data->net_dev);
|
||||||
|
dev_hold(dev);
|
||||||
|
trigger_data->net_dev = dev;
|
||||||
|
trigger_data->link_up = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
|
||||||
|
dev_put(trigger_data->net_dev);
|
||||||
|
trigger_data->net_dev = NULL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UP / DOWN / CHANGE */
|
||||||
|
|
||||||
|
trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
|
||||||
|
set_baseline_state(trigger_data);
|
||||||
|
|
||||||
|
done:
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* here's the real work! */
|
||||||
|
static void netdev_trig_timer(unsigned long arg)
|
||||||
|
{
|
||||||
|
struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
|
||||||
|
struct net_device_stats *dev_stats;
|
||||||
|
unsigned new_activity;
|
||||||
|
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
|
||||||
|
if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
|
||||||
|
/* we don't need to do timer work, just reflect link state. */
|
||||||
|
led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
|
||||||
|
goto no_restart;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev);
|
||||||
|
new_activity =
|
||||||
|
((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
|
||||||
|
((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
|
||||||
|
|
||||||
|
if (trigger_data->mode & MODE_LINK) {
|
||||||
|
/* base state is ON (link present) */
|
||||||
|
/* if there's no link, we don't get this far and the LED is off */
|
||||||
|
|
||||||
|
/* OFF -> ON always */
|
||||||
|
/* ON -> OFF on activity */
|
||||||
|
if (trigger_data->led_cdev->brightness == LED_OFF) {
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||||
|
} else if (trigger_data->last_activity != new_activity) {
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* base state is OFF */
|
||||||
|
/* ON -> OFF always */
|
||||||
|
/* OFF -> ON on activity */
|
||||||
|
if (trigger_data->led_cdev->brightness == LED_FULL) {
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||||
|
} else if (trigger_data->last_activity != new_activity) {
|
||||||
|
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger_data->last_activity = new_activity;
|
||||||
|
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
|
||||||
|
|
||||||
|
no_restart:
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netdev_trig_activate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct led_netdev_data *trigger_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||||
|
if (!trigger_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rwlock_init(&trigger_data->lock);
|
||||||
|
|
||||||
|
trigger_data->notifier.notifier_call = netdev_trig_notify;
|
||||||
|
trigger_data->notifier.priority = 10;
|
||||||
|
|
||||||
|
setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
|
||||||
|
|
||||||
|
trigger_data->led_cdev = led_cdev;
|
||||||
|
trigger_data->net_dev = NULL;
|
||||||
|
trigger_data->device_name[0] = 0;
|
||||||
|
|
||||||
|
trigger_data->mode = 0;
|
||||||
|
trigger_data->interval = msecs_to_jiffies(50);
|
||||||
|
trigger_data->link_up = 0;
|
||||||
|
trigger_data->last_activity = 0;
|
||||||
|
|
||||||
|
led_cdev->trigger_data = trigger_data;
|
||||||
|
|
||||||
|
rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
if (rc)
|
||||||
|
goto err_out;
|
||||||
|
rc = device_create_file(led_cdev->dev, &dev_attr_mode);
|
||||||
|
if (rc)
|
||||||
|
goto err_out_device_name;
|
||||||
|
rc = device_create_file(led_cdev->dev, &dev_attr_interval);
|
||||||
|
if (rc)
|
||||||
|
goto err_out_mode;
|
||||||
|
|
||||||
|
register_netdevice_notifier(&trigger_data->notifier);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_out_mode:
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_mode);
|
||||||
|
err_out_device_name:
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
err_out:
|
||||||
|
led_cdev->trigger_data = NULL;
|
||||||
|
kfree(trigger_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netdev_trig_deactivate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
if (trigger_data) {
|
||||||
|
unregister_netdevice_notifier(&trigger_data->notifier);
|
||||||
|
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_mode);
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||||
|
|
||||||
|
write_lock(&trigger_data->lock);
|
||||||
|
|
||||||
|
if (trigger_data->net_dev) {
|
||||||
|
dev_put(trigger_data->net_dev);
|
||||||
|
trigger_data->net_dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_unlock(&trigger_data->lock);
|
||||||
|
|
||||||
|
del_timer_sync(&trigger_data->timer);
|
||||||
|
|
||||||
|
kfree(trigger_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_trigger netdev_led_trigger = {
|
||||||
|
.name = "netdev",
|
||||||
|
.activate = netdev_trig_activate,
|
||||||
|
.deactivate = netdev_trig_deactivate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init netdev_trig_init(void)
|
||||||
|
{
|
||||||
|
return led_trigger_register(&netdev_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit netdev_trig_exit(void)
|
||||||
|
{
|
||||||
|
led_trigger_unregister(&netdev_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(netdev_trig_init);
|
||||||
|
module_exit(netdev_trig_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
|
||||||
|
MODULE_DESCRIPTION("Netdev LED trigger");
|
||||||
|
MODULE_LICENSE("GPL");
|
170
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.c
Normal file
170
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.c
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* ADM6996 switch driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License v2 as published by the
|
||||||
|
* Free Software Foundation
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mii.h>
|
||||||
|
#include <linux/ethtool.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include "adm6996.h"
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Infineon ADM6996 Switch");
|
||||||
|
MODULE_AUTHOR("Felix Fietkau");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
struct adm6996_priv {
|
||||||
|
/* use abstraction for regops, we want to add gpio support in the future */
|
||||||
|
u16 (*read)(struct phy_device *phydev, enum admreg reg);
|
||||||
|
void (*write)(struct phy_device *phydev, enum admreg reg, u16 val);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv)
|
||||||
|
|
||||||
|
|
||||||
|
static inline u16
|
||||||
|
r16(struct phy_device *pdev, enum admreg reg)
|
||||||
|
{
|
||||||
|
return to_adm(pdev)->read(pdev, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
w16(struct phy_device *pdev, enum admreg reg, u16 val)
|
||||||
|
{
|
||||||
|
to_adm(pdev)->write(pdev, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u16
|
||||||
|
adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg)
|
||||||
|
{
|
||||||
|
return phydev->bus->read(phydev->bus, PHYADDR(reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val)
|
||||||
|
{
|
||||||
|
phydev->bus->write(phydev->bus, PHYADDR(reg), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int adm6996_config_init(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name);
|
||||||
|
pdev->supported = ADVERTISED_100baseT_Full;
|
||||||
|
pdev->advertising = ADVERTISED_100baseT_Full;
|
||||||
|
|
||||||
|
/* initialize port and vlan settings */
|
||||||
|
for (i = 0; i < ADM_PHY_PORTS; i++) {
|
||||||
|
w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT |
|
||||||
|
ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0));
|
||||||
|
}
|
||||||
|
w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU);
|
||||||
|
|
||||||
|
/* reset all ports */
|
||||||
|
for (i = 0; i < ADM_PHY_PORTS; i++) {
|
||||||
|
w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adm6996_read_status(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
phydev->speed = SPEED_100;
|
||||||
|
phydev->duplex = DUPLEX_FULL;
|
||||||
|
phydev->state = PHY_UP;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adm6996_config_aneg(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adm6996_probe(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
struct adm6996_priv *priv;
|
||||||
|
|
||||||
|
priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->read = adm6996_read_mii_reg;
|
||||||
|
priv->write = adm6996_write_mii_reg;
|
||||||
|
pdev->priv = priv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adm6996_remove(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
kfree(pdev->priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool adm6996_detect(struct mii_bus *bus, int addr)
|
||||||
|
{
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
|
/* we only attach to phy id 0 */
|
||||||
|
if (addr != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* look for the switch on the bus */
|
||||||
|
reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK;
|
||||||
|
if (reg != ADM_SIG0_VAL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK;
|
||||||
|
if (reg != ADM_SIG1_VAL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct phy_driver adm6996_driver = {
|
||||||
|
.name = "Infineon ADM6996",
|
||||||
|
.features = PHY_BASIC_FEATURES,
|
||||||
|
.detect = adm6996_detect,
|
||||||
|
.probe = adm6996_probe,
|
||||||
|
.remove = adm6996_remove,
|
||||||
|
.config_init = &adm6996_config_init,
|
||||||
|
.config_aneg = &adm6996_config_aneg,
|
||||||
|
.read_status = &adm6996_read_status,
|
||||||
|
.driver = { .owner = THIS_MODULE,},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init adm6996_init(void)
|
||||||
|
{
|
||||||
|
return phy_driver_register(&adm6996_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit adm6996_exit(void)
|
||||||
|
{
|
||||||
|
phy_driver_unregister(&adm6996_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(adm6996_init);
|
||||||
|
module_exit(adm6996_exit);
|
105
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.h
Normal file
105
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.h
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* ADM6996 switch driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License v2 as published by the
|
||||||
|
* Free Software Foundation
|
||||||
|
*/
|
||||||
|
#ifndef __ADM6996_H
|
||||||
|
#define __ADM6996_H
|
||||||
|
|
||||||
|
#define ADM_PHY_PORTS 5
|
||||||
|
#define ADM_CPU_PORT 5
|
||||||
|
#define ADM_WAN_PORT 0 /* FIXME: dynamic ? */
|
||||||
|
|
||||||
|
enum admreg {
|
||||||
|
ADM_EEPROM_BASE = 0x0,
|
||||||
|
ADM_P0_CFG = ADM_EEPROM_BASE + 1,
|
||||||
|
ADM_P1_CFG = ADM_EEPROM_BASE + 3,
|
||||||
|
ADM_P2_CFG = ADM_EEPROM_BASE + 5,
|
||||||
|
ADM_P3_CFG = ADM_EEPROM_BASE + 7,
|
||||||
|
ADM_P4_CFG = ADM_EEPROM_BASE + 8,
|
||||||
|
ADM_P5_CFG = ADM_EEPROM_BASE + 9,
|
||||||
|
ADM_EEPROM_EXT_BASE = 0x40,
|
||||||
|
ADM_COUNTER_BASE = 0xa0,
|
||||||
|
ADM_SIG0 = ADM_COUNTER_BASE + 0,
|
||||||
|
ADM_SIG1 = ADM_COUNTER_BASE + 1,
|
||||||
|
ADM_PHY_BASE = 0x200,
|
||||||
|
#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Chip identification patterns */
|
||||||
|
#define ADM_SIG0_MASK 0xfff0
|
||||||
|
#define ADM_SIG0_VAL 0x1020
|
||||||
|
#define ADM_SIG1_MASK 0xffff
|
||||||
|
#define ADM_SIG1_VAL 0x0007
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */
|
||||||
|
ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */
|
||||||
|
ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */
|
||||||
|
ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */
|
||||||
|
ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */
|
||||||
|
ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */
|
||||||
|
ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */
|
||||||
|
ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */
|
||||||
|
ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */
|
||||||
|
ADM_PHYCFG_INIT = (
|
||||||
|
ADM_PHYCFG_RST |
|
||||||
|
ADM_PHYCFG_SPEED_100 |
|
||||||
|
ADM_PHYCFG_ANEN |
|
||||||
|
ADM_PHYCFG_ANEN_RST
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */
|
||||||
|
ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */
|
||||||
|
ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */
|
||||||
|
ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */
|
||||||
|
ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */
|
||||||
|
ADM_PORTCFG_PD = (1 << 5), /* Port disable */
|
||||||
|
ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority
|
||||||
|
* 1 = TOS based priority */
|
||||||
|
ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */
|
||||||
|
ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */
|
||||||
|
ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */
|
||||||
|
ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */
|
||||||
|
ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */
|
||||||
|
|
||||||
|
ADM_PORTCFG_INIT = (
|
||||||
|
ADM_PORTCFG_FC |
|
||||||
|
ADM_PORTCFG_AN |
|
||||||
|
ADM_PORTCFG_SPEED_100 |
|
||||||
|
ADM_PORTCFG_DPLX |
|
||||||
|
ADM_PORTCFG_CAM
|
||||||
|
),
|
||||||
|
ADM_PORTCFG_CPU = (
|
||||||
|
ADM_PORTCFG_FC |
|
||||||
|
ADM_PORTCFG_SPEED_100 |
|
||||||
|
ADM_PORTCFG_OT |
|
||||||
|
ADM_PORTCFG_DPLX
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ADM_PORTCFG_PPID(N) ((n & 0x3) << 8)
|
||||||
|
#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
|
||||||
|
|
||||||
|
static const u8 adm_portcfg[] = {
|
||||||
|
[0] = ADM_P0_CFG,
|
||||||
|
[1] = ADM_P1_CFG,
|
||||||
|
[2] = ADM_P2_CFG,
|
||||||
|
[3] = ADM_P3_CFG,
|
||||||
|
[4] = ADM_P4_CFG,
|
||||||
|
[5] = ADM_P5_CFG,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Split the register address in phy id and register
|
||||||
|
* it will get combined again by the mdio bus op
|
||||||
|
*/
|
||||||
|
#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f)
|
||||||
|
|
||||||
|
#endif
|
447
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c
Normal file
447
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* Marvell 88E6060 switch driver
|
||||||
|
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License v2 as published by the
|
||||||
|
* Free Software Foundation
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mii.h>
|
||||||
|
#include <linux/ethtool.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
|
#include <linux/if_vlan.h>
|
||||||
|
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include "mvswitch.h"
|
||||||
|
|
||||||
|
/* Undefine this to use trailer mode instead.
|
||||||
|
* I don't know if header mode works with all chips */
|
||||||
|
#define HEADER_MODE 1
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
|
||||||
|
MODULE_AUTHOR("Felix Fietkau");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
struct mvswitch_priv {
|
||||||
|
/* the driver's tx function */
|
||||||
|
int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
|
||||||
|
struct vlan_group *grp;
|
||||||
|
u8 vlans[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
|
||||||
|
|
||||||
|
static inline u16
|
||||||
|
r16(struct phy_device *phydev, int addr, int reg)
|
||||||
|
{
|
||||||
|
return phydev->bus->read(phydev->bus, addr, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
w16(struct phy_device *phydev, int addr, int reg, u16 val)
|
||||||
|
{
|
||||||
|
phydev->bus->write(phydev->bus, addr, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv;
|
||||||
|
char *buf = NULL;
|
||||||
|
u16 vid;
|
||||||
|
|
||||||
|
priv = dev->phy_ptr;
|
||||||
|
if (unlikely(!priv))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (unlikely(skb->len < 16))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
#ifdef HEADER_MODE
|
||||||
|
if (__vlan_hwaccel_get_tag(skb, &vid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
|
||||||
|
if (pskb_expand_head(skb, MV_HEADER_SIZE, 0, GFP_ATOMIC))
|
||||||
|
goto error_expand;
|
||||||
|
if (skb->len < 62)
|
||||||
|
skb->len = 62;
|
||||||
|
}
|
||||||
|
buf = skb_push(skb, MV_HEADER_SIZE);
|
||||||
|
#else
|
||||||
|
if (__vlan_get_tag(skb, &vid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (unlikely((vid > 15 || !priv->vlans[vid])))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (skb->len <= 64) {
|
||||||
|
if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
|
||||||
|
goto error_expand;
|
||||||
|
|
||||||
|
buf = skb->data + 64;
|
||||||
|
skb->len = 64 + MV_TRAILER_SIZE;
|
||||||
|
} else {
|
||||||
|
if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
|
||||||
|
if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
|
||||||
|
goto error_expand;
|
||||||
|
}
|
||||||
|
buf = skb_put(skb, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move the ethernet header 4 bytes forward, overwriting the vlan tag */
|
||||||
|
memmove(skb->data + 4, skb->data, 12);
|
||||||
|
skb->data += 4;
|
||||||
|
skb->len -= 4;
|
||||||
|
skb->mac_header += 4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HEADER_MODE
|
||||||
|
/* prepend the tag */
|
||||||
|
*((__be16 *) buf) = cpu_to_be16(
|
||||||
|
((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
|
||||||
|
((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
/* append the tag */
|
||||||
|
*((__be32 *) buf) = cpu_to_be32((
|
||||||
|
(MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
|
||||||
|
((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
|
||||||
|
));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return priv->hardstart(skb, dev);
|
||||||
|
|
||||||
|
error_expand:
|
||||||
|
if (net_ratelimit())
|
||||||
|
printk("%s: failed to expand/update skb for the switch\n", dev->name);
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* any errors? drop the packet! */
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_mangle_rx(struct sk_buff *skb, int napi)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv;
|
||||||
|
struct net_device *dev;
|
||||||
|
int vlan = -1;
|
||||||
|
unsigned char *buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev = skb->dev;
|
||||||
|
if (!dev)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
priv = dev->phy_ptr;
|
||||||
|
if (!priv)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!priv->grp)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
#ifdef HEADER_MODE
|
||||||
|
buf = skb->data;
|
||||||
|
skb_pull(skb, MV_HEADER_SIZE);
|
||||||
|
#else
|
||||||
|
buf = skb->data + skb->len - MV_TRAILER_SIZE;
|
||||||
|
if (buf[0] != 0x80)
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* look for the vlan matching the incoming port */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
|
||||||
|
if ((1 << buf[1]) & priv->vlans[i])
|
||||||
|
vlan = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlan == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||||
|
|
||||||
|
if (napi)
|
||||||
|
return vlan_hwaccel_receive_skb(skb, priv->grp, vlan);
|
||||||
|
else
|
||||||
|
return vlan_hwaccel_rx(skb, priv->grp, vlan);
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* no vlan? eat the packet! */
|
||||||
|
dev_kfree_skb_any(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_netif_rx(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return mvswitch_mangle_rx(skb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_netif_receive_skb(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return mvswitch_mangle_rx(skb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv = dev->phy_ptr;
|
||||||
|
priv->grp = grp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_config_init(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv = to_mvsw(pdev);
|
||||||
|
struct net_device *dev = pdev->attached_dev;
|
||||||
|
u8 vlmap = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
|
||||||
|
pdev->supported = ADVERTISED_100baseT_Full;
|
||||||
|
pdev->advertising = ADVERTISED_100baseT_Full;
|
||||||
|
dev->phy_ptr = priv;
|
||||||
|
|
||||||
|
/* initialize default vlans */
|
||||||
|
for (i = 0; i < MV_PORTS; i++)
|
||||||
|
priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
|
||||||
|
|
||||||
|
/* before entering reset, disable all ports */
|
||||||
|
for (i = 0; i < MV_PORTS; i++)
|
||||||
|
w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
|
||||||
|
|
||||||
|
msleep(2); /* wait for the status change to settle in */
|
||||||
|
|
||||||
|
/* put the device in reset and set ATU flags */
|
||||||
|
w16(pdev, MV_SWITCHREG(ATU_CTRL),
|
||||||
|
MV_ATUCTL_RESET |
|
||||||
|
MV_ATUCTL_ATU_1K |
|
||||||
|
MV_ATUCTL_AGETIME(4080) /* maximum */
|
||||||
|
);
|
||||||
|
|
||||||
|
i = 100; /* timeout */
|
||||||
|
do {
|
||||||
|
if (!(r16(pdev, MV_SWITCHREG(ATU_CTRL)) & MV_ATUCTL_RESET))
|
||||||
|
break;
|
||||||
|
msleep(1);
|
||||||
|
} while (--i > 0);
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize the cpu port */
|
||||||
|
w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
|
||||||
|
#ifdef HEADER_MODE
|
||||||
|
MV_PORTCTRL_HEADER |
|
||||||
|
#else
|
||||||
|
MV_PORTCTRL_RXTR |
|
||||||
|
MV_PORTCTRL_TXTR |
|
||||||
|
#endif
|
||||||
|
MV_PORTCTRL_ENABLED
|
||||||
|
);
|
||||||
|
/* wait for the phy change to settle in */
|
||||||
|
msleep(2);
|
||||||
|
for (i = 0; i < MV_PORTS; i++) {
|
||||||
|
u8 pvid = 0;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
vlmap = 0;
|
||||||
|
|
||||||
|
/* look for the matching vlan */
|
||||||
|
for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
|
||||||
|
if (priv->vlans[j] & (1 << i)) {
|
||||||
|
vlmap = priv->vlans[j];
|
||||||
|
pvid = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* leave port unconfigured if it's not part of a vlan */
|
||||||
|
if (!vlmap)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* add the cpu port to the allowed destinations list */
|
||||||
|
vlmap |= (1 << MV_CPUPORT);
|
||||||
|
|
||||||
|
/* take port out of its own vlan destination map */
|
||||||
|
vlmap &= ~(1 << i);
|
||||||
|
|
||||||
|
/* apply vlan settings */
|
||||||
|
w16(pdev, MV_PORTREG(VLANMAP, i),
|
||||||
|
MV_PORTVLAN_PORTS(vlmap) |
|
||||||
|
MV_PORTVLAN_ID(pvid)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* re-enable port */
|
||||||
|
w16(pdev, MV_PORTREG(CONTROL, i), MV_PORTCTRL_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build the target list for the cpu port */
|
||||||
|
for (i = 0; i < MV_PORTS; i++)
|
||||||
|
vlmap |= (1 << i);
|
||||||
|
|
||||||
|
w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
|
||||||
|
MV_PORTVLAN_PORTS(vlmap)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* set the port association vector */
|
||||||
|
for (i = 0; i <= MV_PORTS; i++) {
|
||||||
|
w16(pdev, MV_PORTREG(ASSOC, i),
|
||||||
|
MV_PORTASSOC_PORTS(1 << i)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* init switch control */
|
||||||
|
w16(pdev, MV_SWITCHREG(CTRL),
|
||||||
|
MV_SWITCHCTL_MSIZE |
|
||||||
|
MV_SWITCHCTL_DROP
|
||||||
|
);
|
||||||
|
|
||||||
|
/* hook into the tx function */
|
||||||
|
priv->hardstart = dev->hard_start_xmit;
|
||||||
|
pdev->netif_receive_skb = mvswitch_netif_receive_skb;
|
||||||
|
pdev->netif_rx = mvswitch_netif_rx;
|
||||||
|
dev->hard_start_xmit = mvswitch_mangle_tx;
|
||||||
|
dev->vlan_rx_register = mvswitch_vlan_rx_register;
|
||||||
|
#ifdef HEADER_MODE
|
||||||
|
dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
|
||||||
|
#else
|
||||||
|
dev->features |= NETIF_F_HW_VLAN_RX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_read_status(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
phydev->speed = SPEED_100;
|
||||||
|
phydev->duplex = DUPLEX_FULL;
|
||||||
|
phydev->state = PHY_UP;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_config_aneg(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mvswitch_remove(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv = to_mvsw(pdev);
|
||||||
|
struct net_device *dev = pdev->attached_dev;
|
||||||
|
|
||||||
|
/* restore old xmit handler */
|
||||||
|
if (priv->hardstart && dev)
|
||||||
|
dev->hard_start_xmit = priv->hardstart;
|
||||||
|
dev->vlan_rx_register = NULL;
|
||||||
|
dev->vlan_rx_kill_vid = NULL;
|
||||||
|
dev->phy_ptr = NULL;
|
||||||
|
dev->features &= ~NETIF_F_HW_VLAN_RX;
|
||||||
|
kfree(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mvswitch_detect(struct mii_bus *bus, int addr)
|
||||||
|
{
|
||||||
|
u16 reg;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* we attach to phy id 31 to make sure that the late probe works */
|
||||||
|
if (addr != 31)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* look for the switch on the bus */
|
||||||
|
reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
|
||||||
|
if (reg != MV_IDENT_VALUE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we've established that the switch actually exists, let's
|
||||||
|
* get rid of the competition :)
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 31; i++) {
|
||||||
|
if (!bus->phy_map[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
device_unregister(&bus->phy_map[i]->dev);
|
||||||
|
kfree(bus->phy_map[i]);
|
||||||
|
bus->phy_map[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mvswitch_probe(struct phy_device *pdev)
|
||||||
|
{
|
||||||
|
struct mvswitch_priv *priv;
|
||||||
|
|
||||||
|
priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
|
||||||
|
if (priv == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pdev->priv = priv;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct phy_driver mvswitch_driver = {
|
||||||
|
.name = "Marvell 88E6060",
|
||||||
|
.features = PHY_BASIC_FEATURES,
|
||||||
|
.detect = &mvswitch_detect,
|
||||||
|
.probe = &mvswitch_probe,
|
||||||
|
.remove = &mvswitch_remove,
|
||||||
|
.config_init = &mvswitch_config_init,
|
||||||
|
.config_aneg = &mvswitch_config_aneg,
|
||||||
|
.read_status = &mvswitch_read_status,
|
||||||
|
.driver = { .owner = THIS_MODULE,},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init
|
||||||
|
mvswitch_init(void)
|
||||||
|
{
|
||||||
|
return phy_driver_register(&mvswitch_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit
|
||||||
|
mvswitch_exit(void)
|
||||||
|
{
|
||||||
|
phy_driver_unregister(&mvswitch_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(mvswitch_init);
|
||||||
|
module_exit(mvswitch_exit);
|
129
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h
Normal file
129
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Marvell 88E6060 switch driver
|
||||||
|
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License v2 as published by the
|
||||||
|
* Free Software Foundation
|
||||||
|
*/
|
||||||
|
#ifndef __MVSWITCH_H
|
||||||
|
#define __MVSWITCH_H
|
||||||
|
|
||||||
|
#define MV_HEADER_SIZE 2
|
||||||
|
#define MV_HEADER_PORTS_M 0x001f
|
||||||
|
#define MV_HEADER_PORTS_S 0
|
||||||
|
#define MV_HEADER_VLAN_M 0xf000
|
||||||
|
#define MV_HEADER_VLAN_S 12
|
||||||
|
|
||||||
|
#define MV_TRAILER_SIZE 4
|
||||||
|
#define MV_TRAILER_PORTS_M 0x1f
|
||||||
|
#define MV_TRAILER_PORTS_S 16
|
||||||
|
#define MV_TRAILER_FLAGS_S 24
|
||||||
|
#define MV_TRAILER_OVERRIDE 0x80
|
||||||
|
|
||||||
|
|
||||||
|
#define MV_PORTS 5
|
||||||
|
#define MV_WANPORT 4
|
||||||
|
#define MV_CPUPORT 5
|
||||||
|
|
||||||
|
#define MV_BASE 0x10
|
||||||
|
|
||||||
|
#define MV_PHYPORT_BASE (MV_BASE + 0x0)
|
||||||
|
#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n))
|
||||||
|
#define MV_SWITCHPORT_BASE (MV_BASE + 0x8)
|
||||||
|
#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n))
|
||||||
|
#define MV_SWITCHREGS (MV_BASE + 0xf)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MV_PHY_CONTROL = 0x00,
|
||||||
|
MV_PHY_STATUS = 0x01,
|
||||||
|
MV_PHY_IDENT0 = 0x02,
|
||||||
|
MV_PHY_IDENT1 = 0x03,
|
||||||
|
MV_PHY_ANEG = 0x04,
|
||||||
|
MV_PHY_LINK_ABILITY = 0x05,
|
||||||
|
MV_PHY_ANEG_EXPAND = 0x06,
|
||||||
|
MV_PHY_XMIT_NEXTP = 0x07,
|
||||||
|
MV_PHY_LINK_NEXTP = 0x08,
|
||||||
|
MV_PHY_CONTROL1 = 0x10,
|
||||||
|
MV_PHY_STATUS1 = 0x11,
|
||||||
|
MV_PHY_INTR_EN = 0x12,
|
||||||
|
MV_PHY_INTR_STATUS = 0x13,
|
||||||
|
MV_PHY_INTR_PORT = 0x14,
|
||||||
|
MV_PHY_RECV_COUNTER = 0x16,
|
||||||
|
MV_PHY_LED_PARALLEL = 0x16,
|
||||||
|
MV_PHY_LED_STREAM = 0x17,
|
||||||
|
MV_PHY_LED_CTRL = 0x18,
|
||||||
|
MV_PHY_LED_OVERRIDE = 0x19,
|
||||||
|
MV_PHY_VCT_CTRL = 0x1a,
|
||||||
|
MV_PHY_VCT_STATUS = 0x1b,
|
||||||
|
MV_PHY_CONTROL2 = 0x1e
|
||||||
|
};
|
||||||
|
#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MV_PORT_STATUS = 0x00,
|
||||||
|
MV_PORT_IDENT = 0x03,
|
||||||
|
MV_PORT_CONTROL = 0x04,
|
||||||
|
MV_PORT_VLANMAP = 0x06,
|
||||||
|
MV_PORT_ASSOC = 0x0b,
|
||||||
|
MV_PORT_RXCOUNT = 0x10,
|
||||||
|
MV_PORT_TXCOUNT = 0x11,
|
||||||
|
};
|
||||||
|
#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MV_PORTCTRL_BLOCK = (1 << 0),
|
||||||
|
MV_PORTCTRL_LEARN = (2 << 0),
|
||||||
|
MV_PORTCTRL_ENABLED = (3 << 0),
|
||||||
|
MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */
|
||||||
|
MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */
|
||||||
|
MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */
|
||||||
|
MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */
|
||||||
|
MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
|
||||||
|
#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
|
||||||
|
|
||||||
|
#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
|
||||||
|
#define MV_PORTASSOC_MONITOR (1 << 15)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MV_SWITCH_MAC0 = 0x01,
|
||||||
|
MV_SWITCH_MAC1 = 0x02,
|
||||||
|
MV_SWITCH_MAC2 = 0x03,
|
||||||
|
MV_SWITCH_CTRL = 0x04,
|
||||||
|
MV_SWITCH_ATU_CTRL = 0x0a,
|
||||||
|
MV_SWITCH_ATU_OP = 0x0b,
|
||||||
|
MV_SWITCH_ATU_DATA = 0x0c,
|
||||||
|
MV_SWITCH_ATU_MAC0 = 0x0d,
|
||||||
|
MV_SWITCH_ATU_MAC1 = 0x0e,
|
||||||
|
MV_SWITCH_ATU_MAC2 = 0x0f,
|
||||||
|
};
|
||||||
|
#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */
|
||||||
|
MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */
|
||||||
|
MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */
|
||||||
|
MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */
|
||||||
|
MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */
|
||||||
|
MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */
|
||||||
|
MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */
|
||||||
|
MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4)
|
||||||
|
MV_ATUCTL_ATU_256 = (0 << 12),
|
||||||
|
MV_ATUCTL_ATU_512 = (1 << 12),
|
||||||
|
MV_ATUCTL_ATU_1K = (2 << 12),
|
||||||
|
MV_ATUCTL_ATUMASK = (3 << 12),
|
||||||
|
MV_ATUCTL_NO_LEARN = (1 << 14),
|
||||||
|
MV_ATUCTL_RESET = (1 << 15),
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MV_IDENT_MASK 0xfff0
|
||||||
|
#define MV_IDENT_VALUE 0x0600
|
||||||
|
|
||||||
|
#endif
|
242
target/linux/generic-2.6/files-2.6.25/drivers/spi/spi_gpio.c
Normal file
242
target/linux/generic-2.6/files-2.6.25/drivers/spi/spi_gpio.c
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* Bitbanging SPI bus driver using GPIO API
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Piotr Skamruk
|
||||||
|
* Copyright (c) 2008 Michael Buesch
|
||||||
|
*
|
||||||
|
* based on spi_s3c2410_gpio.c
|
||||||
|
* Copyright (c) 2006 Ben Dooks
|
||||||
|
* Copyright (c) 2006 Simtec Electronics
|
||||||
|
* and on i2c-gpio.c
|
||||||
|
* Copyright (C) 2007 Atmel Corporation
|
||||||
|
*
|
||||||
|
* 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/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
#include <linux/spi/spi_bitbang.h>
|
||||||
|
#include "linux/spi/spi_gpio.h" //XXX
|
||||||
|
#include <asm/gpio.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct spi_gpio {
|
||||||
|
struct spi_bitbang bitbang;
|
||||||
|
struct spi_gpio_platform_data *info;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct spi_board_info bi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
|
||||||
|
{
|
||||||
|
return dev->controller_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setsck(struct spi_device *dev, int val)
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp = spidev_to_sg(dev);
|
||||||
|
gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setmosi(struct spi_device *dev, int val )
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp = spidev_to_sg(dev);
|
||||||
|
gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 getmiso(struct spi_device *dev)
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp = spidev_to_sg(dev);
|
||||||
|
return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp = spidev_to_sg(dev);
|
||||||
|
|
||||||
|
if (!sp->info->no_spi_delay)
|
||||||
|
ndelay(nsecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define spidelay(nsecs) do { \
|
||||||
|
/* Steal the spi_device pointer from our caller. \
|
||||||
|
* The bitbang-API should probably get fixed here... */ \
|
||||||
|
do_spidelay(spi, nsecs); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define EXPAND_BITBANG_TXRX
|
||||||
|
#include <linux/spi/spi_bitbang.h>
|
||||||
|
|
||||||
|
static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
|
||||||
|
unsigned nsecs, u32 word, u8 bits)
|
||||||
|
{
|
||||||
|
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
|
||||||
|
unsigned nsecs, u32 word, u8 bits)
|
||||||
|
{
|
||||||
|
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
|
||||||
|
unsigned nsecs, u32 word, u8 bits)
|
||||||
|
{
|
||||||
|
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
|
||||||
|
unsigned nsecs, u32 word, u8 bits)
|
||||||
|
{
|
||||||
|
return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_gpio_chipselect(struct spi_device *dev, int on)
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp = spidev_to_sg(dev);
|
||||||
|
|
||||||
|
if (sp->info->cs_activelow)
|
||||||
|
on = !on;
|
||||||
|
gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_gpio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct spi_master *master;
|
||||||
|
struct spi_gpio_platform_data *pdata;
|
||||||
|
struct spi_gpio *sp;
|
||||||
|
struct spi_device *spidev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
pdata = pdev->dev.platform_data;
|
||||||
|
if (!pdata)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
err = -ENOMEM;
|
||||||
|
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
|
||||||
|
if (!master)
|
||||||
|
goto err_alloc_master;
|
||||||
|
|
||||||
|
sp = spi_master_get_devdata(master);
|
||||||
|
platform_set_drvdata(pdev, sp);
|
||||||
|
sp->info = pdata;
|
||||||
|
|
||||||
|
err = gpio_request(pdata->pin_clk, "spi_clock");
|
||||||
|
if (err)
|
||||||
|
goto err_request_clk;
|
||||||
|
err = gpio_request(pdata->pin_mosi, "spi_mosi");
|
||||||
|
if (err)
|
||||||
|
goto err_request_mosi;
|
||||||
|
err = gpio_request(pdata->pin_miso, "spi_miso");
|
||||||
|
if (err)
|
||||||
|
goto err_request_miso;
|
||||||
|
err = gpio_request(pdata->pin_cs, "spi_cs");
|
||||||
|
if (err)
|
||||||
|
goto err_request_cs;
|
||||||
|
|
||||||
|
sp->bitbang.master = spi_master_get(master);
|
||||||
|
sp->bitbang.master->bus_num = -1;
|
||||||
|
sp->bitbang.master->num_chipselect = 1;
|
||||||
|
sp->bitbang.chipselect = spi_gpio_chipselect;
|
||||||
|
sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
|
||||||
|
sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
|
||||||
|
sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
|
||||||
|
sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
|
||||||
|
|
||||||
|
gpio_direction_output(pdata->pin_clk, 0);
|
||||||
|
gpio_direction_output(pdata->pin_mosi, 0);
|
||||||
|
gpio_direction_output(pdata->pin_cs,
|
||||||
|
pdata->cs_activelow ? 1 : 0);
|
||||||
|
gpio_direction_input(pdata->pin_miso);
|
||||||
|
|
||||||
|
err = spi_bitbang_start(&sp->bitbang);
|
||||||
|
if (err)
|
||||||
|
goto err_no_bitbang;
|
||||||
|
err = pdata->boardinfo_setup(&sp->bi, master,
|
||||||
|
pdata->boardinfo_setup_data);
|
||||||
|
if (err)
|
||||||
|
goto err_bi_setup;
|
||||||
|
sp->bi.controller_data = sp;
|
||||||
|
spidev = spi_new_device(master, &sp->bi);
|
||||||
|
if (!spidev)
|
||||||
|
goto err_new_dev;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_new_dev:
|
||||||
|
err_bi_setup:
|
||||||
|
spi_bitbang_stop(&sp->bitbang);
|
||||||
|
err_no_bitbang:
|
||||||
|
spi_master_put(sp->bitbang.master);
|
||||||
|
gpio_free(pdata->pin_cs);
|
||||||
|
err_request_cs:
|
||||||
|
gpio_free(pdata->pin_miso);
|
||||||
|
err_request_miso:
|
||||||
|
gpio_free(pdata->pin_mosi);
|
||||||
|
err_request_mosi:
|
||||||
|
gpio_free(pdata->pin_clk);
|
||||||
|
err_request_clk:
|
||||||
|
kfree(master);
|
||||||
|
|
||||||
|
err_alloc_master:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit spi_gpio_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct spi_gpio *sp;
|
||||||
|
struct spi_gpio_platform_data *pdata;
|
||||||
|
|
||||||
|
pdata = pdev->dev.platform_data;
|
||||||
|
sp = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
gpio_free(pdata->pin_clk);
|
||||||
|
gpio_free(pdata->pin_mosi);
|
||||||
|
gpio_free(pdata->pin_miso);
|
||||||
|
gpio_free(pdata->pin_cs);
|
||||||
|
spi_bitbang_stop(&sp->bitbang);
|
||||||
|
spi_master_put(sp->bitbang.master);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver spi_gpio_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "spi-gpio",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = spi_gpio_probe,
|
||||||
|
.remove = __devexit_p(spi_gpio_remove),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init spi_gpio_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = platform_driver_register(&spi_gpio_driver);
|
||||||
|
if (err)
|
||||||
|
printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
module_init(spi_gpio_init);
|
||||||
|
|
||||||
|
static void __exit spi_gpio_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&spi_gpio_driver);
|
||||||
|
}
|
||||||
|
module_exit(spi_gpio_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
|
||||||
|
MODULE_AUTHOR("Michael Buesch");
|
||||||
|
MODULE_DESCRIPTION("Platform independent GPIO bitbangling SPI driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
175
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Kconfig
Normal file
175
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Kconfig
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
#
|
||||||
|
# YAFFS file system configurations
|
||||||
|
#
|
||||||
|
|
||||||
|
config YAFFS_FS
|
||||||
|
tristate "YAFFS2 file system support"
|
||||||
|
default n
|
||||||
|
depends on MTD
|
||||||
|
select YAFFS_YAFFS1
|
||||||
|
select YAFFS_YAFFS2
|
||||||
|
help
|
||||||
|
YAFFS2, or Yet Another Flash Filing System, is a filing system
|
||||||
|
optimised for NAND Flash chips.
|
||||||
|
|
||||||
|
To compile the YAFFS2 file system support as a module, choose M
|
||||||
|
here: the module will be called yaffs2.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
Further information on YAFFS2 is available at
|
||||||
|
<http://www.aleph1.co.uk/yaffs/>.
|
||||||
|
|
||||||
|
config YAFFS_YAFFS1
|
||||||
|
bool "512 byte / page devices"
|
||||||
|
depends on YAFFS_FS
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Enable YAFFS1 support -- yaffs for 512 byte / page devices
|
||||||
|
|
||||||
|
Not needed for 2K-page devices.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config YAFFS_9BYTE_TAGS
|
||||||
|
bool "Use older-style on-NAND data format with pageStatus byte"
|
||||||
|
depends on YAFFS_YAFFS1
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
|
||||||
|
Older-style on-NAND data format has a "pageStatus" byte to record
|
||||||
|
chunk/page state. This byte is zero when the page is discarded.
|
||||||
|
Choose this option if you have existing on-NAND data using this
|
||||||
|
format that you need to continue to support. New data written
|
||||||
|
also uses the older-style format. Note: Use of this option
|
||||||
|
generally requires that MTD's oob layout be adjusted to use the
|
||||||
|
older-style format. See notes on tags formats and MTD versions.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config YAFFS_DOES_ECC
|
||||||
|
bool "Lets Yaffs do its own ECC"
|
||||||
|
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This enables Yaffs to use its own ECC functions instead of using
|
||||||
|
the ones from the generic MTD-NAND driver.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config YAFFS_ECC_WRONG_ORDER
|
||||||
|
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
|
||||||
|
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This makes yaffs_ecc.c use the same ecc byte order as Steven
|
||||||
|
Hill's nand_ecc.c. If not set, then you get the same ecc byte
|
||||||
|
order as SmartMedia.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config YAFFS_YAFFS2
|
||||||
|
bool "2048 byte (or larger) / page devices"
|
||||||
|
depends on YAFFS_FS
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config YAFFS_AUTO_YAFFS2
|
||||||
|
bool "Autoselect yaffs2 format"
|
||||||
|
depends on YAFFS_YAFFS2
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Without this, you need to explicitely use yaffs2 as the file
|
||||||
|
system type. With this, you can say "yaffs" and yaffs or yaffs2
|
||||||
|
will be used depending on the device page size (yaffs on
|
||||||
|
512-byte page devices, yaffs2 on 2K page devices).
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config YAFFS_DISABLE_LAZY_LOAD
|
||||||
|
bool "Disable lazy loading"
|
||||||
|
depends on YAFFS_YAFFS2
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
"Lazy loading" defers loading file details until they are
|
||||||
|
required. This saves mount time, but makes the first look-up
|
||||||
|
a bit longer.
|
||||||
|
|
||||||
|
Lazy loading will only happen if enabled by this option being 'n'
|
||||||
|
and if the appropriate tags are available, else yaffs2 will
|
||||||
|
automatically fall back to immediate loading and do the right
|
||||||
|
thing.
|
||||||
|
|
||||||
|
Lazy laoding will be required by checkpointing.
|
||||||
|
|
||||||
|
Setting this to 'y' will disable lazy loading.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
|
||||||
|
int "Reserved blocks for checkpointing"
|
||||||
|
depends on YAFFS_YAFFS2
|
||||||
|
default 10
|
||||||
|
help
|
||||||
|
Give the number of Blocks to reserve for checkpointing.
|
||||||
|
Checkpointing saves the state at unmount so that mounting is
|
||||||
|
much faster as a scan of all the flash to regenerate this state
|
||||||
|
is not needed. These Blocks are reserved per partition, so if
|
||||||
|
you have very small partitions the default (10) may be a mess
|
||||||
|
for you. You can set this value to 0, but that does not mean
|
||||||
|
checkpointing is disabled at all. There only won't be any
|
||||||
|
specially reserved blocks for checkpointing, so if there is
|
||||||
|
enough free space on the filesystem, it will be used for
|
||||||
|
checkpointing.
|
||||||
|
|
||||||
|
If unsure, leave at default (10), but don't wonder if there are
|
||||||
|
always 2MB used on your large page device partition (10 x 2k
|
||||||
|
pagesize). When using small partitions or when being very small
|
||||||
|
on space, you probably want to set this to zero.
|
||||||
|
|
||||||
|
config YAFFS_DISABLE_WIDE_TNODES
|
||||||
|
bool "Turn off wide tnodes"
|
||||||
|
depends on YAFFS_FS
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
|
||||||
|
page devices and >=128MB for 2k page devices. They use slightly
|
||||||
|
more RAM but are faster since they eliminate chunk group
|
||||||
|
searching.
|
||||||
|
|
||||||
|
Setting this to 'y' will force tnode width to 16 bits and save
|
||||||
|
memory but make large arrays slower.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
|
||||||
|
bool "Force chunk erase check"
|
||||||
|
depends on YAFFS_FS
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Normally YAFFS only checks chunks before writing until an erased
|
||||||
|
chunk is found. This helps to detect any partially written
|
||||||
|
chunks that might have happened due to power loss.
|
||||||
|
|
||||||
|
Enabling this forces on the test that chunks are erased in flash
|
||||||
|
before writing to them. This takes more time but is potentially
|
||||||
|
a bit more secure.
|
||||||
|
|
||||||
|
Suggest setting Y during development and ironing out driver
|
||||||
|
issues etc. Suggest setting to N if you want faster writing.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config YAFFS_SHORT_NAMES_IN_RAM
|
||||||
|
bool "Cache short names in RAM"
|
||||||
|
depends on YAFFS_FS
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
If this config is set, then short names are stored with the
|
||||||
|
yaffs_Object. This costs an extra 16 bytes of RAM per object,
|
||||||
|
but makes look-ups faster.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
11
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Makefile
Normal file
11
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#
|
||||||
|
# Makefile for the linux YAFFS filesystem routines.
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||||
|
|
||||||
|
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
|
||||||
|
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||||
|
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||||
|
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
|
||||||
|
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o
|
264
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/devextras.h
Normal file
264
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/devextras.h
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is just holds extra declarations used during development.
|
||||||
|
* Most of these are from kernel includes placed here so we can use them in
|
||||||
|
* applications.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __EXTRAS_H__
|
||||||
|
#define __EXTRAS_H__
|
||||||
|
|
||||||
|
#if defined WIN32
|
||||||
|
#define __inline__ __inline
|
||||||
|
#define new newHack
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(defined __KERNEL__) || (defined WIN32)
|
||||||
|
|
||||||
|
/* User space defines */
|
||||||
|
|
||||||
|
typedef unsigned char __u8;
|
||||||
|
typedef unsigned short __u16;
|
||||||
|
typedef unsigned __u32;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple doubly linked list implementation.
|
||||||
|
*
|
||||||
|
* Some of the internal functions ("__xxx") are useful when
|
||||||
|
* manipulating whole lists rather than single entries, as
|
||||||
|
* sometimes we already know the next/prev entries and we can
|
||||||
|
* generate better code by using them directly rather than
|
||||||
|
* using the generic single-entry routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define prefetch(x) 1
|
||||||
|
|
||||||
|
struct list_head {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||||
|
|
||||||
|
#define LIST_HEAD(name) \
|
||||||
|
struct list_head name = LIST_HEAD_INIT(name)
|
||||||
|
|
||||||
|
#define INIT_LIST_HEAD(ptr) do { \
|
||||||
|
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a new entry between two known consecutive entries.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static __inline__ void __list_add(struct list_head *new,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = new;
|
||||||
|
new->next = next;
|
||||||
|
new->prev = prev;
|
||||||
|
prev->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it after
|
||||||
|
*
|
||||||
|
* Insert a new entry after the specified head.
|
||||||
|
* This is good for implementing stacks.
|
||||||
|
*/
|
||||||
|
static __inline__ void list_add(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add_tail - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it before
|
||||||
|
*
|
||||||
|
* Insert a new entry before the specified head.
|
||||||
|
* This is useful for implementing queues.
|
||||||
|
*/
|
||||||
|
static __inline__ void list_add_tail(struct list_head *new,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a list entry by making the prev/next entries
|
||||||
|
* point to each other.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static __inline__ void __list_del(struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del - deletes entry from list.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
* Note: list_empty on entry does not return true after this, the entry is
|
||||||
|
* in an undefined state.
|
||||||
|
*/
|
||||||
|
static __inline__ void list_del(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del_init - deletes entry from list and reinitialize it.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
*/
|
||||||
|
static __inline__ void list_del_init(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
INIT_LIST_HEAD(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty - tests whether a list is empty
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static __inline__ int list_empty(struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice - join two lists
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*/
|
||||||
|
static __inline__ void list_splice(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
struct list_head *first = list->next;
|
||||||
|
|
||||||
|
if (first != list) {
|
||||||
|
struct list_head *last = list->prev;
|
||||||
|
struct list_head *at = head->next;
|
||||||
|
|
||||||
|
first->prev = head;
|
||||||
|
head->next = first;
|
||||||
|
|
||||||
|
last->next = at;
|
||||||
|
at->prev = last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_entry - get the struct for this entry
|
||||||
|
* @ptr: the &struct list_head pointer.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_struct within the struct.
|
||||||
|
*/
|
||||||
|
#define list_entry(ptr, type, member) \
|
||||||
|
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each - iterate over a list
|
||||||
|
* @pos: the &struct list_head to use as a loop counter.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each(pos, head) \
|
||||||
|
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||||
|
pos = pos->next, prefetch(pos->next))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_safe - iterate over a list safe against removal
|
||||||
|
* of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop counter.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||||
|
pos = n, n = pos->next)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File types
|
||||||
|
*/
|
||||||
|
#define DT_UNKNOWN 0
|
||||||
|
#define DT_FIFO 1
|
||||||
|
#define DT_CHR 2
|
||||||
|
#define DT_DIR 4
|
||||||
|
#define DT_BLK 6
|
||||||
|
#define DT_REG 8
|
||||||
|
#define DT_LNK 10
|
||||||
|
#define DT_SOCK 12
|
||||||
|
#define DT_WHT 14
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attribute flags. These should be or-ed together to figure out what
|
||||||
|
* has been changed!
|
||||||
|
*/
|
||||||
|
#define ATTR_MODE 1
|
||||||
|
#define ATTR_UID 2
|
||||||
|
#define ATTR_GID 4
|
||||||
|
#define ATTR_SIZE 8
|
||||||
|
#define ATTR_ATIME 16
|
||||||
|
#define ATTR_MTIME 32
|
||||||
|
#define ATTR_CTIME 64
|
||||||
|
#define ATTR_ATIME_SET 128
|
||||||
|
#define ATTR_MTIME_SET 256
|
||||||
|
#define ATTR_FORCE 512 /* Not a change, but a change it */
|
||||||
|
#define ATTR_ATTR_FLAG 1024
|
||||||
|
|
||||||
|
struct iattr {
|
||||||
|
unsigned int ia_valid;
|
||||||
|
unsigned ia_mode;
|
||||||
|
unsigned ia_uid;
|
||||||
|
unsigned ia_gid;
|
||||||
|
unsigned ia_size;
|
||||||
|
unsigned ia_atime;
|
||||||
|
unsigned ia_mtime;
|
||||||
|
unsigned ia_ctime;
|
||||||
|
unsigned int ia_attr_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define KERN_DEBUG
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined WIN32
|
||||||
|
#undef new
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_CONFIG_H__
|
||||||
|
#define __YAFFS_CONFIG_H__
|
||||||
|
|
||||||
|
#ifdef YAFFS_OUT_OF_TREE
|
||||||
|
|
||||||
|
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
|
||||||
|
#define CONFIG_YAFFS_FS
|
||||||
|
#define CONFIG_YAFFS_YAFFS1
|
||||||
|
#define CONFIG_YAFFS_YAFFS2
|
||||||
|
|
||||||
|
/* These options are independent of each other. Select those that matter. */
|
||||||
|
|
||||||
|
/* Default: Not selected */
|
||||||
|
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
|
||||||
|
//#define CONFIG_YAFFS_DOES_ECC
|
||||||
|
|
||||||
|
/* Default: Not selected */
|
||||||
|
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
|
||||||
|
/* CONFIG_YAFFS_DOES_ECC is set */
|
||||||
|
//#define CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||||
|
|
||||||
|
/* Default: Selected */
|
||||||
|
/* Meaning: Disables testing whether chunks are erased before writing to them*/
|
||||||
|
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
|
||||||
|
|
||||||
|
/* Default: Selected */
|
||||||
|
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
|
||||||
|
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
||||||
|
|
||||||
|
/* Default: 10 */
|
||||||
|
/* Meaning: set the count of blocks to reserve for checkpointing */
|
||||||
|
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
Older-style on-NAND data format has a "pageStatus" byte to record
|
||||||
|
chunk/page state. This byte is zeroed when the page is discarded.
|
||||||
|
Choose this option if you have existing on-NAND data in this format
|
||||||
|
that you need to continue to support. New data written also uses the
|
||||||
|
older-style format.
|
||||||
|
Note: Use of this option generally requires that MTD's oob layout be
|
||||||
|
adjusted to use the older-style format. See notes on tags formats and
|
||||||
|
MTD versions.
|
||||||
|
*/
|
||||||
|
/* Default: Not selected */
|
||||||
|
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||||
|
#define CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
|
||||||
|
#endif /* YAFFS_OUT_OF_TREE */
|
||||||
|
|
||||||
|
#endif /* __YAFFS_CONFIG_H__ */
|
|
@ -0,0 +1,404 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *yaffs_checkptrw_c_version =
|
||||||
|
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
|
||||||
|
|
||||||
|
|
||||||
|
#include "yaffs_checkptrw.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,
|
||||||
|
(TSTR("checkpt blocks available = %d" TENDSTR),
|
||||||
|
blocksAvailable));
|
||||||
|
|
||||||
|
|
||||||
|
return (blocksAvailable <= 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int yaffs_CheckpointErase(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
if(!dev->eraseBlockInNAND)
|
||||||
|
return 0;
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
|
||||||
|
dev->internalStartBlock,dev->internalEndBlock));
|
||||||
|
|
||||||
|
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
|
||||||
|
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
|
||||||
|
if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
|
||||||
|
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
|
||||||
|
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
dev->nErasedBlocks++;
|
||||||
|
dev->nFreeChunks += dev->nChunksPerBlock;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dev->markNANDBlockBad(dev,i);
|
||||||
|
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->blocksInCheckpoint = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,
|
||||||
|
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
|
||||||
|
dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
|
||||||
|
|
||||||
|
if(dev->checkpointNextBlock >= 0 &&
|
||||||
|
dev->checkpointNextBlock <= dev->internalEndBlock &&
|
||||||
|
blocksAvailable > 0){
|
||||||
|
|
||||||
|
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
|
||||||
|
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
|
||||||
|
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
|
||||||
|
dev->checkpointNextBlock = i + 1;
|
||||||
|
dev->checkpointCurrentBlock = i;
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
|
||||||
|
|
||||||
|
dev->checkpointNextBlock = -1;
|
||||||
|
dev->checkpointCurrentBlock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
yaffs_ExtendedTags tags;
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
|
||||||
|
dev->blocksInCheckpoint, dev->checkpointNextBlock));
|
||||||
|
|
||||||
|
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
|
||||||
|
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
|
||||||
|
int chunk = i * dev->nChunksPerBlock;
|
||||||
|
int realignedChunk = chunk - dev->chunkOffset;
|
||||||
|
|
||||||
|
dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
|
||||||
|
i, tags.objectId,tags.sequenceNumber,tags.eccResult));
|
||||||
|
|
||||||
|
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
|
||||||
|
/* Right kind of block */
|
||||||
|
dev->checkpointNextBlock = tags.objectId;
|
||||||
|
dev->checkpointCurrentBlock = i;
|
||||||
|
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
|
||||||
|
dev->blocksInCheckpoint++;
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
|
||||||
|
|
||||||
|
dev->checkpointNextBlock = -1;
|
||||||
|
dev->checkpointCurrentBlock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Got the functions we need? */
|
||||||
|
if (!dev->writeChunkWithTagsToNAND ||
|
||||||
|
!dev->readChunkWithTagsFromNAND ||
|
||||||
|
!dev->eraseBlockInNAND ||
|
||||||
|
!dev->markNANDBlockBad)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(forWriting && !yaffs_CheckpointSpaceOk(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!dev->checkpointBuffer)
|
||||||
|
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
|
||||||
|
if(!dev->checkpointBuffer)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
dev->checkpointPageSequence = 0;
|
||||||
|
|
||||||
|
dev->checkpointOpenForWrite = forWriting;
|
||||||
|
|
||||||
|
dev->checkpointByteCount = 0;
|
||||||
|
dev->checkpointSum = 0;
|
||||||
|
dev->checkpointXor = 0;
|
||||||
|
dev->checkpointCurrentBlock = -1;
|
||||||
|
dev->checkpointCurrentChunk = -1;
|
||||||
|
dev->checkpointNextBlock = dev->internalStartBlock;
|
||||||
|
|
||||||
|
/* Erase all the blocks in the checkpoint area */
|
||||||
|
if(forWriting){
|
||||||
|
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
|
||||||
|
dev->checkpointByteOffset = 0;
|
||||||
|
return yaffs_CheckpointErase(dev);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
/* Set to a value that will kick off a read */
|
||||||
|
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
|
||||||
|
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
|
||||||
|
* going to be way more than we need */
|
||||||
|
dev->blocksInCheckpoint = 0;
|
||||||
|
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
|
||||||
|
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
|
||||||
|
for(i = 0; i < dev->checkpointMaxBlocks; i++)
|
||||||
|
dev->checkpointBlockList[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
|
||||||
|
{
|
||||||
|
__u32 compositeSum;
|
||||||
|
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
|
||||||
|
*sum = compositeSum;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
int chunk;
|
||||||
|
int realignedChunk;
|
||||||
|
|
||||||
|
yaffs_ExtendedTags tags;
|
||||||
|
|
||||||
|
if(dev->checkpointCurrentBlock < 0){
|
||||||
|
yaffs_CheckpointFindNextErasedBlock(dev);
|
||||||
|
dev->checkpointCurrentChunk = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dev->checkpointCurrentBlock < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tags.chunkDeleted = 0;
|
||||||
|
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
|
||||||
|
tags.chunkId = dev->checkpointPageSequence + 1;
|
||||||
|
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
|
||||||
|
tags.byteCount = dev->nDataBytesPerChunk;
|
||||||
|
if(dev->checkpointCurrentChunk == 0){
|
||||||
|
/* First chunk we write for the block? Set block state to
|
||||||
|
checkpoint */
|
||||||
|
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
|
||||||
|
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||||
|
dev->blocksInCheckpoint++;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
|
||||||
|
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
|
||||||
|
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
|
||||||
|
|
||||||
|
realignedChunk = chunk - dev->chunkOffset;
|
||||||
|
|
||||||
|
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
|
||||||
|
dev->checkpointByteOffset = 0;
|
||||||
|
dev->checkpointPageSequence++;
|
||||||
|
dev->checkpointCurrentChunk++;
|
||||||
|
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
|
||||||
|
dev->checkpointCurrentChunk = 0;
|
||||||
|
dev->checkpointCurrentBlock = -1;
|
||||||
|
}
|
||||||
|
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
int ok = 1;
|
||||||
|
|
||||||
|
|
||||||
|
__u8 * dataBytes = (__u8 *)data;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(!dev->checkpointBuffer)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!dev->checkpointOpenForWrite)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while(i < nBytes && ok) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
|
||||||
|
dev->checkpointSum += *dataBytes;
|
||||||
|
dev->checkpointXor ^= *dataBytes;
|
||||||
|
|
||||||
|
dev->checkpointByteOffset++;
|
||||||
|
i++;
|
||||||
|
dataBytes++;
|
||||||
|
dev->checkpointByteCount++;
|
||||||
|
|
||||||
|
|
||||||
|
if(dev->checkpointByteOffset < 0 ||
|
||||||
|
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
|
||||||
|
ok = yaffs_CheckpointFlushBuffer(dev);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
int ok = 1;
|
||||||
|
yaffs_ExtendedTags tags;
|
||||||
|
|
||||||
|
|
||||||
|
int chunk;
|
||||||
|
int realignedChunk;
|
||||||
|
|
||||||
|
__u8 *dataBytes = (__u8 *)data;
|
||||||
|
|
||||||
|
if(!dev->checkpointBuffer)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(dev->checkpointOpenForWrite)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while(i < nBytes && ok) {
|
||||||
|
|
||||||
|
|
||||||
|
if(dev->checkpointByteOffset < 0 ||
|
||||||
|
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
|
||||||
|
|
||||||
|
if(dev->checkpointCurrentBlock < 0){
|
||||||
|
yaffs_CheckpointFindNextCheckpointBlock(dev);
|
||||||
|
dev->checkpointCurrentChunk = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dev->checkpointCurrentBlock < 0)
|
||||||
|
ok = 0;
|
||||||
|
else {
|
||||||
|
|
||||||
|
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
|
||||||
|
dev->checkpointCurrentChunk;
|
||||||
|
|
||||||
|
realignedChunk = chunk - dev->chunkOffset;
|
||||||
|
|
||||||
|
/* read in the next chunk */
|
||||||
|
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
|
||||||
|
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
|
||||||
|
dev->checkpointBuffer,
|
||||||
|
&tags);
|
||||||
|
|
||||||
|
if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
|
||||||
|
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
|
||||||
|
ok = 0;
|
||||||
|
|
||||||
|
dev->checkpointByteOffset = 0;
|
||||||
|
dev->checkpointPageSequence++;
|
||||||
|
dev->checkpointCurrentChunk++;
|
||||||
|
|
||||||
|
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
|
||||||
|
dev->checkpointCurrentBlock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ok){
|
||||||
|
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
|
||||||
|
dev->checkpointSum += *dataBytes;
|
||||||
|
dev->checkpointXor ^= *dataBytes;
|
||||||
|
dev->checkpointByteOffset++;
|
||||||
|
i++;
|
||||||
|
dataBytes++;
|
||||||
|
dev->checkpointByteCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_CheckpointClose(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(dev->checkpointOpenForWrite){
|
||||||
|
if(dev->checkpointByteOffset != 0)
|
||||||
|
yaffs_CheckpointFlushBuffer(dev);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
|
||||||
|
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
|
||||||
|
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
|
||||||
|
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
|
||||||
|
else {
|
||||||
|
// Todo this looks odd...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
YFREE(dev->checkpointBlockList);
|
||||||
|
dev->checkpointBlockList = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
|
||||||
|
dev->nErasedBlocks -= dev->blocksInCheckpoint;
|
||||||
|
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
|
||||||
|
dev->checkpointByteCount));
|
||||||
|
|
||||||
|
if(dev->checkpointBuffer){
|
||||||
|
/* free the buffer */
|
||||||
|
YFREE(dev->checkpointBuffer);
|
||||||
|
dev->checkpointBuffer = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
|
||||||
|
{
|
||||||
|
/* Erase the first checksum block */
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
|
||||||
|
|
||||||
|
if(!yaffs_CheckpointSpaceOk(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return yaffs_CheckpointErase(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_CHECKPTRW_H__
|
||||||
|
#define __YAFFS_CHECKPTRW_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
|
||||||
|
|
||||||
|
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
|
||||||
|
|
||||||
|
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
|
||||||
|
|
||||||
|
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
|
||||||
|
|
||||||
|
int yaffs_CheckpointClose(yaffs_Device *dev);
|
||||||
|
|
||||||
|
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
331
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.c
Normal file
331
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.c
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code implements the ECC algorithm used in SmartMedia.
|
||||||
|
*
|
||||||
|
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
|
||||||
|
* The two unused bit are set to 1.
|
||||||
|
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
|
||||||
|
* blocks are used on a 512-byte NAND page.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Table generated by gen-ecc.c
|
||||||
|
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
|
||||||
|
* for each byte of data. These are instead provided in a table in bits7..2.
|
||||||
|
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
|
||||||
|
* this bytes influence on the line parity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *yaffs_ecc_c_version =
|
||||||
|
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
#include "yaffs_ecc.h"
|
||||||
|
|
||||||
|
static const unsigned char column_parity_table[] = {
|
||||||
|
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
|
||||||
|
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
|
||||||
|
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
|
||||||
|
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
|
||||||
|
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
|
||||||
|
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
|
||||||
|
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
|
||||||
|
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
|
||||||
|
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
|
||||||
|
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
|
||||||
|
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
|
||||||
|
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
|
||||||
|
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
|
||||||
|
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
|
||||||
|
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
|
||||||
|
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
|
||||||
|
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
|
||||||
|
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
|
||||||
|
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
|
||||||
|
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
|
||||||
|
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
|
||||||
|
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
|
||||||
|
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
|
||||||
|
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
|
||||||
|
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
|
||||||
|
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
|
||||||
|
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
|
||||||
|
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
|
||||||
|
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
|
||||||
|
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
|
||||||
|
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
|
||||||
|
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Count the bits in an unsigned char or a U32 */
|
||||||
|
|
||||||
|
static int yaffs_CountBits(unsigned char x)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
while (x) {
|
||||||
|
if (x & 1)
|
||||||
|
r++;
|
||||||
|
x >>= 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yaffs_CountBits32(unsigned x)
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
while (x) {
|
||||||
|
if (x & 1)
|
||||||
|
r++;
|
||||||
|
x >>= 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the ECC for a 256-byte block of data */
|
||||||
|
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
unsigned char col_parity = 0;
|
||||||
|
unsigned char line_parity = 0;
|
||||||
|
unsigned char line_parity_prime = 0;
|
||||||
|
unsigned char t;
|
||||||
|
unsigned char b;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
b = column_parity_table[*data++];
|
||||||
|
col_parity ^= b;
|
||||||
|
|
||||||
|
if (b & 0x01) // odd number of bits in the byte
|
||||||
|
{
|
||||||
|
line_parity ^= i;
|
||||||
|
line_parity_prime ^= ~i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ecc[2] = (~col_parity) | 0x03;
|
||||||
|
|
||||||
|
t = 0;
|
||||||
|
if (line_parity & 0x80)
|
||||||
|
t |= 0x80;
|
||||||
|
if (line_parity_prime & 0x80)
|
||||||
|
t |= 0x40;
|
||||||
|
if (line_parity & 0x40)
|
||||||
|
t |= 0x20;
|
||||||
|
if (line_parity_prime & 0x40)
|
||||||
|
t |= 0x10;
|
||||||
|
if (line_parity & 0x20)
|
||||||
|
t |= 0x08;
|
||||||
|
if (line_parity_prime & 0x20)
|
||||||
|
t |= 0x04;
|
||||||
|
if (line_parity & 0x10)
|
||||||
|
t |= 0x02;
|
||||||
|
if (line_parity_prime & 0x10)
|
||||||
|
t |= 0x01;
|
||||||
|
ecc[1] = ~t;
|
||||||
|
|
||||||
|
t = 0;
|
||||||
|
if (line_parity & 0x08)
|
||||||
|
t |= 0x80;
|
||||||
|
if (line_parity_prime & 0x08)
|
||||||
|
t |= 0x40;
|
||||||
|
if (line_parity & 0x04)
|
||||||
|
t |= 0x20;
|
||||||
|
if (line_parity_prime & 0x04)
|
||||||
|
t |= 0x10;
|
||||||
|
if (line_parity & 0x02)
|
||||||
|
t |= 0x08;
|
||||||
|
if (line_parity_prime & 0x02)
|
||||||
|
t |= 0x04;
|
||||||
|
if (line_parity & 0x01)
|
||||||
|
t |= 0x02;
|
||||||
|
if (line_parity_prime & 0x01)
|
||||||
|
t |= 0x01;
|
||||||
|
ecc[0] = ~t;
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||||
|
// Swap the bytes into the wrong order
|
||||||
|
t = ecc[0];
|
||||||
|
ecc[0] = ecc[1];
|
||||||
|
ecc[1] = t;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Correct the ECC on a 256 byte block of data */
|
||||||
|
|
||||||
|
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||||
|
const unsigned char *test_ecc)
|
||||||
|
{
|
||||||
|
unsigned char d0, d1, d2; /* deltas */
|
||||||
|
|
||||||
|
d0 = read_ecc[0] ^ test_ecc[0];
|
||||||
|
d1 = read_ecc[1] ^ test_ecc[1];
|
||||||
|
d2 = read_ecc[2] ^ test_ecc[2];
|
||||||
|
|
||||||
|
if ((d0 | d1 | d2) == 0)
|
||||||
|
return 0; /* no error */
|
||||||
|
|
||||||
|
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
|
||||||
|
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
|
||||||
|
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
|
||||||
|
/* Single bit (recoverable) error in data */
|
||||||
|
|
||||||
|
unsigned byte;
|
||||||
|
unsigned bit;
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||||
|
// swap the bytes to correct for the wrong order
|
||||||
|
unsigned char t;
|
||||||
|
|
||||||
|
t = d0;
|
||||||
|
d0 = d1;
|
||||||
|
d1 = t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bit = byte = 0;
|
||||||
|
|
||||||
|
if (d1 & 0x80)
|
||||||
|
byte |= 0x80;
|
||||||
|
if (d1 & 0x20)
|
||||||
|
byte |= 0x40;
|
||||||
|
if (d1 & 0x08)
|
||||||
|
byte |= 0x20;
|
||||||
|
if (d1 & 0x02)
|
||||||
|
byte |= 0x10;
|
||||||
|
if (d0 & 0x80)
|
||||||
|
byte |= 0x08;
|
||||||
|
if (d0 & 0x20)
|
||||||
|
byte |= 0x04;
|
||||||
|
if (d0 & 0x08)
|
||||||
|
byte |= 0x02;
|
||||||
|
if (d0 & 0x02)
|
||||||
|
byte |= 0x01;
|
||||||
|
|
||||||
|
if (d2 & 0x80)
|
||||||
|
bit |= 0x04;
|
||||||
|
if (d2 & 0x20)
|
||||||
|
bit |= 0x02;
|
||||||
|
if (d2 & 0x08)
|
||||||
|
bit |= 0x01;
|
||||||
|
|
||||||
|
data[byte] ^= (1 << bit);
|
||||||
|
|
||||||
|
return 1; /* Corrected the error */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((yaffs_CountBits(d0) +
|
||||||
|
yaffs_CountBits(d1) +
|
||||||
|
yaffs_CountBits(d2)) == 1) {
|
||||||
|
/* Reccoverable error in ecc */
|
||||||
|
|
||||||
|
read_ecc[0] = test_ecc[0];
|
||||||
|
read_ecc[1] = test_ecc[1];
|
||||||
|
read_ecc[2] = test_ecc[2];
|
||||||
|
|
||||||
|
return 1; /* Corrected the error */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unrecoverable error */
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
|
||||||
|
*/
|
||||||
|
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||||
|
yaffs_ECCOther * eccOther)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
unsigned char col_parity = 0;
|
||||||
|
unsigned line_parity = 0;
|
||||||
|
unsigned line_parity_prime = 0;
|
||||||
|
unsigned char b;
|
||||||
|
|
||||||
|
for (i = 0; i < nBytes; i++) {
|
||||||
|
b = column_parity_table[*data++];
|
||||||
|
col_parity ^= b;
|
||||||
|
|
||||||
|
if (b & 0x01) {
|
||||||
|
/* odd number of bits in the byte */
|
||||||
|
line_parity ^= i;
|
||||||
|
line_parity_prime ^= ~i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
eccOther->colParity = (col_parity >> 2) & 0x3f;
|
||||||
|
eccOther->lineParity = line_parity;
|
||||||
|
eccOther->lineParityPrime = line_parity_prime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||||
|
yaffs_ECCOther * read_ecc,
|
||||||
|
const yaffs_ECCOther * test_ecc)
|
||||||
|
{
|
||||||
|
unsigned char cDelta; /* column parity delta */
|
||||||
|
unsigned lDelta; /* line parity delta */
|
||||||
|
unsigned lDeltaPrime; /* line parity delta */
|
||||||
|
unsigned bit;
|
||||||
|
|
||||||
|
cDelta = read_ecc->colParity ^ test_ecc->colParity;
|
||||||
|
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
|
||||||
|
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
|
||||||
|
|
||||||
|
if ((cDelta | lDelta | lDeltaPrime) == 0)
|
||||||
|
return 0; /* no error */
|
||||||
|
|
||||||
|
if (lDelta == ~lDeltaPrime &&
|
||||||
|
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
|
||||||
|
{
|
||||||
|
/* Single bit (recoverable) error in data */
|
||||||
|
|
||||||
|
bit = 0;
|
||||||
|
|
||||||
|
if (cDelta & 0x20)
|
||||||
|
bit |= 0x04;
|
||||||
|
if (cDelta & 0x08)
|
||||||
|
bit |= 0x02;
|
||||||
|
if (cDelta & 0x02)
|
||||||
|
bit |= 0x01;
|
||||||
|
|
||||||
|
if(lDelta >= nBytes)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
data[lDelta] ^= (1 << bit);
|
||||||
|
|
||||||
|
return 1; /* corrected */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
|
||||||
|
yaffs_CountBits(cDelta)) == 1) {
|
||||||
|
/* Reccoverable error in ecc */
|
||||||
|
|
||||||
|
*read_ecc = *test_ecc;
|
||||||
|
return 1; /* corrected */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unrecoverable error */
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
44
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.h
Normal file
44
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code implements the ECC algorithm used in SmartMedia.
|
||||||
|
*
|
||||||
|
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
|
||||||
|
* The two unused bit are set to 1.
|
||||||
|
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
|
||||||
|
* blocks are used on a 512-byte NAND page.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_ECC_H__
|
||||||
|
#define __YAFFS_ECC_H__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char colParity;
|
||||||
|
unsigned lineParity;
|
||||||
|
unsigned lineParityPrime;
|
||||||
|
} yaffs_ECCOther;
|
||||||
|
|
||||||
|
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
|
||||||
|
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
|
||||||
|
const unsigned char *test_ecc);
|
||||||
|
|
||||||
|
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
|
||||||
|
yaffs_ECCOther * ecc);
|
||||||
|
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
|
||||||
|
yaffs_ECCOther * read_ecc,
|
||||||
|
const yaffs_ECCOther * test_ecc);
|
||||||
|
#endif
|
2299
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_fs.c
Normal file
2299
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_fs.c
Normal file
File diff suppressed because it is too large
Load diff
7469
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.c
Normal file
7469
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.c
Normal file
File diff suppressed because it is too large
Load diff
902
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.h
Normal file
902
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.h
Normal file
|
@ -0,0 +1,902 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_GUTS_H__
|
||||||
|
#define __YAFFS_GUTS_H__
|
||||||
|
|
||||||
|
#include "devextras.h"
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
#define YAFFS_OK 1
|
||||||
|
#define YAFFS_FAIL 0
|
||||||
|
|
||||||
|
/* Give us a Y=0x59,
|
||||||
|
* Give us an A=0x41,
|
||||||
|
* Give us an FF=0xFF
|
||||||
|
* Give us an S=0x53
|
||||||
|
* And what have we got...
|
||||||
|
*/
|
||||||
|
#define YAFFS_MAGIC 0x5941FF53
|
||||||
|
|
||||||
|
#define YAFFS_NTNODES_LEVEL0 16
|
||||||
|
#define YAFFS_TNODES_LEVEL0_BITS 4
|
||||||
|
#define YAFFS_TNODES_LEVEL0_MASK 0xf
|
||||||
|
|
||||||
|
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
|
||||||
|
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
|
||||||
|
#define YAFFS_TNODES_INTERNAL_MASK 0x7
|
||||||
|
#define YAFFS_TNODES_MAX_LEVEL 6
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_NO_YAFFS1
|
||||||
|
#define YAFFS_BYTES_PER_SPARE 16
|
||||||
|
#define YAFFS_BYTES_PER_CHUNK 512
|
||||||
|
#define YAFFS_CHUNK_SIZE_SHIFT 9
|
||||||
|
#define YAFFS_CHUNKS_PER_BLOCK 32
|
||||||
|
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
|
||||||
|
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
|
||||||
|
|
||||||
|
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
|
||||||
|
|
||||||
|
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
|
||||||
|
|
||||||
|
#define YAFFS_ALLOCATION_NOBJECTS 100
|
||||||
|
#define YAFFS_ALLOCATION_NTNODES 100
|
||||||
|
#define YAFFS_ALLOCATION_NLINKS 100
|
||||||
|
|
||||||
|
#define YAFFS_NOBJECT_BUCKETS 256
|
||||||
|
|
||||||
|
|
||||||
|
#define YAFFS_OBJECT_SPACE 0x40000
|
||||||
|
|
||||||
|
#define YAFFS_CHECKPOINT_VERSION 3
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_UNICODE
|
||||||
|
#define YAFFS_MAX_NAME_LENGTH 127
|
||||||
|
#define YAFFS_MAX_ALIAS_LENGTH 79
|
||||||
|
#else
|
||||||
|
#define YAFFS_MAX_NAME_LENGTH 255
|
||||||
|
#define YAFFS_MAX_ALIAS_LENGTH 159
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define YAFFS_SHORT_NAME_LENGTH 15
|
||||||
|
|
||||||
|
/* Some special object ids for pseudo objects */
|
||||||
|
#define YAFFS_OBJECTID_ROOT 1
|
||||||
|
#define YAFFS_OBJECTID_LOSTNFOUND 2
|
||||||
|
#define YAFFS_OBJECTID_UNLINKED 3
|
||||||
|
#define YAFFS_OBJECTID_DELETED 4
|
||||||
|
|
||||||
|
/* Sseudo object ids for checkpointing */
|
||||||
|
#define YAFFS_OBJECTID_SB_HEADER 0x10
|
||||||
|
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
|
||||||
|
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
|
||||||
|
|
||||||
|
/* */
|
||||||
|
|
||||||
|
#define YAFFS_MAX_SHORT_OP_CACHES 20
|
||||||
|
|
||||||
|
#define YAFFS_N_TEMP_BUFFERS 4
|
||||||
|
|
||||||
|
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||||
|
* Small-page devices have 32 pages per block; large-page devices have 64.
|
||||||
|
* Default to something in the order of 5 to 10 blocks worth of chunks.
|
||||||
|
*/
|
||||||
|
#define YAFFS_WR_ATTEMPTS (5*64)
|
||||||
|
|
||||||
|
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
|
||||||
|
* The range is limited slightly to help distinguish bad numbers from good.
|
||||||
|
* This also allows us to perhaps in the future use special numbers for
|
||||||
|
* special purposes.
|
||||||
|
* EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
|
||||||
|
* and is a larger number than the lifetime of a 2GB device.
|
||||||
|
*/
|
||||||
|
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
|
||||||
|
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
|
||||||
|
|
||||||
|
/* ChunkCache is used for short read/write operations.*/
|
||||||
|
typedef struct {
|
||||||
|
struct yaffs_ObjectStruct *object;
|
||||||
|
int chunkId;
|
||||||
|
int lastUse;
|
||||||
|
int dirty;
|
||||||
|
int nBytes; /* Only valid if the cache is dirty */
|
||||||
|
int locked; /* Can't push out or flush while locked. */
|
||||||
|
#ifdef CONFIG_YAFFS_YAFFS2
|
||||||
|
__u8 *data;
|
||||||
|
#else
|
||||||
|
__u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||||
|
#endif
|
||||||
|
} yaffs_ChunkCache;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Tags structures in RAM
|
||||||
|
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
|
||||||
|
* the structure size will get blown out.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_NO_YAFFS1
|
||||||
|
typedef struct {
|
||||||
|
unsigned chunkId:20;
|
||||||
|
unsigned serialNumber:2;
|
||||||
|
unsigned byteCount:10;
|
||||||
|
unsigned objectId:18;
|
||||||
|
unsigned ecc:12;
|
||||||
|
unsigned unusedStuff:2;
|
||||||
|
|
||||||
|
} yaffs_Tags;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
yaffs_Tags asTags;
|
||||||
|
__u8 asBytes[8];
|
||||||
|
} yaffs_TagsUnion;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Stuff used for extended tags in YAFFS2 */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
YAFFS_ECC_RESULT_UNKNOWN,
|
||||||
|
YAFFS_ECC_RESULT_NO_ERROR,
|
||||||
|
YAFFS_ECC_RESULT_FIXED,
|
||||||
|
YAFFS_ECC_RESULT_UNFIXED
|
||||||
|
} yaffs_ECCResult;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
YAFFS_OBJECT_TYPE_UNKNOWN,
|
||||||
|
YAFFS_OBJECT_TYPE_FILE,
|
||||||
|
YAFFS_OBJECT_TYPE_SYMLINK,
|
||||||
|
YAFFS_OBJECT_TYPE_DIRECTORY,
|
||||||
|
YAFFS_OBJECT_TYPE_HARDLINK,
|
||||||
|
YAFFS_OBJECT_TYPE_SPECIAL
|
||||||
|
} yaffs_ObjectType;
|
||||||
|
|
||||||
|
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
unsigned validMarker0;
|
||||||
|
unsigned chunkUsed; /* Status of the chunk: used or unused */
|
||||||
|
unsigned objectId; /* If 0 then this is not part of an object (unused) */
|
||||||
|
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
|
||||||
|
unsigned byteCount; /* Only valid for data chunks */
|
||||||
|
|
||||||
|
/* The following stuff only has meaning when we read */
|
||||||
|
yaffs_ECCResult eccResult;
|
||||||
|
unsigned blockBad;
|
||||||
|
|
||||||
|
/* YAFFS 1 stuff */
|
||||||
|
unsigned chunkDeleted; /* The chunk is marked deleted */
|
||||||
|
unsigned serialNumber; /* Yaffs1 2-bit serial number */
|
||||||
|
|
||||||
|
/* YAFFS2 stuff */
|
||||||
|
unsigned sequenceNumber; /* The sequence number of this block */
|
||||||
|
|
||||||
|
/* Extra info if this is an object header (YAFFS2 only) */
|
||||||
|
|
||||||
|
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
|
||||||
|
unsigned extraParentObjectId; /* The parent object */
|
||||||
|
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
|
||||||
|
unsigned extraShadows; /* Does this shadow another object? */
|
||||||
|
|
||||||
|
yaffs_ObjectType extraObjectType; /* What object type? */
|
||||||
|
|
||||||
|
unsigned extraFileLength; /* Length if it is a file */
|
||||||
|
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
|
||||||
|
|
||||||
|
unsigned validMarker1;
|
||||||
|
|
||||||
|
} yaffs_ExtendedTags;
|
||||||
|
|
||||||
|
/* Spare structure for YAFFS1 */
|
||||||
|
typedef struct {
|
||||||
|
__u8 tagByte0;
|
||||||
|
__u8 tagByte1;
|
||||||
|
__u8 tagByte2;
|
||||||
|
__u8 tagByte3;
|
||||||
|
__u8 pageStatus; /* set to 0 to delete the chunk */
|
||||||
|
__u8 blockStatus;
|
||||||
|
__u8 tagByte4;
|
||||||
|
__u8 tagByte5;
|
||||||
|
__u8 ecc1[3];
|
||||||
|
__u8 tagByte6;
|
||||||
|
__u8 tagByte7;
|
||||||
|
__u8 ecc2[3];
|
||||||
|
} yaffs_Spare;
|
||||||
|
|
||||||
|
/*Special structure for passing through to mtd */
|
||||||
|
struct yaffs_NANDSpare {
|
||||||
|
yaffs_Spare spare;
|
||||||
|
int eccres1;
|
||||||
|
int eccres2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Block data in RAM */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
YAFFS_BLOCK_STATE_UNKNOWN = 0,
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_SCANNING,
|
||||||
|
YAFFS_BLOCK_STATE_NEEDS_SCANNING,
|
||||||
|
/* The block might have something on it (ie it is allocating or full, perhaps empty)
|
||||||
|
* but it needs to be scanned to determine its true state.
|
||||||
|
* This state is only valid during yaffs_Scan.
|
||||||
|
* NB We tolerate empty because the pre-scanner might be incapable of deciding
|
||||||
|
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number
|
||||||
|
*/
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_EMPTY,
|
||||||
|
/* This block is empty */
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_ALLOCATING,
|
||||||
|
/* This block is partially allocated.
|
||||||
|
* At least one page holds valid data.
|
||||||
|
* This is the one currently being used for page
|
||||||
|
* allocation. Should never be more than one of these
|
||||||
|
*/
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_FULL,
|
||||||
|
/* All the pages in this block have been allocated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_DIRTY,
|
||||||
|
/* All pages have been allocated and deleted.
|
||||||
|
* Erase me, reuse me.
|
||||||
|
*/
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_CHECKPOINT,
|
||||||
|
/* This block is assigned to holding checkpoint data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_COLLECTING,
|
||||||
|
/* This block is being garbage collected */
|
||||||
|
|
||||||
|
YAFFS_BLOCK_STATE_DEAD
|
||||||
|
/* This block has failed and is not in use */
|
||||||
|
} yaffs_BlockState;
|
||||||
|
|
||||||
|
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
int softDeletions:10; /* number of soft deleted pages */
|
||||||
|
int pagesInUse:10; /* number of pages in use */
|
||||||
|
yaffs_BlockState blockState:4; /* One of the above block states */
|
||||||
|
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
|
||||||
|
/* and retire the block. */
|
||||||
|
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
|
||||||
|
__u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block.
|
||||||
|
It should be prioritised for GC */
|
||||||
|
__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_YAFFS2
|
||||||
|
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
|
||||||
|
__u32 sequenceNumber; /* block sequence number for yaffs2 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} yaffs_BlockInfo;
|
||||||
|
|
||||||
|
/* -------------------------- Object structure -------------------------------*/
|
||||||
|
/* This is the object structure as stored on NAND */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
yaffs_ObjectType type;
|
||||||
|
|
||||||
|
/* Apply to everything */
|
||||||
|
int parentObjectId;
|
||||||
|
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
|
||||||
|
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
|
/* Thes following apply to directories, files, symlinks - not hard links */
|
||||||
|
__u32 yst_mode; /* protection */
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_WINCE
|
||||||
|
__u32 notForWinCE[5];
|
||||||
|
#else
|
||||||
|
__u32 yst_uid;
|
||||||
|
__u32 yst_gid;
|
||||||
|
__u32 yst_atime;
|
||||||
|
__u32 yst_mtime;
|
||||||
|
__u32 yst_ctime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* File size applies to files only */
|
||||||
|
int fileSize;
|
||||||
|
|
||||||
|
/* Equivalent object id applies to hard links only. */
|
||||||
|
int equivalentObjectId;
|
||||||
|
|
||||||
|
/* Alias is for symlinks only. */
|
||||||
|
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
|
||||||
|
|
||||||
|
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_WINCE
|
||||||
|
__u32 win_ctime[2];
|
||||||
|
__u32 win_atime[2];
|
||||||
|
__u32 win_mtime[2];
|
||||||
|
__u32 roomToGrow[4];
|
||||||
|
#else
|
||||||
|
__u32 roomToGrow[10];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int shadowsObject; /* This object header shadows the specified object if > 0 */
|
||||||
|
|
||||||
|
/* isShrink applies to object headers written when we shrink the file (ie resize) */
|
||||||
|
__u32 isShrink;
|
||||||
|
|
||||||
|
} yaffs_ObjectHeader;
|
||||||
|
|
||||||
|
/*--------------------------- Tnode -------------------------- */
|
||||||
|
|
||||||
|
union yaffs_Tnode_union {
|
||||||
|
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
|
||||||
|
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
|
||||||
|
#else
|
||||||
|
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
|
||||||
|
#endif
|
||||||
|
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union yaffs_Tnode_union yaffs_Tnode;
|
||||||
|
|
||||||
|
struct yaffs_TnodeList_struct {
|
||||||
|
struct yaffs_TnodeList_struct *next;
|
||||||
|
yaffs_Tnode *tnodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
|
||||||
|
|
||||||
|
/*------------------------ Object -----------------------------*/
|
||||||
|
/* An object can be one of:
|
||||||
|
* - a directory (no data, has children links
|
||||||
|
* - a regular file (data.... not prunes :->).
|
||||||
|
* - a symlink [symbolic link] (the alias).
|
||||||
|
* - a hard link
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__u32 fileSize;
|
||||||
|
__u32 scannedFileSize;
|
||||||
|
__u32 shrinkSize;
|
||||||
|
int topLevel;
|
||||||
|
yaffs_Tnode *top;
|
||||||
|
} yaffs_FileStructure;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct list_head children; /* list of child links */
|
||||||
|
} yaffs_DirectoryStructure;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
YCHAR *alias;
|
||||||
|
} yaffs_SymLinkStructure;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct yaffs_ObjectStruct *equivalentObject;
|
||||||
|
__u32 equivalentObjectId;
|
||||||
|
} yaffs_HardLinkStructure;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
yaffs_FileStructure fileVariant;
|
||||||
|
yaffs_DirectoryStructure directoryVariant;
|
||||||
|
yaffs_SymLinkStructure symLinkVariant;
|
||||||
|
yaffs_HardLinkStructure hardLinkVariant;
|
||||||
|
} yaffs_ObjectVariant;
|
||||||
|
|
||||||
|
struct yaffs_ObjectStruct {
|
||||||
|
__u8 deleted:1; /* This should only apply to unlinked files. */
|
||||||
|
__u8 softDeleted:1; /* it has also been soft deleted */
|
||||||
|
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
|
||||||
|
__u8 fake:1; /* A fake object has no presence on NAND. */
|
||||||
|
__u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
|
||||||
|
__u8 unlinkAllowed:1;
|
||||||
|
__u8 dirty:1; /* the object needs to be written to flash */
|
||||||
|
__u8 valid:1; /* When the file system is being loaded up, this
|
||||||
|
* object might be created before the data
|
||||||
|
* is available (ie. file data records appear before the header).
|
||||||
|
*/
|
||||||
|
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
|
||||||
|
|
||||||
|
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
|
||||||
|
* still in the inode cache. Free of object is defered.
|
||||||
|
* until the inode is released.
|
||||||
|
*/
|
||||||
|
|
||||||
|
__u8 serial; /* serial number of chunk in NAND. Cached here */
|
||||||
|
__u16 sum; /* sum of the name to speed searching */
|
||||||
|
|
||||||
|
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
|
||||||
|
|
||||||
|
struct list_head hashLink; /* list of objects in this hash bucket */
|
||||||
|
|
||||||
|
struct list_head hardLinks; /* all the equivalent hard linked objects */
|
||||||
|
|
||||||
|
/* directory structure stuff */
|
||||||
|
/* also used for linking up the free list */
|
||||||
|
struct yaffs_ObjectStruct *parent;
|
||||||
|
struct list_head siblings;
|
||||||
|
|
||||||
|
/* Where's my object header in NAND? */
|
||||||
|
int chunkId;
|
||||||
|
|
||||||
|
int nDataChunks; /* Number of data chunks attached to the file. */
|
||||||
|
|
||||||
|
__u32 objectId; /* the object id value */
|
||||||
|
|
||||||
|
__u32 yst_mode;
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
||||||
|
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __KERNEL__
|
||||||
|
__u32 inUse;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_WINCE
|
||||||
|
__u32 win_ctime[2];
|
||||||
|
__u32 win_mtime[2];
|
||||||
|
__u32 win_atime[2];
|
||||||
|
#else
|
||||||
|
__u32 yst_uid;
|
||||||
|
__u32 yst_gid;
|
||||||
|
__u32 yst_atime;
|
||||||
|
__u32 yst_mtime;
|
||||||
|
__u32 yst_ctime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__u32 yst_rdev;
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
struct inode *myInode;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
yaffs_ObjectType variantType;
|
||||||
|
|
||||||
|
yaffs_ObjectVariant variant;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct yaffs_ObjectStruct yaffs_Object;
|
||||||
|
|
||||||
|
struct yaffs_ObjectList_struct {
|
||||||
|
yaffs_Object *objects;
|
||||||
|
struct yaffs_ObjectList_struct *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct list_head list;
|
||||||
|
int count;
|
||||||
|
} yaffs_ObjectBucket;
|
||||||
|
|
||||||
|
|
||||||
|
/* yaffs_CheckpointObject holds the definition of an object as dumped
|
||||||
|
* by checkpointing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int structType;
|
||||||
|
__u32 objectId;
|
||||||
|
__u32 parentId;
|
||||||
|
int chunkId;
|
||||||
|
|
||||||
|
yaffs_ObjectType variantType:3;
|
||||||
|
__u8 deleted:1;
|
||||||
|
__u8 softDeleted:1;
|
||||||
|
__u8 unlinked:1;
|
||||||
|
__u8 fake:1;
|
||||||
|
__u8 renameAllowed:1;
|
||||||
|
__u8 unlinkAllowed:1;
|
||||||
|
__u8 serial;
|
||||||
|
|
||||||
|
int nDataChunks;
|
||||||
|
__u32 fileSizeOrEquivalentObjectId;
|
||||||
|
|
||||||
|
}yaffs_CheckpointObject;
|
||||||
|
|
||||||
|
/*--------------------- Temporary buffers ----------------
|
||||||
|
*
|
||||||
|
* These are chunk-sized working buffers. Each device has a few
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
__u8 *buffer;
|
||||||
|
int line; /* track from whence this buffer was allocated */
|
||||||
|
int maxLine;
|
||||||
|
} yaffs_TempBuffer;
|
||||||
|
|
||||||
|
/*----------------- Device ---------------------------------*/
|
||||||
|
|
||||||
|
struct yaffs_DeviceStruct {
|
||||||
|
struct list_head devList;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/* Entry parameters set up way early. Yaffs sets up the rest.*/
|
||||||
|
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
|
||||||
|
int nChunksPerBlock; /* does not need to be a power of 2 */
|
||||||
|
int nBytesPerSpare; /* spare area size */
|
||||||
|
int startBlock; /* Start block we're allowed to use */
|
||||||
|
int endBlock; /* End block we're allowed to use */
|
||||||
|
int nReservedBlocks; /* We want this tuneable so that we can reduce */
|
||||||
|
/* reserved blocks on NOR and RAM. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Stuff used by the shared space checkpointing mechanism */
|
||||||
|
/* If this value is zero, then this mechanism is disabled */
|
||||||
|
|
||||||
|
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
|
||||||
|
* the number of short op caches (don't use too many)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
|
||||||
|
|
||||||
|
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
|
||||||
|
|
||||||
|
void *genericDevice; /* Pointer to device context
|
||||||
|
* On an mtd this holds the mtd pointer.
|
||||||
|
*/
|
||||||
|
void *superBlock;
|
||||||
|
|
||||||
|
/* NAND access functions (Must be set before calling YAFFS)*/
|
||||||
|
|
||||||
|
int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev,
|
||||||
|
int chunkInNAND, const __u8 * data,
|
||||||
|
const yaffs_Spare * spare);
|
||||||
|
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
|
||||||
|
int chunkInNAND, __u8 * data,
|
||||||
|
yaffs_Spare * spare);
|
||||||
|
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
|
||||||
|
int blockInNAND);
|
||||||
|
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_YAFFS2
|
||||||
|
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
|
||||||
|
int chunkInNAND, const __u8 * data,
|
||||||
|
const yaffs_ExtendedTags * tags);
|
||||||
|
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
|
||||||
|
int chunkInNAND, __u8 * data,
|
||||||
|
yaffs_ExtendedTags * tags);
|
||||||
|
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
|
||||||
|
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
|
||||||
|
yaffs_BlockState * state, int *sequenceNumber);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int isYaffs2;
|
||||||
|
|
||||||
|
/* The removeObjectCallback function must be supplied by OS flavours that
|
||||||
|
* need it. The Linux kernel does not use this, but yaffs direct does use
|
||||||
|
* it to implement the faster readdir
|
||||||
|
*/
|
||||||
|
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
|
||||||
|
|
||||||
|
/* Callback to mark the superblock dirsty */
|
||||||
|
void (*markSuperBlockDirty)(void * superblock);
|
||||||
|
|
||||||
|
int wideTnodesDisabled; /* Set to disable wide tnodes */
|
||||||
|
|
||||||
|
|
||||||
|
/* End of stuff that must be set before initialisation. */
|
||||||
|
|
||||||
|
/* Checkpoint control. Can be set before or after initialisation */
|
||||||
|
__u8 skipCheckpointRead;
|
||||||
|
__u8 skipCheckpointWrite;
|
||||||
|
|
||||||
|
/* Runtime parameters. Set up by YAFFS. */
|
||||||
|
|
||||||
|
__u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
|
||||||
|
__u16 chunkGroupSize; /* == 2^^chunkGroupBits */
|
||||||
|
|
||||||
|
/* Stuff to support wide tnodes */
|
||||||
|
__u32 tnodeWidth;
|
||||||
|
__u32 tnodeMask;
|
||||||
|
|
||||||
|
/* Stuff to support various file offses to chunk/offset translations */
|
||||||
|
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
|
||||||
|
__u32 crumbMask;
|
||||||
|
__u32 crumbShift;
|
||||||
|
__u32 crumbsPerChunk;
|
||||||
|
|
||||||
|
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
|
||||||
|
__u32 chunkShift;
|
||||||
|
__u32 chunkMask;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
struct semaphore sem; /* Semaphore for waiting on erasure.*/
|
||||||
|
struct semaphore grossLock; /* Gross locking semaphore */
|
||||||
|
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
|
||||||
|
* at compile time so we have to allocate it.
|
||||||
|
*/
|
||||||
|
void (*putSuperFunc) (struct super_block * sb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int isMounted;
|
||||||
|
|
||||||
|
int isCheckpointed;
|
||||||
|
|
||||||
|
|
||||||
|
/* Stuff to support block offsetting to support start block zero */
|
||||||
|
int internalStartBlock;
|
||||||
|
int internalEndBlock;
|
||||||
|
int blockOffset;
|
||||||
|
int chunkOffset;
|
||||||
|
|
||||||
|
|
||||||
|
/* Runtime checkpointing stuff */
|
||||||
|
int checkpointPageSequence; /* running sequence number of checkpoint pages */
|
||||||
|
int checkpointByteCount;
|
||||||
|
int checkpointByteOffset;
|
||||||
|
__u8 *checkpointBuffer;
|
||||||
|
int checkpointOpenForWrite;
|
||||||
|
int blocksInCheckpoint;
|
||||||
|
int checkpointCurrentChunk;
|
||||||
|
int checkpointCurrentBlock;
|
||||||
|
int checkpointNextBlock;
|
||||||
|
int *checkpointBlockList;
|
||||||
|
int checkpointMaxBlocks;
|
||||||
|
__u32 checkpointSum;
|
||||||
|
__u32 checkpointXor;
|
||||||
|
|
||||||
|
/* Block Info */
|
||||||
|
yaffs_BlockInfo *blockInfo;
|
||||||
|
__u8 *chunkBits; /* bitmap of chunks in use */
|
||||||
|
unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
|
||||||
|
unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
|
||||||
|
int chunkBitmapStride; /* Number of bytes of chunkBits per block.
|
||||||
|
* Must be consistent with nChunksPerBlock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int nErasedBlocks;
|
||||||
|
int allocationBlock; /* Current block being allocated off */
|
||||||
|
__u32 allocationPage;
|
||||||
|
int allocationBlockFinder; /* Used to search for next allocation block */
|
||||||
|
|
||||||
|
/* Runtime state */
|
||||||
|
int nTnodesCreated;
|
||||||
|
yaffs_Tnode *freeTnodes;
|
||||||
|
int nFreeTnodes;
|
||||||
|
yaffs_TnodeList *allocatedTnodeList;
|
||||||
|
|
||||||
|
int isDoingGC;
|
||||||
|
|
||||||
|
int nObjectsCreated;
|
||||||
|
yaffs_Object *freeObjects;
|
||||||
|
int nFreeObjects;
|
||||||
|
|
||||||
|
yaffs_ObjectList *allocatedObjectList;
|
||||||
|
|
||||||
|
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
|
||||||
|
|
||||||
|
int nFreeChunks;
|
||||||
|
|
||||||
|
int currentDirtyChecker; /* Used to find current dirtiest block */
|
||||||
|
|
||||||
|
__u32 *gcCleanupList; /* objects to delete at the end of a GC. */
|
||||||
|
int nonAggressiveSkip; /* GC state/mode */
|
||||||
|
|
||||||
|
/* Statistcs */
|
||||||
|
int nPageWrites;
|
||||||
|
int nPageReads;
|
||||||
|
int nBlockErasures;
|
||||||
|
int nErasureFailures;
|
||||||
|
int nGCCopies;
|
||||||
|
int garbageCollections;
|
||||||
|
int passiveGarbageCollections;
|
||||||
|
int nRetriedWrites;
|
||||||
|
int nRetiredBlocks;
|
||||||
|
int eccFixed;
|
||||||
|
int eccUnfixed;
|
||||||
|
int tagsEccFixed;
|
||||||
|
int tagsEccUnfixed;
|
||||||
|
int nDeletions;
|
||||||
|
int nUnmarkedDeletions;
|
||||||
|
|
||||||
|
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
|
||||||
|
|
||||||
|
/* Special directories */
|
||||||
|
yaffs_Object *rootDir;
|
||||||
|
yaffs_Object *lostNFoundDir;
|
||||||
|
|
||||||
|
/* Buffer areas for storing data to recover from write failures TODO
|
||||||
|
* __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
|
||||||
|
* yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
|
||||||
|
*/
|
||||||
|
|
||||||
|
int bufferedBlock; /* Which block is buffered here? */
|
||||||
|
int doingBufferedBlockRewrite;
|
||||||
|
|
||||||
|
yaffs_ChunkCache *srCache;
|
||||||
|
int srLastUse;
|
||||||
|
|
||||||
|
int cacheHits;
|
||||||
|
|
||||||
|
/* Stuff for background deletion and unlinked files.*/
|
||||||
|
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
|
||||||
|
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
|
||||||
|
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
|
||||||
|
int nDeletedFiles; /* Count of files awaiting deletion;*/
|
||||||
|
int nUnlinkedFiles; /* Count of unlinked files. */
|
||||||
|
int nBackgroundDeletions; /* Count of background deletions. */
|
||||||
|
|
||||||
|
|
||||||
|
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
|
||||||
|
int maxTemp;
|
||||||
|
int unmanagedTempAllocations;
|
||||||
|
int unmanagedTempDeallocations;
|
||||||
|
|
||||||
|
/* yaffs2 runtime stuff */
|
||||||
|
unsigned sequenceNumber; /* Sequence number of currently allocating block */
|
||||||
|
unsigned oldestDirtySequence;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct yaffs_DeviceStruct yaffs_Device;
|
||||||
|
|
||||||
|
/* The static layout of bllock usage etc is stored in the super block header */
|
||||||
|
typedef struct {
|
||||||
|
int StructType;
|
||||||
|
int version;
|
||||||
|
int checkpointStartBlock;
|
||||||
|
int checkpointEndBlock;
|
||||||
|
int startBlock;
|
||||||
|
int endBlock;
|
||||||
|
int rfu[100];
|
||||||
|
} yaffs_SuperBlockHeader;
|
||||||
|
|
||||||
|
/* The CheckpointDevice structure holds the device information that changes at runtime and
|
||||||
|
* must be preserved over unmount/mount cycles.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int structType;
|
||||||
|
int nErasedBlocks;
|
||||||
|
int allocationBlock; /* Current block being allocated off */
|
||||||
|
__u32 allocationPage;
|
||||||
|
int nFreeChunks;
|
||||||
|
|
||||||
|
int nDeletedFiles; /* Count of files awaiting deletion;*/
|
||||||
|
int nUnlinkedFiles; /* Count of unlinked files. */
|
||||||
|
int nBackgroundDeletions; /* Count of background deletions. */
|
||||||
|
|
||||||
|
/* yaffs2 runtime stuff */
|
||||||
|
unsigned sequenceNumber; /* Sequence number of currently allocating block */
|
||||||
|
unsigned oldestDirtySequence;
|
||||||
|
|
||||||
|
} yaffs_CheckpointDevice;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int structType;
|
||||||
|
__u32 magic;
|
||||||
|
__u32 version;
|
||||||
|
__u32 head;
|
||||||
|
} yaffs_CheckpointValidity;
|
||||||
|
|
||||||
|
/* Function to manipulate block info */
|
||||||
|
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
|
||||||
|
{
|
||||||
|
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
|
||||||
|
blk));
|
||||||
|
YBUG();
|
||||||
|
}
|
||||||
|
return &dev->blockInfo[blk - dev->internalStartBlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------- YAFFS Functions -----------------------*/
|
||||||
|
|
||||||
|
int yaffs_GutsInitialise(yaffs_Device * dev);
|
||||||
|
void yaffs_Deinitialise(yaffs_Device * dev);
|
||||||
|
|
||||||
|
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
|
||||||
|
|
||||||
|
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
|
||||||
|
yaffs_Object * newDir, const YCHAR * newName);
|
||||||
|
|
||||||
|
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
|
||||||
|
int yaffs_DeleteFile(yaffs_Object * obj);
|
||||||
|
|
||||||
|
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
|
||||||
|
int yaffs_GetObjectFileLength(yaffs_Object * obj);
|
||||||
|
int yaffs_GetObjectInode(yaffs_Object * obj);
|
||||||
|
unsigned yaffs_GetObjectType(yaffs_Object * obj);
|
||||||
|
int yaffs_GetObjectLinkCount(yaffs_Object * obj);
|
||||||
|
|
||||||
|
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
|
||||||
|
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
|
||||||
|
|
||||||
|
/* File operations */
|
||||||
|
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
|
||||||
|
int nBytes);
|
||||||
|
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
|
||||||
|
int nBytes, int writeThrough);
|
||||||
|
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
|
||||||
|
|
||||||
|
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
|
||||||
|
__u32 mode, __u32 uid, __u32 gid);
|
||||||
|
int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
|
||||||
|
|
||||||
|
/* Flushing and checkpointing */
|
||||||
|
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
|
||||||
|
|
||||||
|
int yaffs_CheckpointSave(yaffs_Device *dev);
|
||||||
|
int yaffs_CheckpointRestore(yaffs_Device *dev);
|
||||||
|
|
||||||
|
/* Directory operations */
|
||||||
|
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
|
||||||
|
__u32 mode, __u32 uid, __u32 gid);
|
||||||
|
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
|
||||||
|
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
|
||||||
|
int (*fn) (yaffs_Object *));
|
||||||
|
|
||||||
|
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
|
||||||
|
|
||||||
|
/* Link operations */
|
||||||
|
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
|
||||||
|
yaffs_Object * equivalentObject);
|
||||||
|
|
||||||
|
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
|
||||||
|
|
||||||
|
/* Symlink operations */
|
||||||
|
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
|
||||||
|
__u32 mode, __u32 uid, __u32 gid,
|
||||||
|
const YCHAR * alias);
|
||||||
|
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
|
||||||
|
|
||||||
|
/* Special inodes (fifos, sockets and devices) */
|
||||||
|
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
|
||||||
|
__u32 mode, __u32 uid, __u32 gid, __u32 rdev);
|
||||||
|
|
||||||
|
/* Special directories */
|
||||||
|
yaffs_Object *yaffs_Root(yaffs_Device * dev);
|
||||||
|
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
|
||||||
|
|
||||||
|
#ifdef CONFIG_YAFFS_WINCE
|
||||||
|
/* CONFIG_YAFFS_WINCE special stuff */
|
||||||
|
void yfsd_WinFileTimeNow(__u32 target[2]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
void yaffs_HandleDeferedFree(yaffs_Object * obj);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Debug dump */
|
||||||
|
int yaffs_DumpObject(yaffs_Object * obj);
|
||||||
|
|
||||||
|
void yaffs_GutsTest(yaffs_Device * dev);
|
||||||
|
|
||||||
|
/* A few useful functions */
|
||||||
|
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
|
||||||
|
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
|
||||||
|
int yaffs_CheckFF(__u8 * buffer, int nBytes);
|
||||||
|
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
|
||||||
|
|
||||||
|
#endif
|
241
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.c
Normal file
241
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.c
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *yaffs_mtdif_c_version =
|
||||||
|
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "yaffs_mtdif.h"
|
||||||
|
|
||||||
|
#include "linux/mtd/mtd.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/time.h"
|
||||||
|
#include "linux/mtd/nand.h"
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
|
||||||
|
static struct nand_oobinfo yaffs_oobinfo = {
|
||||||
|
.useecc = 1,
|
||||||
|
.eccbytes = 6,
|
||||||
|
.eccpos = {8, 9, 10, 13, 14, 15}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nand_oobinfo yaffs_noeccinfo = {
|
||||||
|
.useecc = 0,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
|
||||||
|
{
|
||||||
|
oob[0] = spare->tagByte0;
|
||||||
|
oob[1] = spare->tagByte1;
|
||||||
|
oob[2] = spare->tagByte2;
|
||||||
|
oob[3] = spare->tagByte3;
|
||||||
|
oob[4] = spare->tagByte4;
|
||||||
|
oob[5] = spare->tagByte5 & 0x3f;
|
||||||
|
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
|
||||||
|
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
|
||||||
|
oob[6] = spare->tagByte6;
|
||||||
|
oob[7] = spare->tagByte7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
|
||||||
|
{
|
||||||
|
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
|
||||||
|
spare->tagByte0 = oob[0];
|
||||||
|
spare->tagByte1 = oob[1];
|
||||||
|
spare->tagByte2 = oob[2];
|
||||||
|
spare->tagByte3 = oob[3];
|
||||||
|
spare->tagByte4 = oob[4];
|
||||||
|
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
|
||||||
|
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
|
||||||
|
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
|
||||||
|
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
|
||||||
|
spare->tagByte6 = oob[6];
|
||||||
|
spare->tagByte7 = oob[7];
|
||||||
|
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
|
||||||
|
|
||||||
|
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data, const yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
#endif
|
||||||
|
size_t dummy;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
__u8 spareAsBytes[8]; /* OOB */
|
||||||
|
|
||||||
|
if (data && !spare)
|
||||||
|
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data);
|
||||||
|
else if (spare) {
|
||||||
|
if (dev->useNANDECC) {
|
||||||
|
translate_spare2oob(spare, spareAsBytes);
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.ooblen = 8; /* temp hack */
|
||||||
|
} else {
|
||||||
|
ops.mode = MTD_OOB_RAW;
|
||||||
|
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||||
|
}
|
||||||
|
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
|
||||||
|
ops.datbuf = (u8 *)data;
|
||||||
|
ops.ooboffs = 0;
|
||||||
|
ops.oobbuf = spareAsBytes;
|
||||||
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
__u8 *spareAsBytes = (__u8 *) spare;
|
||||||
|
|
||||||
|
if (data && spare) {
|
||||||
|
if (dev->useNANDECC)
|
||||||
|
retval =
|
||||||
|
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, spareAsBytes,
|
||||||
|
&yaffs_oobinfo);
|
||||||
|
else
|
||||||
|
retval =
|
||||||
|
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, spareAsBytes,
|
||||||
|
&yaffs_noeccinfo);
|
||||||
|
} else {
|
||||||
|
if (data)
|
||||||
|
retval =
|
||||||
|
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||||
|
data);
|
||||||
|
if (spare)
|
||||||
|
retval =
|
||||||
|
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
|
||||||
|
&dummy, spareAsBytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||||
|
yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
#endif
|
||||||
|
size_t dummy;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
__u8 spareAsBytes[8]; /* OOB */
|
||||||
|
|
||||||
|
if (data && !spare)
|
||||||
|
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data);
|
||||||
|
else if (spare) {
|
||||||
|
if (dev->useNANDECC) {
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.ooblen = 8; /* temp hack */
|
||||||
|
} else {
|
||||||
|
ops.mode = MTD_OOB_RAW;
|
||||||
|
ops.ooblen = YAFFS_BYTES_PER_SPARE;
|
||||||
|
}
|
||||||
|
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
|
||||||
|
ops.datbuf = data;
|
||||||
|
ops.ooboffs = 0;
|
||||||
|
ops.oobbuf = spareAsBytes;
|
||||||
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
|
if (dev->useNANDECC)
|
||||||
|
translate_oob2spare(spare, spareAsBytes);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
__u8 *spareAsBytes = (__u8 *) spare;
|
||||||
|
|
||||||
|
if (data && spare) {
|
||||||
|
if (dev->useNANDECC) {
|
||||||
|
/* Careful, this call adds 2 ints */
|
||||||
|
/* to the end of the spare data. Calling function */
|
||||||
|
/* should allocate enough memory for spare, */
|
||||||
|
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
|
||||||
|
retval =
|
||||||
|
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, spareAsBytes,
|
||||||
|
&yaffs_oobinfo);
|
||||||
|
} else {
|
||||||
|
retval =
|
||||||
|
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, spareAsBytes,
|
||||||
|
&yaffs_noeccinfo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data)
|
||||||
|
retval =
|
||||||
|
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||||
|
data);
|
||||||
|
if (spare)
|
||||||
|
retval =
|
||||||
|
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
|
||||||
|
&dummy, spareAsBytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
__u32 addr =
|
||||||
|
((loff_t) blockNumber) * dev->nDataBytesPerChunk
|
||||||
|
* dev->nChunksPerBlock;
|
||||||
|
struct erase_info ei;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
ei.mtd = mtd;
|
||||||
|
ei.addr = addr;
|
||||||
|
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
|
||||||
|
ei.time = 1000;
|
||||||
|
ei.retries = 2;
|
||||||
|
ei.callback = NULL;
|
||||||
|
ei.priv = (u_long) dev;
|
||||||
|
|
||||||
|
/* Todo finish off the ei if required */
|
||||||
|
|
||||||
|
sema_init(&dev->sem, 0);
|
||||||
|
|
||||||
|
retval = mtd->erase(mtd, &ei);
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd_InitialiseNAND(yaffs_Device * dev)
|
||||||
|
{
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_MTDIF_H__
|
||||||
|
#define __YAFFS_MTDIF_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data, const yaffs_Spare * spare);
|
||||||
|
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
|
||||||
|
yaffs_Spare * spare);
|
||||||
|
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
|
||||||
|
int nandmtd_InitialiseNAND(yaffs_Device * dev);
|
||||||
|
#endif
|
|
@ -0,0 +1,434 @@
|
||||||
|
From ian@brightstareng.com Fri May 18 15:06:49 2007
|
||||||
|
From ian@brightstareng.com Fri May 18 15:08:21 2007
|
||||||
|
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
|
||||||
|
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
|
||||||
|
(envelope-from <ian@brightstareng.com>)
|
||||||
|
id 1Hp380-00011e-T6
|
||||||
|
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
|
||||||
|
Received: from localhost (localhost.localdomain [127.0.0.1])
|
||||||
|
by zebra.brightstareng.com (Postfix) with ESMTP
|
||||||
|
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
|
||||||
|
Received: from zebra.brightstareng.com ([127.0.0.1])
|
||||||
|
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
|
||||||
|
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
|
||||||
|
Received: from pippin (unknown [192.168.1.25])
|
||||||
|
by zebra.brightstareng.com (Postfix) with ESMTP
|
||||||
|
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
|
||||||
|
From: Ian McDonnell <ian@brightstareng.com>
|
||||||
|
To: David Goodenough <david.goodenough@linkchoose.co.uk>
|
||||||
|
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
|
||||||
|
Date: Fri, 18 May 2007 10:06:49 -0400
|
||||||
|
User-Agent: KMail/1.9.1
|
||||||
|
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
|
||||||
|
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
|
||||||
|
Cc: Andrea Conti <alyf@alyf.net>,
|
||||||
|
Charles Manning <manningc2@actrix.gen.nz>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: Multipart/Mixed;
|
||||||
|
boundary="Boundary-00=_5LbTGmt62YoutxM"
|
||||||
|
Message-Id: <200705181006.49860.ian@brightstareng.com>
|
||||||
|
X-Virus-Scanned: by amavisd-new at brightstareng.com
|
||||||
|
Status: R
|
||||||
|
X-Status: NT
|
||||||
|
X-KMail-EncryptionState:
|
||||||
|
X-KMail-SignatureState:
|
||||||
|
X-KMail-MDN-Sent:
|
||||||
|
|
||||||
|
--Boundary-00=_5LbTGmt62YoutxM
|
||||||
|
Content-Type: text/plain;
|
||||||
|
charset="iso-8859-15"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
Content-Disposition: inline
|
||||||
|
|
||||||
|
David, Andrea,
|
||||||
|
|
||||||
|
On Friday 18 May 2007 08:34, you wrote:
|
||||||
|
> Yea team. With this fix in place (I put it in the wrong place
|
||||||
|
> at first) I can now mount and ls the Yaffs partition without
|
||||||
|
> an error messages!
|
||||||
|
|
||||||
|
Good news!
|
||||||
|
|
||||||
|
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
|
||||||
|
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
|
||||||
|
See the LINUX_VERSION_CODE conditional in
|
||||||
|
nandmtd1_ReadChunkWithTagsFromNAND.
|
||||||
|
|
||||||
|
-imcd
|
||||||
|
|
||||||
|
--Boundary-00=_5LbTGmt62YoutxM
|
||||||
|
Content-Type: text/x-csrc;
|
||||||
|
charset="iso-8859-15";
|
||||||
|
name="yaffs_mtdif1.c"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
Content-Disposition: attachment;
|
||||||
|
filename="yaffs_mtdif1.c"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||||
|
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module provides the interface between yaffs_nand.c and the
|
||||||
|
* MTD API. This version is used when the MTD interface supports the
|
||||||
|
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
|
||||||
|
* and we have small-page NAND device.
|
||||||
|
*
|
||||||
|
* These functions are invoked via function pointers in yaffs_nand.c.
|
||||||
|
* This replaces functionality provided by functions in yaffs_mtdif.c
|
||||||
|
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
|
||||||
|
* called in yaffs_mtdif.c when the function pointers are NULL.
|
||||||
|
* We assume the MTD layer is performing ECC (useNANDECC is true).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
#include "yaffs_packedtags1.h"
|
||||||
|
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
|
||||||
|
|
||||||
|
#include "linux/kernel.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/mtd/mtd.h"
|
||||||
|
|
||||||
|
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
|
||||||
|
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
# define YTAG1_SIZE 8
|
||||||
|
#else
|
||||||
|
# define YTAG1_SIZE 9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Use the following nand_ecclayout with MTD when using
|
||||||
|
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
|
||||||
|
* If you have existing Yaffs images and the byte order differs from this,
|
||||||
|
* adjust 'oobfree' to match your existing Yaffs data.
|
||||||
|
*
|
||||||
|
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
|
||||||
|
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
|
||||||
|
* the 9th byte.
|
||||||
|
*
|
||||||
|
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
|
||||||
|
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
|
||||||
|
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
|
||||||
|
* byte and B is the small-page bad-block indicator byte.
|
||||||
|
*/
|
||||||
|
static struct nand_ecclayout nand_oob_16 = {
|
||||||
|
.eccbytes = 6,
|
||||||
|
.eccpos = { 8, 9, 10, 13, 14, 15 },
|
||||||
|
.oobavail = 9,
|
||||||
|
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write a chunk (page) of data to NAND.
|
||||||
|
*
|
||||||
|
* Caller always provides ExtendedTags data which are converted to a more
|
||||||
|
* compact (packed) form for storage in NAND. A mini-ECC runs over the
|
||||||
|
* contents of the tags meta-data; used to valid the tags when read.
|
||||||
|
*
|
||||||
|
* - Pack ExtendedTags to PackedTags1 form
|
||||||
|
* - Compute mini-ECC for PackedTags1
|
||||||
|
* - Write data and packed tags to NAND.
|
||||||
|
*
|
||||||
|
* Note: Due to the use of the PackedTags1 meta-data which does not include
|
||||||
|
* a full sequence number (as found in the larger PackedTags2 form) it is
|
||||||
|
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
|
||||||
|
* discarded and dirty. This is not ideal: newer NAND parts are supposed
|
||||||
|
* to be written just once. When Yaffs performs this operation, this
|
||||||
|
* function is called with a NULL data pointer -- calling MTD write_oob
|
||||||
|
* without data is valid usage (2.6.17).
|
||||||
|
*
|
||||||
|
* Any underlying MTD error results in YAFFS_FAIL.
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||||
|
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkBytes = dev->nDataBytesPerChunk;
|
||||||
|
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
yaffs_PackedTags1 pt1;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/* we assume that PackedTags1 and yaffs_Tags are compatible */
|
||||||
|
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
|
||||||
|
compile_time_assertion(sizeof(yaffs_Tags) == 8);
|
||||||
|
|
||||||
|
yaffs_PackTags1(&pt1, etags);
|
||||||
|
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
|
||||||
|
|
||||||
|
/* When deleting a chunk, the upper layer provides only skeletal
|
||||||
|
* etags, one with chunkDeleted set. However, we need to update the
|
||||||
|
* tags, not erase them completely. So we use the NAND write property
|
||||||
|
* that only zeroed-bits stick and set tag bytes to all-ones and
|
||||||
|
* zero just the (not) deleted bit.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
if (etags->chunkDeleted) {
|
||||||
|
memset(&pt1, 0xff, 8);
|
||||||
|
/* clear delete status bit to indicate deleted */
|
||||||
|
pt1.deleted = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
((__u8 *)&pt1)[8] = 0xff;
|
||||||
|
if (etags->chunkDeleted) {
|
||||||
|
memset(&pt1, 0xff, 8);
|
||||||
|
/* zero pageStatus byte to indicate deleted */
|
||||||
|
((__u8 *)&pt1)[8] = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(&ops, 0, sizeof(ops));
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.len = (data) ? chunkBytes : 0;
|
||||||
|
ops.ooblen = YTAG1_SIZE;
|
||||||
|
ops.datbuf = (__u8 *)data;
|
||||||
|
ops.oobbuf = (__u8 *)&pt1;
|
||||||
|
|
||||||
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
|
if (retval) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_MTD,
|
||||||
|
"write_oob failed, chunk %d, mtd error %d\n",
|
||||||
|
chunkInNAND, retval);
|
||||||
|
}
|
||||||
|
return retval ? YAFFS_FAIL : YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return with empty ExtendedTags but add eccResult.
|
||||||
|
*/
|
||||||
|
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
|
||||||
|
{
|
||||||
|
if (etags) {
|
||||||
|
memset(etags, 0, sizeof(*etags));
|
||||||
|
etags->eccResult = eccResult;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a chunk (page) from NAND.
|
||||||
|
*
|
||||||
|
* Caller expects ExtendedTags data to be usable even on error; that is,
|
||||||
|
* all members except eccResult and blockBad are zeroed.
|
||||||
|
*
|
||||||
|
* - Check ECC results for data (if applicable)
|
||||||
|
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
||||||
|
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
||||||
|
* - Convert PackedTags1 to ExtendedTags
|
||||||
|
* - Update eccResult and blockBad members to refect state.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
|
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkBytes = dev->nDataBytesPerChunk;
|
||||||
|
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||||
|
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
yaffs_PackedTags1 pt1;
|
||||||
|
int retval;
|
||||||
|
int deleted;
|
||||||
|
|
||||||
|
memset(&ops, 0, sizeof(ops));
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.len = (data) ? chunkBytes : 0;
|
||||||
|
ops.ooblen = YTAG1_SIZE;
|
||||||
|
ops.datbuf = data;
|
||||||
|
ops.oobbuf = (__u8 *)&pt1;
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||||
|
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
|
||||||
|
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
|
||||||
|
*/
|
||||||
|
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
|
||||||
|
#endif
|
||||||
|
/* Read page and oob using MTD.
|
||||||
|
* Check status and determine ECC result.
|
||||||
|
*/
|
||||||
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
|
if (retval) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_MTD,
|
||||||
|
"read_oob failed, chunk %d, mtd error %d\n",
|
||||||
|
chunkInNAND, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (retval) {
|
||||||
|
case 0:
|
||||||
|
/* no error */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -EUCLEAN:
|
||||||
|
/* MTD's ECC fixed the data */
|
||||||
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
dev->eccFixed++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -EBADMSG:
|
||||||
|
/* MTD's ECC could not fix the data */
|
||||||
|
dev->eccUnfixed++;
|
||||||
|
/* fall into... */
|
||||||
|
default:
|
||||||
|
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
|
||||||
|
etags->blockBad = (mtd->block_isbad)(mtd, addr);
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for a blank/erased chunk.
|
||||||
|
*/
|
||||||
|
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
|
||||||
|
/* when blank, upper layers want eccResult to be <= NO_ERROR */
|
||||||
|
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
/* Read deleted status (bit) then return it to it's non-deleted
|
||||||
|
* state before performing tags mini-ECC check. pt1.deleted is
|
||||||
|
* inverted.
|
||||||
|
*/
|
||||||
|
deleted = !pt1.deleted;
|
||||||
|
pt1.deleted = 1;
|
||||||
|
#else
|
||||||
|
(void) deleted; /* not used */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check the packed tags mini-ECC and correct if necessary/possible.
|
||||||
|
*/
|
||||||
|
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
|
||||||
|
switch (retval) {
|
||||||
|
case 0:
|
||||||
|
/* no tags error, use MTD result */
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* recovered tags-ECC error */
|
||||||
|
dev->tagsEccFixed++;
|
||||||
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* unrecovered tags-ECC error */
|
||||||
|
dev->tagsEccUnfixed++;
|
||||||
|
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unpack the tags to extended form and set ECC result.
|
||||||
|
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
|
||||||
|
*/
|
||||||
|
pt1.shouldBeFF = 0xFFFFFFFF;
|
||||||
|
yaffs_UnpackTags1(etags, &pt1);
|
||||||
|
etags->eccResult = eccres;
|
||||||
|
|
||||||
|
/* Set deleted state.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
etags->chunkDeleted = deleted;
|
||||||
|
#else
|
||||||
|
etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
|
||||||
|
#endif
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark a block bad.
|
||||||
|
*
|
||||||
|
* This is a persistant state.
|
||||||
|
* Use of this function should be rare.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
|
||||||
|
|
||||||
|
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||||
|
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check any MTD prerequists.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
|
||||||
|
{
|
||||||
|
/* 2.6.18 has mtd->ecclayout->oobavail */
|
||||||
|
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
|
||||||
|
int oobavail = mtd->ecclayout->oobavail;
|
||||||
|
|
||||||
|
if (oobavail < YTAG1_SIZE) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_ERROR,
|
||||||
|
"mtd device has only %d bytes for tags, need %d",
|
||||||
|
oobavail, YTAG1_SIZE);
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query for the current state of a specific block.
|
||||||
|
*
|
||||||
|
* Examine the tags of the first chunk of the block and return the state:
|
||||||
|
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
|
||||||
|
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
|
||||||
|
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
|
||||||
|
*
|
||||||
|
* Always returns YAFFS_OK.
|
||||||
|
*/
|
||||||
|
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * pState, int *pSequenceNumber)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||||
|
yaffs_ExtendedTags etags;
|
||||||
|
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
int seqnum = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/* We don't yet have a good place to test for MTD config prerequists.
|
||||||
|
* Do it here as we are called during the initial scan.
|
||||||
|
*/
|
||||||
|
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||||
|
if (etags.blockBad) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||||
|
"block %d is marked bad", blockNo);
|
||||||
|
state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
}
|
||||||
|
else if (etags.chunkUsed) {
|
||||||
|
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
|
seqnum = etags.sequenceNumber;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pState = state;
|
||||||
|
*pSequenceNumber = seqnum;
|
||||||
|
|
||||||
|
/* query always succeeds */
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*KERNEL_VERSION*/
|
||||||
|
|
||||||
|
--Boundary-00=_5LbTGmt62YoutxM--
|
||||||
|
|
||||||
|
|
||||||
|
|
363
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.c
Normal file
363
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.c
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||||
|
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module provides the interface between yaffs_nand.c and the
|
||||||
|
* MTD API. This version is used when the MTD interface supports the
|
||||||
|
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
|
||||||
|
* and we have small-page NAND device.
|
||||||
|
*
|
||||||
|
* These functions are invoked via function pointers in yaffs_nand.c.
|
||||||
|
* This replaces functionality provided by functions in yaffs_mtdif.c
|
||||||
|
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
|
||||||
|
* called in yaffs_mtdif.c when the function pointers are NULL.
|
||||||
|
* We assume the MTD layer is performing ECC (useNANDECC is true).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
#include "yaffs_packedtags1.h"
|
||||||
|
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
|
||||||
|
|
||||||
|
#include "linux/kernel.h"
|
||||||
|
#include "linux/version.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/mtd/mtd.h"
|
||||||
|
|
||||||
|
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
|
||||||
|
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
# define YTAG1_SIZE 8
|
||||||
|
#else
|
||||||
|
# define YTAG1_SIZE 9
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Use the following nand_ecclayout with MTD when using
|
||||||
|
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
|
||||||
|
* If you have existing Yaffs images and the byte order differs from this,
|
||||||
|
* adjust 'oobfree' to match your existing Yaffs data.
|
||||||
|
*
|
||||||
|
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
|
||||||
|
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
|
||||||
|
* the 9th byte.
|
||||||
|
*
|
||||||
|
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
|
||||||
|
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
|
||||||
|
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
|
||||||
|
* byte and B is the small-page bad-block indicator byte.
|
||||||
|
*/
|
||||||
|
static struct nand_ecclayout nand_oob_16 = {
|
||||||
|
.eccbytes = 6,
|
||||||
|
.eccpos = { 8, 9, 10, 13, 14, 15 },
|
||||||
|
.oobavail = 9,
|
||||||
|
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write a chunk (page) of data to NAND.
|
||||||
|
*
|
||||||
|
* Caller always provides ExtendedTags data which are converted to a more
|
||||||
|
* compact (packed) form for storage in NAND. A mini-ECC runs over the
|
||||||
|
* contents of the tags meta-data; used to valid the tags when read.
|
||||||
|
*
|
||||||
|
* - Pack ExtendedTags to PackedTags1 form
|
||||||
|
* - Compute mini-ECC for PackedTags1
|
||||||
|
* - Write data and packed tags to NAND.
|
||||||
|
*
|
||||||
|
* Note: Due to the use of the PackedTags1 meta-data which does not include
|
||||||
|
* a full sequence number (as found in the larger PackedTags2 form) it is
|
||||||
|
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
|
||||||
|
* discarded and dirty. This is not ideal: newer NAND parts are supposed
|
||||||
|
* to be written just once. When Yaffs performs this operation, this
|
||||||
|
* function is called with a NULL data pointer -- calling MTD write_oob
|
||||||
|
* without data is valid usage (2.6.17).
|
||||||
|
*
|
||||||
|
* Any underlying MTD error results in YAFFS_FAIL.
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||||
|
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkBytes = dev->nDataBytesPerChunk;
|
||||||
|
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
yaffs_PackedTags1 pt1;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/* we assume that PackedTags1 and yaffs_Tags are compatible */
|
||||||
|
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
|
||||||
|
compile_time_assertion(sizeof(yaffs_Tags) == 8);
|
||||||
|
|
||||||
|
dev->nPageWrites++;
|
||||||
|
|
||||||
|
yaffs_PackTags1(&pt1, etags);
|
||||||
|
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
|
||||||
|
|
||||||
|
/* When deleting a chunk, the upper layer provides only skeletal
|
||||||
|
* etags, one with chunkDeleted set. However, we need to update the
|
||||||
|
* tags, not erase them completely. So we use the NAND write property
|
||||||
|
* that only zeroed-bits stick and set tag bytes to all-ones and
|
||||||
|
* zero just the (not) deleted bit.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
if (etags->chunkDeleted) {
|
||||||
|
memset(&pt1, 0xff, 8);
|
||||||
|
/* clear delete status bit to indicate deleted */
|
||||||
|
pt1.deleted = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
((__u8 *)&pt1)[8] = 0xff;
|
||||||
|
if (etags->chunkDeleted) {
|
||||||
|
memset(&pt1, 0xff, 8);
|
||||||
|
/* zero pageStatus byte to indicate deleted */
|
||||||
|
((__u8 *)&pt1)[8] = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memset(&ops, 0, sizeof(ops));
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.len = (data) ? chunkBytes : 0;
|
||||||
|
ops.ooblen = YTAG1_SIZE;
|
||||||
|
ops.datbuf = (__u8 *)data;
|
||||||
|
ops.oobbuf = (__u8 *)&pt1;
|
||||||
|
|
||||||
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
|
if (retval) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_MTD,
|
||||||
|
"write_oob failed, chunk %d, mtd error %d\n",
|
||||||
|
chunkInNAND, retval);
|
||||||
|
}
|
||||||
|
return retval ? YAFFS_FAIL : YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return with empty ExtendedTags but add eccResult.
|
||||||
|
*/
|
||||||
|
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
|
||||||
|
{
|
||||||
|
if (etags) {
|
||||||
|
memset(etags, 0, sizeof(*etags));
|
||||||
|
etags->eccResult = eccResult;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a chunk (page) from NAND.
|
||||||
|
*
|
||||||
|
* Caller expects ExtendedTags data to be usable even on error; that is,
|
||||||
|
* all members except eccResult and blockBad are zeroed.
|
||||||
|
*
|
||||||
|
* - Check ECC results for data (if applicable)
|
||||||
|
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
||||||
|
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
||||||
|
* - Convert PackedTags1 to ExtendedTags
|
||||||
|
* - Update eccResult and blockBad members to refect state.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||||
|
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkBytes = dev->nDataBytesPerChunk;
|
||||||
|
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||||
|
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
yaffs_PackedTags1 pt1;
|
||||||
|
int retval;
|
||||||
|
int deleted;
|
||||||
|
|
||||||
|
dev->nPageReads++;
|
||||||
|
|
||||||
|
memset(&ops, 0, sizeof(ops));
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.len = (data) ? chunkBytes : 0;
|
||||||
|
ops.ooblen = YTAG1_SIZE;
|
||||||
|
ops.datbuf = data;
|
||||||
|
ops.oobbuf = (__u8 *)&pt1;
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||||
|
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
|
||||||
|
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
|
||||||
|
*/
|
||||||
|
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
|
||||||
|
#endif
|
||||||
|
/* Read page and oob using MTD.
|
||||||
|
* Check status and determine ECC result.
|
||||||
|
*/
|
||||||
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
|
if (retval) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_MTD,
|
||||||
|
"read_oob failed, chunk %d, mtd error %d\n",
|
||||||
|
chunkInNAND, retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (retval) {
|
||||||
|
case 0:
|
||||||
|
/* no error */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -EUCLEAN:
|
||||||
|
/* MTD's ECC fixed the data */
|
||||||
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
dev->eccFixed++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -EBADMSG:
|
||||||
|
/* MTD's ECC could not fix the data */
|
||||||
|
dev->eccUnfixed++;
|
||||||
|
/* fall into... */
|
||||||
|
default:
|
||||||
|
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
|
||||||
|
etags->blockBad = (mtd->block_isbad)(mtd, addr);
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for a blank/erased chunk.
|
||||||
|
*/
|
||||||
|
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
|
||||||
|
/* when blank, upper layers want eccResult to be <= NO_ERROR */
|
||||||
|
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||||
|
/* Read deleted status (bit) then return it to it's non-deleted
|
||||||
|
* state before performing tags mini-ECC check. pt1.deleted is
|
||||||
|
* inverted.
|
||||||
|
*/
|
||||||
|
deleted = !pt1.deleted;
|
||||||
|
pt1.deleted = 1;
|
||||||
|
#else
|
||||||
|
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check the packed tags mini-ECC and correct if necessary/possible.
|
||||||
|
*/
|
||||||
|
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
|
||||||
|
switch (retval) {
|
||||||
|
case 0:
|
||||||
|
/* no tags error, use MTD result */
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* recovered tags-ECC error */
|
||||||
|
dev->tagsEccFixed++;
|
||||||
|
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
|
||||||
|
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* unrecovered tags-ECC error */
|
||||||
|
dev->tagsEccUnfixed++;
|
||||||
|
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unpack the tags to extended form and set ECC result.
|
||||||
|
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
|
||||||
|
*/
|
||||||
|
pt1.shouldBeFF = 0xFFFFFFFF;
|
||||||
|
yaffs_UnpackTags1(etags, &pt1);
|
||||||
|
etags->eccResult = eccres;
|
||||||
|
|
||||||
|
/* Set deleted state */
|
||||||
|
etags->chunkDeleted = deleted;
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark a block bad.
|
||||||
|
*
|
||||||
|
* This is a persistant state.
|
||||||
|
* Use of this function should be rare.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
|
||||||
|
|
||||||
|
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||||
|
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check any MTD prerequists.
|
||||||
|
*
|
||||||
|
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||||
|
*/
|
||||||
|
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
|
||||||
|
{
|
||||||
|
/* 2.6.18 has mtd->ecclayout->oobavail */
|
||||||
|
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
|
||||||
|
int oobavail = mtd->ecclayout->oobavail;
|
||||||
|
|
||||||
|
if (oobavail < YTAG1_SIZE) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_ERROR,
|
||||||
|
"mtd device has only %d bytes for tags, need %d\n",
|
||||||
|
oobavail, YTAG1_SIZE);
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Query for the current state of a specific block.
|
||||||
|
*
|
||||||
|
* Examine the tags of the first chunk of the block and return the state:
|
||||||
|
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
|
||||||
|
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
|
||||||
|
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
|
||||||
|
*
|
||||||
|
* Always returns YAFFS_OK.
|
||||||
|
*/
|
||||||
|
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * pState, int *pSequenceNumber)
|
||||||
|
{
|
||||||
|
struct mtd_info * mtd = dev->genericDevice;
|
||||||
|
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||||
|
yaffs_ExtendedTags etags;
|
||||||
|
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
int seqnum = 0;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
/* We don't yet have a good place to test for MTD config prerequists.
|
||||||
|
* Do it here as we are called during the initial scan.
|
||||||
|
*/
|
||||||
|
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||||
|
if (etags.blockBad) {
|
||||||
|
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||||
|
"block %d is marked bad", blockNo);
|
||||||
|
state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
}
|
||||||
|
else if (etags.chunkUsed) {
|
||||||
|
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
|
seqnum = etags.sequenceNumber;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pState = state;
|
||||||
|
*pSequenceNumber = seqnum;
|
||||||
|
|
||||||
|
/* query always succeeds */
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*KERNEL_VERSION*/
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_MTDIF1_H__
|
||||||
|
#define __YAFFS_MTDIF1_H__
|
||||||
|
|
||||||
|
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data, const yaffs_ExtendedTags * tags);
|
||||||
|
|
||||||
|
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
__u8 * data, yaffs_ExtendedTags * tags);
|
||||||
|
|
||||||
|
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||||
|
|
||||||
|
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * state, int *sequenceNumber);
|
||||||
|
|
||||||
|
#endif
|
232
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.c
Normal file
232
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.c
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* mtd interface for YAFFS2 */
|
||||||
|
|
||||||
|
const char *yaffs_mtdif2_c_version =
|
||||||
|
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "yaffs_mtdif2.h"
|
||||||
|
|
||||||
|
#include "linux/mtd/mtd.h"
|
||||||
|
#include "linux/types.h"
|
||||||
|
#include "linux/time.h"
|
||||||
|
|
||||||
|
#include "yaffs_packedtags2.h"
|
||||||
|
|
||||||
|
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
#else
|
||||||
|
size_t dummy;
|
||||||
|
#endif
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||||
|
|
||||||
|
yaffs_PackedTags2 pt;
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR
|
||||||
|
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||||
|
TENDSTR), chunkInNAND, data, tags));
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
if (tags)
|
||||||
|
yaffs_PackTags2(&pt, tags);
|
||||||
|
else
|
||||||
|
BUG(); /* both tags and data should always be present */
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.ooblen = sizeof(pt);
|
||||||
|
ops.len = dev->nDataBytesPerChunk;
|
||||||
|
ops.ooboffs = 0;
|
||||||
|
ops.datbuf = (__u8 *)data;
|
||||||
|
ops.oobbuf = (void *)&pt;
|
||||||
|
retval = mtd->write_oob(mtd, addr, &ops);
|
||||||
|
} else
|
||||||
|
BUG(); /* both tags and data should always be present */
|
||||||
|
#else
|
||||||
|
if (tags) {
|
||||||
|
yaffs_PackTags2(&pt, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && tags) {
|
||||||
|
if (dev->useNANDECC)
|
||||||
|
retval =
|
||||||
|
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, (__u8 *) & pt, NULL);
|
||||||
|
else
|
||||||
|
retval =
|
||||||
|
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, (__u8 *) & pt, NULL);
|
||||||
|
} else {
|
||||||
|
if (data)
|
||||||
|
retval =
|
||||||
|
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||||
|
data);
|
||||||
|
if (tags)
|
||||||
|
retval =
|
||||||
|
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||||
|
(__u8 *) & pt);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
__u8 * data, yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
struct mtd_oob_ops ops;
|
||||||
|
#endif
|
||||||
|
size_t dummy;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
|
||||||
|
|
||||||
|
yaffs_PackedTags2 pt;
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR
|
||||||
|
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
|
||||||
|
TENDSTR), chunkInNAND, data, tags));
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||||
|
if (data && !tags)
|
||||||
|
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data);
|
||||||
|
else if (tags) {
|
||||||
|
ops.mode = MTD_OOB_AUTO;
|
||||||
|
ops.ooblen = sizeof(pt);
|
||||||
|
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
|
||||||
|
ops.ooboffs = 0;
|
||||||
|
ops.datbuf = data;
|
||||||
|
ops.oobbuf = dev->spareBuffer;
|
||||||
|
retval = mtd->read_oob(mtd, addr, &ops);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (data && tags) {
|
||||||
|
if (dev->useNANDECC) {
|
||||||
|
retval =
|
||||||
|
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, dev->spareBuffer,
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
retval =
|
||||||
|
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
|
||||||
|
&dummy, data, dev->spareBuffer,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data)
|
||||||
|
retval =
|
||||||
|
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
|
||||||
|
data);
|
||||||
|
if (tags)
|
||||||
|
retval =
|
||||||
|
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||||
|
dev->spareBuffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy(&pt, dev->spareBuffer, sizeof(pt));
|
||||||
|
|
||||||
|
if (tags)
|
||||||
|
yaffs_UnpackTags2(tags, &pt);
|
||||||
|
|
||||||
|
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
|
||||||
|
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
int retval;
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
|
||||||
|
|
||||||
|
retval =
|
||||||
|
mtd->block_markbad(mtd,
|
||||||
|
blockNo * dev->nChunksPerBlock *
|
||||||
|
dev->nDataBytesPerChunk);
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * state, int *sequenceNumber)
|
||||||
|
{
|
||||||
|
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
|
||||||
|
retval =
|
||||||
|
mtd->block_isbad(mtd,
|
||||||
|
blockNo * dev->nChunksPerBlock *
|
||||||
|
dev->nDataBytesPerChunk);
|
||||||
|
|
||||||
|
if (retval) {
|
||||||
|
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
||||||
|
|
||||||
|
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
*sequenceNumber = 0;
|
||||||
|
} else {
|
||||||
|
yaffs_ExtendedTags t;
|
||||||
|
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
||||||
|
blockNo *
|
||||||
|
dev->nChunksPerBlock, NULL,
|
||||||
|
&t);
|
||||||
|
|
||||||
|
if (t.chunkUsed) {
|
||||||
|
*sequenceNumber = t.sequenceNumber;
|
||||||
|
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
|
} else {
|
||||||
|
*sequenceNumber = 0;
|
||||||
|
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
|
||||||
|
*state));
|
||||||
|
|
||||||
|
if (retval == 0)
|
||||||
|
return YAFFS_OK;
|
||||||
|
else
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_MTDIF2_H__
|
||||||
|
#define __YAFFS_MTDIF2_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_ExtendedTags * tags);
|
||||||
|
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
__u8 * data, yaffs_ExtendedTags * tags);
|
||||||
|
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||||
|
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * state, int *sequenceNumber);
|
||||||
|
|
||||||
|
#endif
|
134
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.c
Normal file
134
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char *yaffs_nand_c_version =
|
||||||
|
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
|
||||||
|
|
||||||
|
#include "yaffs_nand.h"
|
||||||
|
#include "yaffs_tagscompat.h"
|
||||||
|
#include "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
|
|
||||||
|
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
__u8 * buffer,
|
||||||
|
yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
yaffs_ExtendedTags localTags;
|
||||||
|
|
||||||
|
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
|
||||||
|
|
||||||
|
/* If there are no tags provided, use local tags to get prioritised gc working */
|
||||||
|
if(!tags)
|
||||||
|
tags = &localTags;
|
||||||
|
|
||||||
|
if (dev->readChunkWithTagsFromNAND)
|
||||||
|
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
|
||||||
|
tags);
|
||||||
|
else
|
||||||
|
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
|
||||||
|
realignedChunkInNAND,
|
||||||
|
buffer,
|
||||||
|
tags);
|
||||||
|
if(tags &&
|
||||||
|
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
|
||||||
|
|
||||||
|
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
|
||||||
|
yaffs_HandleChunkError(dev,bi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
const __u8 * buffer,
|
||||||
|
yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
chunkInNAND -= dev->chunkOffset;
|
||||||
|
|
||||||
|
|
||||||
|
if (tags) {
|
||||||
|
tags->sequenceNumber = dev->sequenceNumber;
|
||||||
|
tags->chunkUsed = 1;
|
||||||
|
if (!yaffs_ValidateTags(tags)) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR("Writing uninitialised tags" TENDSTR)));
|
||||||
|
YBUG();
|
||||||
|
}
|
||||||
|
T(YAFFS_TRACE_WRITE,
|
||||||
|
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
|
||||||
|
tags->objectId, tags->chunkId));
|
||||||
|
} else {
|
||||||
|
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
|
||||||
|
YBUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->writeChunkWithTagsToNAND)
|
||||||
|
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
|
||||||
|
tags);
|
||||||
|
else
|
||||||
|
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
|
||||||
|
chunkInNAND,
|
||||||
|
buffer,
|
||||||
|
tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
|
||||||
|
{
|
||||||
|
blockNo -= dev->blockOffset;
|
||||||
|
|
||||||
|
;
|
||||||
|
if (dev->markNANDBlockBad)
|
||||||
|
return dev->markNANDBlockBad(dev, blockNo);
|
||||||
|
else
|
||||||
|
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||||
|
int blockNo,
|
||||||
|
yaffs_BlockState * state,
|
||||||
|
unsigned *sequenceNumber)
|
||||||
|
{
|
||||||
|
blockNo -= dev->blockOffset;
|
||||||
|
|
||||||
|
if (dev->queryNANDBlock)
|
||||||
|
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
|
||||||
|
else
|
||||||
|
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
|
||||||
|
state,
|
||||||
|
sequenceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockInNAND)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
blockInNAND -= dev->blockOffset;
|
||||||
|
|
||||||
|
|
||||||
|
dev->nBlockErasures++;
|
||||||
|
result = dev->eraseBlockInNAND(dev, blockInNAND);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
|
||||||
|
{
|
||||||
|
return dev->initialiseNAND(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
44
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.h
Normal file
44
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_NAND_H__
|
||||||
|
#define __YAFFS_NAND_H__
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
__u8 * buffer,
|
||||||
|
yaffs_ExtendedTags * tags);
|
||||||
|
|
||||||
|
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
const __u8 * buffer,
|
||||||
|
yaffs_ExtendedTags * tags);
|
||||||
|
|
||||||
|
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
|
||||||
|
|
||||||
|
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
|
||||||
|
int blockNo,
|
||||||
|
yaffs_BlockState * state,
|
||||||
|
unsigned *sequenceNumber);
|
||||||
|
|
||||||
|
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockInNAND);
|
||||||
|
|
||||||
|
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Interface to emulated NAND functions (2k page size) */
|
||||||
|
|
||||||
|
#ifndef __YAFFS_NANDEMUL2K_H__
|
||||||
|
#define __YAFFS_NANDEMUL2K_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int chunkInNAND, const __u8 * data,
|
||||||
|
yaffs_ExtendedTags * tags);
|
||||||
|
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int chunkInNAND, __u8 * data,
|
||||||
|
yaffs_ExtendedTags * tags);
|
||||||
|
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||||
|
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||||
|
yaffs_BlockState * state, int *sequenceNumber);
|
||||||
|
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockInNAND);
|
||||||
|
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
|
||||||
|
int nandemul2k_GetBytesPerChunk(void);
|
||||||
|
int nandemul2k_GetChunksPerBlock(void);
|
||||||
|
int nandemul2k_GetNumberOfBlocks(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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 "yaffs_packedtags1.h"
|
||||||
|
#include "yportenv.h"
|
||||||
|
|
||||||
|
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
|
||||||
|
{
|
||||||
|
pt->chunkId = t->chunkId;
|
||||||
|
pt->serialNumber = t->serialNumber;
|
||||||
|
pt->byteCount = t->byteCount;
|
||||||
|
pt->objectId = t->objectId;
|
||||||
|
pt->ecc = 0;
|
||||||
|
pt->deleted = (t->chunkDeleted) ? 0 : 1;
|
||||||
|
pt->unusedStuff = 0;
|
||||||
|
pt->shouldBeFF = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
|
||||||
|
{
|
||||||
|
static const __u8 allFF[] =
|
||||||
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff };
|
||||||
|
|
||||||
|
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
|
||||||
|
t->blockBad = 0;
|
||||||
|
if (pt->shouldBeFF != 0xFFFFFFFF) {
|
||||||
|
t->blockBad = 1;
|
||||||
|
}
|
||||||
|
t->chunkUsed = 1;
|
||||||
|
t->objectId = pt->objectId;
|
||||||
|
t->chunkId = pt->chunkId;
|
||||||
|
t->byteCount = pt->byteCount;
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
t->chunkDeleted = (pt->deleted) ? 0 : 1;
|
||||||
|
t->serialNumber = pt->serialNumber;
|
||||||
|
} else {
|
||||||
|
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
|
||||||
|
|
||||||
|
#ifndef __YAFFS_PACKEDTAGS1_H__
|
||||||
|
#define __YAFFS_PACKEDTAGS1_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned chunkId:20;
|
||||||
|
unsigned serialNumber:2;
|
||||||
|
unsigned byteCount:10;
|
||||||
|
unsigned objectId:18;
|
||||||
|
unsigned ecc:12;
|
||||||
|
unsigned deleted:1;
|
||||||
|
unsigned unusedStuff:1;
|
||||||
|
unsigned shouldBeFF;
|
||||||
|
|
||||||
|
} yaffs_PackedTags1;
|
||||||
|
|
||||||
|
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
|
||||||
|
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
|
||||||
|
#endif
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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 "yaffs_packedtags2.h"
|
||||||
|
#include "yportenv.h"
|
||||||
|
#include "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
|
/* This code packs a set of extended tags into a binary structure for
|
||||||
|
* NAND storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Some of the information is "extra" struff which can be packed in to
|
||||||
|
* speed scanning
|
||||||
|
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Extra flags applied to chunkId */
|
||||||
|
|
||||||
|
#define EXTRA_HEADER_INFO_FLAG 0x80000000
|
||||||
|
#define EXTRA_SHRINK_FLAG 0x40000000
|
||||||
|
#define EXTRA_SHADOWS_FLAG 0x20000000
|
||||||
|
#define EXTRA_SPARE_FLAGS 0x10000000
|
||||||
|
|
||||||
|
#define ALL_EXTRA_FLAGS 0xF0000000
|
||||||
|
|
||||||
|
/* Also, the top 4 bits of the object Id are set to the object type. */
|
||||||
|
#define EXTRA_OBJECT_TYPE_SHIFT (28)
|
||||||
|
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
|
||||||
|
|
||||||
|
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
|
||||||
|
{
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
|
||||||
|
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
|
||||||
|
pt->t.sequenceNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
|
||||||
|
{
|
||||||
|
T(YAFFS_TRACE_MTD,
|
||||||
|
(TSTR
|
||||||
|
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
|
||||||
|
"%d del %d ser %d seq %d"
|
||||||
|
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
|
||||||
|
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
|
||||||
|
t->sequenceNumber));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
|
||||||
|
{
|
||||||
|
pt->t.chunkId = t->chunkId;
|
||||||
|
pt->t.sequenceNumber = t->sequenceNumber;
|
||||||
|
pt->t.byteCount = t->byteCount;
|
||||||
|
pt->t.objectId = t->objectId;
|
||||||
|
|
||||||
|
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
|
||||||
|
/* Store the extra header info instead */
|
||||||
|
/* We save the parent object in the chunkId */
|
||||||
|
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
|
||||||
|
| t->extraParentObjectId;
|
||||||
|
if (t->extraIsShrinkHeader) {
|
||||||
|
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
|
||||||
|
}
|
||||||
|
if (t->extraShadows) {
|
||||||
|
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||||
|
pt->t.objectId |=
|
||||||
|
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
|
||||||
|
|
||||||
|
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||||
|
pt->t.byteCount = t->extraEquivalentObjectId;
|
||||||
|
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
|
||||||
|
pt->t.byteCount = t->extraFileLength;
|
||||||
|
} else {
|
||||||
|
pt->t.byteCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yaffs_DumpPackedTags2(pt);
|
||||||
|
yaffs_DumpTags2(t);
|
||||||
|
|
||||||
|
#ifndef YAFFS_IGNORE_TAGS_ECC
|
||||||
|
{
|
||||||
|
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||||
|
sizeof(yaffs_PackedTags2TagsPart),
|
||||||
|
&pt->ecc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
|
||||||
|
{
|
||||||
|
|
||||||
|
memset(t, 0, sizeof(yaffs_ExtendedTags));
|
||||||
|
|
||||||
|
yaffs_InitialiseTags(t);
|
||||||
|
|
||||||
|
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
|
||||||
|
/* Page is in use */
|
||||||
|
#ifdef YAFFS_IGNORE_TAGS_ECC
|
||||||
|
{
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
yaffs_ECCOther ecc;
|
||||||
|
int result;
|
||||||
|
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
|
||||||
|
sizeof
|
||||||
|
(yaffs_PackedTags2TagsPart),
|
||||||
|
&ecc);
|
||||||
|
result =
|
||||||
|
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
|
||||||
|
sizeof
|
||||||
|
(yaffs_PackedTags2TagsPart),
|
||||||
|
&pt->ecc, &ecc);
|
||||||
|
switch(result){
|
||||||
|
case 0:
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
t->blockBad = 0;
|
||||||
|
t->chunkUsed = 1;
|
||||||
|
t->objectId = pt->t.objectId;
|
||||||
|
t->chunkId = pt->t.chunkId;
|
||||||
|
t->byteCount = pt->t.byteCount;
|
||||||
|
t->chunkDeleted = 0;
|
||||||
|
t->serialNumber = 0;
|
||||||
|
t->sequenceNumber = pt->t.sequenceNumber;
|
||||||
|
|
||||||
|
/* Do extra header info stuff */
|
||||||
|
|
||||||
|
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
|
||||||
|
t->chunkId = 0;
|
||||||
|
t->byteCount = 0;
|
||||||
|
|
||||||
|
t->extraHeaderInfoAvailable = 1;
|
||||||
|
t->extraParentObjectId =
|
||||||
|
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
|
||||||
|
t->extraIsShrinkHeader =
|
||||||
|
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
|
||||||
|
t->extraShadows =
|
||||||
|
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
|
||||||
|
t->extraObjectType =
|
||||||
|
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
|
||||||
|
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
|
||||||
|
|
||||||
|
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
|
||||||
|
t->extraEquivalentObjectId = pt->t.byteCount;
|
||||||
|
} else {
|
||||||
|
t->extraFileLength = pt->t.byteCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yaffs_DumpPackedTags2(pt);
|
||||||
|
yaffs_DumpTags2(t);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
|
||||||
|
|
||||||
|
#ifndef __YAFFS_PACKEDTAGS2_H__
|
||||||
|
#define __YAFFS_PACKEDTAGS2_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
#include "yaffs_ecc.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned sequenceNumber;
|
||||||
|
unsigned objectId;
|
||||||
|
unsigned chunkId;
|
||||||
|
unsigned byteCount;
|
||||||
|
} yaffs_PackedTags2TagsPart;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
yaffs_PackedTags2TagsPart t;
|
||||||
|
yaffs_ECCOther ecc;
|
||||||
|
} yaffs_PackedTags2;
|
||||||
|
|
||||||
|
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
|
||||||
|
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
|
||||||
|
#endif
|
160
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.c
Normal file
160
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.c
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1992, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "yportenv.h"
|
||||||
|
//#include <linux/string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
|
||||||
|
*/
|
||||||
|
#define swapcode(TYPE, parmi, parmj, n) { \
|
||||||
|
long i = (n) / sizeof (TYPE); \
|
||||||
|
register TYPE *pi = (TYPE *) (parmi); \
|
||||||
|
register TYPE *pj = (TYPE *) (parmj); \
|
||||||
|
do { \
|
||||||
|
register TYPE t = *pi; \
|
||||||
|
*pi++ = *pj; \
|
||||||
|
*pj++ = t; \
|
||||||
|
} while (--i > 0); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
|
||||||
|
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
swapfunc(char *a, char *b, int n, int swaptype)
|
||||||
|
{
|
||||||
|
if (swaptype <= 1)
|
||||||
|
swapcode(long, a, b, n)
|
||||||
|
else
|
||||||
|
swapcode(char, a, b, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
#define swap(a, b) \
|
||||||
|
if (swaptype == 0) { \
|
||||||
|
long t = *(long *)(a); \
|
||||||
|
*(long *)(a) = *(long *)(b); \
|
||||||
|
*(long *)(b) = t; \
|
||||||
|
} else \
|
||||||
|
swapfunc(a, b, es, swaptype)
|
||||||
|
|
||||||
|
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
|
||||||
|
|
||||||
|
static __inline char *
|
||||||
|
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
|
||||||
|
{
|
||||||
|
return cmp(a, b) < 0 ?
|
||||||
|
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
|
||||||
|
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
yaffs_qsort(void *aa, size_t n, size_t es,
|
||||||
|
int (*cmp)(const void *, const void *))
|
||||||
|
{
|
||||||
|
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
|
||||||
|
int d, r, swaptype, swap_cnt;
|
||||||
|
register char *a = aa;
|
||||||
|
|
||||||
|
loop: SWAPINIT(a, es);
|
||||||
|
swap_cnt = 0;
|
||||||
|
if (n < 7) {
|
||||||
|
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
|
||||||
|
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||||
|
pl -= es)
|
||||||
|
swap(pl, pl - es);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pm = (char *)a + (n / 2) * es;
|
||||||
|
if (n > 7) {
|
||||||
|
pl = (char *)a;
|
||||||
|
pn = (char *)a + (n - 1) * es;
|
||||||
|
if (n > 40) {
|
||||||
|
d = (n / 8) * es;
|
||||||
|
pl = med3(pl, pl + d, pl + 2 * d, cmp);
|
||||||
|
pm = med3(pm - d, pm, pm + d, cmp);
|
||||||
|
pn = med3(pn - 2 * d, pn - d, pn, cmp);
|
||||||
|
}
|
||||||
|
pm = med3(pl, pm, pn, cmp);
|
||||||
|
}
|
||||||
|
swap(a, pm);
|
||||||
|
pa = pb = (char *)a + es;
|
||||||
|
|
||||||
|
pc = pd = (char *)a + (n - 1) * es;
|
||||||
|
for (;;) {
|
||||||
|
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
|
||||||
|
if (r == 0) {
|
||||||
|
swap_cnt = 1;
|
||||||
|
swap(pa, pb);
|
||||||
|
pa += es;
|
||||||
|
}
|
||||||
|
pb += es;
|
||||||
|
}
|
||||||
|
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
|
||||||
|
if (r == 0) {
|
||||||
|
swap_cnt = 1;
|
||||||
|
swap(pc, pd);
|
||||||
|
pd -= es;
|
||||||
|
}
|
||||||
|
pc -= es;
|
||||||
|
}
|
||||||
|
if (pb > pc)
|
||||||
|
break;
|
||||||
|
swap(pb, pc);
|
||||||
|
swap_cnt = 1;
|
||||||
|
pb += es;
|
||||||
|
pc -= es;
|
||||||
|
}
|
||||||
|
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||||
|
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
|
||||||
|
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||||
|
pl -= es)
|
||||||
|
swap(pl, pl - es);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pn = (char *)a + n * es;
|
||||||
|
r = min(pa - (char *)a, pb - pa);
|
||||||
|
vecswap(a, pb - r, r);
|
||||||
|
r = min((long)(pd - pc), (long)(pn - pd - es));
|
||||||
|
vecswap(pb, pn - r, r);
|
||||||
|
if ((r = pb - pa) > es)
|
||||||
|
yaffs_qsort(a, r / es, es, cmp);
|
||||||
|
if ((r = pd - pc) > es) {
|
||||||
|
/* Iterate rather than recurse to save stack space */
|
||||||
|
a = pn - r;
|
||||||
|
n = r / es;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __YAFFS_QSORT_H__
|
||||||
|
#define __YAFFS_QSORT_H__
|
||||||
|
|
||||||
|
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
|
||||||
|
int (*cmp)(const void *, const void *));
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,530 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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 "yaffs_guts.h"
|
||||||
|
#include "yaffs_tagscompat.h"
|
||||||
|
#include "yaffs_ecc.h"
|
||||||
|
|
||||||
|
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
|
||||||
|
#ifdef NOTYET
|
||||||
|
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
|
||||||
|
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_Spare * spare);
|
||||||
|
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const yaffs_Spare * spare);
|
||||||
|
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char yaffs_countBitsTable[256] = {
|
||||||
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||||
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||||
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||||
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||||
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||||
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||||
|
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||||
|
};
|
||||||
|
|
||||||
|
int yaffs_CountBits(__u8 x)
|
||||||
|
{
|
||||||
|
int retVal;
|
||||||
|
retVal = yaffs_countBitsTable[x];
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** Tags ECC calculations *********/
|
||||||
|
|
||||||
|
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
yaffs_ECCCalculate(data, spare->ecc1);
|
||||||
|
yaffs_ECCCalculate(&data[256], spare->ecc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yaffs_CalcTagsECC(yaffs_Tags * tags)
|
||||||
|
{
|
||||||
|
/* Calculate an ecc */
|
||||||
|
|
||||||
|
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||||
|
unsigned i, j;
|
||||||
|
unsigned ecc = 0;
|
||||||
|
unsigned bit = 0;
|
||||||
|
|
||||||
|
tags->ecc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
for (j = 1; j & 0xff; j <<= 1) {
|
||||||
|
bit++;
|
||||||
|
if (b[i] & j) {
|
||||||
|
ecc ^= bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tags->ecc = ecc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
|
||||||
|
{
|
||||||
|
unsigned ecc = tags->ecc;
|
||||||
|
|
||||||
|
yaffs_CalcTagsECC(tags);
|
||||||
|
|
||||||
|
ecc ^= tags->ecc;
|
||||||
|
|
||||||
|
if (ecc && ecc <= 64) {
|
||||||
|
/* TODO: Handle the failure better. Retire? */
|
||||||
|
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
|
||||||
|
|
||||||
|
ecc--;
|
||||||
|
|
||||||
|
b[ecc / 8] ^= (1 << (ecc & 7));
|
||||||
|
|
||||||
|
/* Now recvalc the ecc */
|
||||||
|
yaffs_CalcTagsECC(tags);
|
||||||
|
|
||||||
|
return 1; /* recovered error */
|
||||||
|
} else if (ecc) {
|
||||||
|
/* Wierd ecc failure value */
|
||||||
|
/* TODO Need to do somethiong here */
|
||||||
|
return -1; /* unrecovered error */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** Tags **********/
|
||||||
|
|
||||||
|
static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
|
||||||
|
yaffs_Tags * tagsPtr)
|
||||||
|
{
|
||||||
|
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||||
|
|
||||||
|
yaffs_CalcTagsECC(tagsPtr);
|
||||||
|
|
||||||
|
sparePtr->tagByte0 = tu->asBytes[0];
|
||||||
|
sparePtr->tagByte1 = tu->asBytes[1];
|
||||||
|
sparePtr->tagByte2 = tu->asBytes[2];
|
||||||
|
sparePtr->tagByte3 = tu->asBytes[3];
|
||||||
|
sparePtr->tagByte4 = tu->asBytes[4];
|
||||||
|
sparePtr->tagByte5 = tu->asBytes[5];
|
||||||
|
sparePtr->tagByte6 = tu->asBytes[6];
|
||||||
|
sparePtr->tagByte7 = tu->asBytes[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
|
||||||
|
yaffs_Tags * tagsPtr)
|
||||||
|
{
|
||||||
|
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
tu->asBytes[0] = sparePtr->tagByte0;
|
||||||
|
tu->asBytes[1] = sparePtr->tagByte1;
|
||||||
|
tu->asBytes[2] = sparePtr->tagByte2;
|
||||||
|
tu->asBytes[3] = sparePtr->tagByte3;
|
||||||
|
tu->asBytes[4] = sparePtr->tagByte4;
|
||||||
|
tu->asBytes[5] = sparePtr->tagByte5;
|
||||||
|
tu->asBytes[6] = sparePtr->tagByte6;
|
||||||
|
tu->asBytes[7] = sparePtr->tagByte7;
|
||||||
|
|
||||||
|
result = yaffs_CheckECCOnTags(tagsPtr);
|
||||||
|
if (result > 0) {
|
||||||
|
dev->tagsEccFixed++;
|
||||||
|
} else if (result < 0) {
|
||||||
|
dev->tagsEccUnfixed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_SpareInitialise(yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
memset(spare, 0xFF, sizeof(yaffs_Spare));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int chunkInNAND, const __u8 * data,
|
||||||
|
yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
|
||||||
|
chunkInNAND));
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->nPageWrites++;
|
||||||
|
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
__u8 * data,
|
||||||
|
yaffs_Spare * spare,
|
||||||
|
yaffs_ECCResult * eccResult,
|
||||||
|
int doErrorCorrection)
|
||||||
|
{
|
||||||
|
int retVal;
|
||||||
|
yaffs_Spare localSpare;
|
||||||
|
|
||||||
|
dev->nPageReads++;
|
||||||
|
|
||||||
|
if (!spare && data) {
|
||||||
|
/* If we don't have a real spare, then we use a local one. */
|
||||||
|
/* Need this for the calculation of the ecc */
|
||||||
|
spare = &localSpare;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev->useNANDECC) {
|
||||||
|
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
|
||||||
|
if (data && doErrorCorrection) {
|
||||||
|
/* Do ECC correction */
|
||||||
|
/* Todo handle any errors */
|
||||||
|
int eccResult1, eccResult2;
|
||||||
|
__u8 calcEcc[3];
|
||||||
|
|
||||||
|
yaffs_ECCCalculate(data, calcEcc);
|
||||||
|
eccResult1 =
|
||||||
|
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
|
||||||
|
yaffs_ECCCalculate(&data[256], calcEcc);
|
||||||
|
eccResult2 =
|
||||||
|
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
|
||||||
|
|
||||||
|
if (eccResult1 > 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>yaffs ecc error fix performed on chunk %d:0"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
dev->eccFixed++;
|
||||||
|
} else if (eccResult1 < 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>yaffs ecc error unfixed on chunk %d:0"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
dev->eccUnfixed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eccResult2 > 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>yaffs ecc error fix performed on chunk %d:1"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
dev->eccFixed++;
|
||||||
|
} else if (eccResult2 < 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>yaffs ecc error unfixed on chunk %d:1"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
dev->eccUnfixed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eccResult1 || eccResult2) {
|
||||||
|
/* We had a data problem on this page */
|
||||||
|
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eccResult1 < 0 || eccResult2 < 0)
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
|
else if (eccResult1 > 0 || eccResult2 > 0)
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
else
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Must allocate enough memory for spare+2*sizeof(int) */
|
||||||
|
/* for ecc results from device. */
|
||||||
|
struct yaffs_NANDSpare nspare;
|
||||||
|
retVal =
|
||||||
|
dev->readChunkFromNAND(dev, chunkInNAND, data,
|
||||||
|
(yaffs_Spare *) & nspare);
|
||||||
|
memcpy(spare, &nspare, sizeof(yaffs_Spare));
|
||||||
|
if (data && doErrorCorrection) {
|
||||||
|
if (nspare.eccres1 > 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>mtd ecc error fix performed on chunk %d:0"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
} else if (nspare.eccres1 < 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>mtd ecc error unfixed on chunk %d:0"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nspare.eccres2 > 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>mtd ecc error fix performed on chunk %d:1"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
} else if (nspare.eccres2 < 0) {
|
||||||
|
T(YAFFS_TRACE_ERROR,
|
||||||
|
(TSTR
|
||||||
|
("**>>mtd ecc error unfixed on chunk %d:1"
|
||||||
|
TENDSTR), chunkInNAND));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nspare.eccres1 || nspare.eccres2) {
|
||||||
|
/* We had a data problem on this page */
|
||||||
|
yaffs_HandleReadDataError(dev, chunkInNAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
|
||||||
|
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||||
|
else
|
||||||
|
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOTYET
|
||||||
|
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
|
||||||
|
int chunkInNAND)
|
||||||
|
{
|
||||||
|
|
||||||
|
static int init = 0;
|
||||||
|
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
|
||||||
|
static __u8 data[YAFFS_BYTES_PER_CHUNK];
|
||||||
|
/* Might as well always allocate the larger size for */
|
||||||
|
/* dev->useNANDECC == true; */
|
||||||
|
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
|
||||||
|
|
||||||
|
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
|
||||||
|
|
||||||
|
if (!init) {
|
||||||
|
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
if (memcmp(cmpbuf, spare, 16))
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
|
||||||
|
return YAFFS_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions for robustisizing
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
|
||||||
|
{
|
||||||
|
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
|
||||||
|
|
||||||
|
/* Mark the block for retirement */
|
||||||
|
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
||||||
|
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
|
||||||
|
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* Just do a garbage collection on the affected block
|
||||||
|
* then retire the block
|
||||||
|
* NB recursion
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NOTYET
|
||||||
|
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
|
||||||
|
const yaffs_Spare * spare)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
|
||||||
|
{
|
||||||
|
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
|
||||||
|
|
||||||
|
/* Mark the block for retirement */
|
||||||
|
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
|
||||||
|
/* Delete the chunk */
|
||||||
|
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
|
||||||
|
const yaffs_Spare * s0, const yaffs_Spare * s1)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
|
||||||
|
s0->tagByte0 != s1->tagByte0 ||
|
||||||
|
s0->tagByte1 != s1->tagByte1 ||
|
||||||
|
s0->tagByte2 != s1->tagByte2 ||
|
||||||
|
s0->tagByte3 != s1->tagByte3 ||
|
||||||
|
s0->tagByte4 != s1->tagByte4 ||
|
||||||
|
s0->tagByte5 != s1->tagByte5 ||
|
||||||
|
s0->tagByte6 != s1->tagByte6 ||
|
||||||
|
s0->tagByte7 != s1->tagByte7 ||
|
||||||
|
s0->ecc1[0] != s1->ecc1[0] ||
|
||||||
|
s0->ecc1[1] != s1->ecc1[1] ||
|
||||||
|
s0->ecc1[2] != s1->ecc1[2] ||
|
||||||
|
s0->ecc2[0] != s1->ecc2[0] ||
|
||||||
|
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* NOTYET */
|
||||||
|
|
||||||
|
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_ExtendedTags *
|
||||||
|
eTags)
|
||||||
|
{
|
||||||
|
yaffs_Spare spare;
|
||||||
|
yaffs_Tags tags;
|
||||||
|
|
||||||
|
yaffs_SpareInitialise(&spare);
|
||||||
|
|
||||||
|
if (eTags->chunkDeleted) {
|
||||||
|
spare.pageStatus = 0;
|
||||||
|
} else {
|
||||||
|
tags.objectId = eTags->objectId;
|
||||||
|
tags.chunkId = eTags->chunkId;
|
||||||
|
tags.byteCount = eTags->byteCount;
|
||||||
|
tags.serialNumber = eTags->serialNumber;
|
||||||
|
|
||||||
|
if (!dev->useNANDECC && data) {
|
||||||
|
yaffs_CalcECC(data, &spare);
|
||||||
|
}
|
||||||
|
yaffs_LoadTagsIntoSpare(&spare, &tags);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
__u8 * data,
|
||||||
|
yaffs_ExtendedTags * eTags)
|
||||||
|
{
|
||||||
|
|
||||||
|
yaffs_Spare spare;
|
||||||
|
yaffs_Tags tags;
|
||||||
|
yaffs_ECCResult eccResult;
|
||||||
|
|
||||||
|
static yaffs_Spare spareFF;
|
||||||
|
static int init;
|
||||||
|
|
||||||
|
if (!init) {
|
||||||
|
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yaffs_ReadChunkFromNAND
|
||||||
|
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
|
||||||
|
/* eTags may be NULL */
|
||||||
|
if (eTags) {
|
||||||
|
|
||||||
|
int deleted =
|
||||||
|
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
|
||||||
|
|
||||||
|
eTags->chunkDeleted = deleted;
|
||||||
|
eTags->eccResult = eccResult;
|
||||||
|
eTags->blockBad = 0; /* We're reading it */
|
||||||
|
/* therefore it is not a bad block */
|
||||||
|
eTags->chunkUsed =
|
||||||
|
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
|
||||||
|
0) ? 1 : 0;
|
||||||
|
|
||||||
|
if (eTags->chunkUsed) {
|
||||||
|
yaffs_GetTagsFromSpare(dev, &spare, &tags);
|
||||||
|
|
||||||
|
eTags->objectId = tags.objectId;
|
||||||
|
eTags->chunkId = tags.chunkId;
|
||||||
|
eTags->byteCount = tags.byteCount;
|
||||||
|
eTags->serialNumber = tags.serialNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YAFFS_OK;
|
||||||
|
} else {
|
||||||
|
return YAFFS_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockInNAND)
|
||||||
|
{
|
||||||
|
|
||||||
|
yaffs_Spare spare;
|
||||||
|
|
||||||
|
memset(&spare, 0xff, sizeof(yaffs_Spare));
|
||||||
|
|
||||||
|
spare.blockStatus = 'Y';
|
||||||
|
|
||||||
|
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
|
||||||
|
&spare);
|
||||||
|
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
|
||||||
|
NULL, &spare);
|
||||||
|
|
||||||
|
return YAFFS_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockNo, yaffs_BlockState *
|
||||||
|
state,
|
||||||
|
int *sequenceNumber)
|
||||||
|
{
|
||||||
|
|
||||||
|
yaffs_Spare spare0, spare1;
|
||||||
|
static yaffs_Spare spareFF;
|
||||||
|
static int init;
|
||||||
|
yaffs_ECCResult dummy;
|
||||||
|
|
||||||
|
if (!init) {
|
||||||
|
memset(&spareFF, 0xFF, sizeof(spareFF));
|
||||||
|
init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sequenceNumber = 0;
|
||||||
|
|
||||||
|
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
|
||||||
|
&spare0, &dummy, 1);
|
||||||
|
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
|
||||||
|
&spare1, &dummy, 1);
|
||||||
|
|
||||||
|
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
|
||||||
|
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||||
|
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
|
||||||
|
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||||
|
else
|
||||||
|
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||||
|
|
||||||
|
return YAFFS_OK;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFS_TAGSCOMPAT_H__
|
||||||
|
#define __YAFFS_TAGSCOMPAT_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
const __u8 * data,
|
||||||
|
const yaffs_ExtendedTags *
|
||||||
|
tags);
|
||||||
|
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
|
||||||
|
int chunkInNAND,
|
||||||
|
__u8 * data,
|
||||||
|
yaffs_ExtendedTags *
|
||||||
|
tags);
|
||||||
|
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockNo);
|
||||||
|
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
|
||||||
|
int blockNo, yaffs_BlockState *
|
||||||
|
state, int *sequenceNumber);
|
||||||
|
|
||||||
|
void yaffs_CalcTagsECC(yaffs_Tags * tags);
|
||||||
|
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
|
||||||
|
int yaffs_CountBits(__u8 byte);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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 "yaffs_tagsvalidity.h"
|
||||||
|
|
||||||
|
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
memset(tags, 0, sizeof(yaffs_ExtendedTags));
|
||||||
|
tags->validMarker0 = 0xAAAAAAAA;
|
||||||
|
tags->validMarker1 = 0x55555555;
|
||||||
|
}
|
||||||
|
|
||||||
|
int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
|
||||||
|
{
|
||||||
|
return (tags->validMarker0 == 0xAAAAAAAA &&
|
||||||
|
tags->validMarker1 == 0x55555555);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __YAFFS_TAGS_VALIDITY_H__
|
||||||
|
#define __YAFFS_TAGS_VALIDITY_H__
|
||||||
|
|
||||||
|
#include "yaffs_guts.h"
|
||||||
|
|
||||||
|
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
|
||||||
|
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
|
||||||
|
#endif
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __YAFFSINTERFACE_H__
|
||||||
|
#define __YAFFSINTERFACE_H__
|
||||||
|
|
||||||
|
int yaffs_Initialise(unsigned nBlocks);
|
||||||
|
|
||||||
|
#endif
|
187
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yportenv.h
Normal file
187
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yportenv.h
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||||
|
* for Toby Churchill Ltd and Brightstar Engineering
|
||||||
|
*
|
||||||
|
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __YPORTENV_H__
|
||||||
|
#define __YPORTENV_H__
|
||||||
|
|
||||||
|
#if defined CONFIG_YAFFS_WINCE
|
||||||
|
|
||||||
|
#include "ywinceenv.h"
|
||||||
|
|
||||||
|
#elif defined __KERNEL__
|
||||||
|
|
||||||
|
#include "moduleconfig.h"
|
||||||
|
|
||||||
|
/* Linux kernel */
|
||||||
|
#include <linux/version.h>
|
||||||
|
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
|
||||||
|
#include <linux/config.h>
|
||||||
|
#endif
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
|
#define YCHAR char
|
||||||
|
#define YUCHAR unsigned char
|
||||||
|
#define _Y(x) x
|
||||||
|
#define yaffs_strcpy(a,b) strcpy(a,b)
|
||||||
|
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
|
||||||
|
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
|
||||||
|
#define yaffs_strlen(s) strlen(s)
|
||||||
|
#define yaffs_sprintf sprintf
|
||||||
|
#define yaffs_toupper(a) toupper(a)
|
||||||
|
|
||||||
|
#define Y_INLINE inline
|
||||||
|
|
||||||
|
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||||
|
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||||
|
|
||||||
|
/* #define YPRINTF(x) printk x */
|
||||||
|
#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
|
||||||
|
#define YFREE(x) kfree(x)
|
||||||
|
#define YMALLOC_ALT(x) vmalloc(x)
|
||||||
|
#define YFREE_ALT(x) vfree(x)
|
||||||
|
#define YMALLOC_DMA(x) YMALLOC(x)
|
||||||
|
|
||||||
|
// KR - added for use in scan so processes aren't blocked indefinitely.
|
||||||
|
#define YYIELD() schedule()
|
||||||
|
|
||||||
|
#define YAFFS_ROOT_MODE 0666
|
||||||
|
#define YAFFS_LOSTNFOUND_MODE 0666
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
|
||||||
|
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
|
||||||
|
#define Y_TIME_CONVERT(x) (x).tv_sec
|
||||||
|
#else
|
||||||
|
#define Y_CURRENT_TIME CURRENT_TIME
|
||||||
|
#define Y_TIME_CONVERT(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define yaffs_SumCompare(x,y) ((x) == (y))
|
||||||
|
#define yaffs_strcmp(a,b) strcmp(a,b)
|
||||||
|
|
||||||
|
#define TENDSTR "\n"
|
||||||
|
#define TSTR(x) KERN_WARNING x
|
||||||
|
#define TOUT(p) printk p
|
||||||
|
|
||||||
|
#define yaffs_trace(mask, fmt, args...) \
|
||||||
|
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
|
||||||
|
printk(KERN_WARNING "yaffs: " fmt, ## args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define compile_time_assertion(assertion) \
|
||||||
|
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
|
||||||
|
|
||||||
|
#elif defined CONFIG_YAFFS_DIRECT
|
||||||
|
|
||||||
|
/* Direct interface */
|
||||||
|
#include "ydirectenv.h"
|
||||||
|
|
||||||
|
#elif defined CONFIG_YAFFS_UTIL
|
||||||
|
|
||||||
|
/* Stuff for YAFFS utilities */
|
||||||
|
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#include "devextras.h"
|
||||||
|
|
||||||
|
#define YMALLOC(x) malloc(x)
|
||||||
|
#define YFREE(x) free(x)
|
||||||
|
#define YMALLOC_ALT(x) malloc(x)
|
||||||
|
#define YFREE_ALT(x) free(x)
|
||||||
|
|
||||||
|
#define YCHAR char
|
||||||
|
#define YUCHAR unsigned char
|
||||||
|
#define _Y(x) x
|
||||||
|
#define yaffs_strcpy(a,b) strcpy(a,b)
|
||||||
|
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
|
||||||
|
#define yaffs_strlen(s) strlen(s)
|
||||||
|
#define yaffs_sprintf sprintf
|
||||||
|
#define yaffs_toupper(a) toupper(a)
|
||||||
|
|
||||||
|
#define Y_INLINE inline
|
||||||
|
|
||||||
|
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
|
||||||
|
/* #define YALERT(s) YINFO(s) */
|
||||||
|
|
||||||
|
#define TENDSTR "\n"
|
||||||
|
#define TSTR(x) x
|
||||||
|
#define TOUT(p) printf p
|
||||||
|
|
||||||
|
#define YAFFS_LOSTNFOUND_NAME "lost+found"
|
||||||
|
#define YAFFS_LOSTNFOUND_PREFIX "obj"
|
||||||
|
/* #define YPRINTF(x) printf x */
|
||||||
|
|
||||||
|
#define YAFFS_ROOT_MODE 0666
|
||||||
|
#define YAFFS_LOSTNFOUND_MODE 0666
|
||||||
|
|
||||||
|
#define yaffs_SumCompare(x,y) ((x) == (y))
|
||||||
|
#define yaffs_strcmp(a,b) strcmp(a,b)
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* Should have specified a configuration type */
|
||||||
|
#error Unknown configuration
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* see yaffs_fs.c */
|
||||||
|
extern unsigned int yaffs_traceMask;
|
||||||
|
extern unsigned int yaffs_wr_attempts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tracing flags.
|
||||||
|
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define YAFFS_TRACE_OS 0x00000002
|
||||||
|
#define YAFFS_TRACE_ALLOCATE 0x00000004
|
||||||
|
#define YAFFS_TRACE_SCAN 0x00000008
|
||||||
|
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
|
||||||
|
#define YAFFS_TRACE_ERASE 0x00000020
|
||||||
|
#define YAFFS_TRACE_GC 0x00000040
|
||||||
|
#define YAFFS_TRACE_WRITE 0x00000080
|
||||||
|
#define YAFFS_TRACE_TRACING 0x00000100
|
||||||
|
#define YAFFS_TRACE_DELETION 0x00000200
|
||||||
|
#define YAFFS_TRACE_BUFFERS 0x00000400
|
||||||
|
#define YAFFS_TRACE_NANDACCESS 0x00000800
|
||||||
|
#define YAFFS_TRACE_GC_DETAIL 0x00001000
|
||||||
|
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
|
||||||
|
#define YAFFS_TRACE_MTD 0x00004000
|
||||||
|
#define YAFFS_TRACE_CHECKPOINT 0x00008000
|
||||||
|
|
||||||
|
#define YAFFS_TRACE_VERIFY 0x00010000
|
||||||
|
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
|
||||||
|
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
|
||||||
|
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
|
||||||
|
|
||||||
|
|
||||||
|
#define YAFFS_TRACE_ERROR 0x40000000
|
||||||
|
#define YAFFS_TRACE_BUG 0x80000000
|
||||||
|
#define YAFFS_TRACE_ALWAYS 0xF0000000
|
||||||
|
|
||||||
|
|
||||||
|
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
|
||||||
|
|
||||||
|
#ifndef CONFIG_YAFFS_WINCE
|
||||||
|
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Definitions for the GPIO buttons interface driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
|
||||||
|
*
|
||||||
|
* This file was based on: /include/linux/gpio_keys.h
|
||||||
|
* The original gpio_keys.h seems not to have a license.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GPIO_BUTTONS_H_
|
||||||
|
#define _GPIO_BUTTONS_H_
|
||||||
|
|
||||||
|
struct gpio_button {
|
||||||
|
int gpio; /* GPIO line number */
|
||||||
|
int active_low;
|
||||||
|
char *desc; /* button description */
|
||||||
|
int type; /* input event type (EV_KEY, EV_SW) */
|
||||||
|
int code; /* input event code (KEY_*, SW_*) */
|
||||||
|
int count;
|
||||||
|
int threshold; /* count threshold */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gpio_buttons_platform_data {
|
||||||
|
struct gpio_button *buttons;
|
||||||
|
int nbuttons; /* number of buttons */
|
||||||
|
int poll_interval; /* polling interval */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _GPIO_BUTTONS_H_ */
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _GPIODEV_H__
|
||||||
|
#define _GPIODEV_H__
|
||||||
|
|
||||||
|
#define IOC_GPIODEV_MAGIC 'B'
|
||||||
|
#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
|
||||||
|
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
|
||||||
|
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
|
||||||
|
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
|
||||||
|
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* spi_gpio interface to platform code
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Piotr Skamruk
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef _LINUX_SPI_SPI_GPIO
|
||||||
|
#define _LINUX_SPI_SPI_GPIO
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
|
||||||
|
* This structure holds information about a GPIO-based SPI device.
|
||||||
|
*
|
||||||
|
* @pin_clk: The GPIO pin number of the CLOCK pin.
|
||||||
|
*
|
||||||
|
* @pin_miso: The GPIO pin number of the MISO pin.
|
||||||
|
*
|
||||||
|
* @pin_mosi: The GPIO pin number of the MOSI pin.
|
||||||
|
*
|
||||||
|
* @pin_cs: The GPIO pin number of the CHIPSELECT pin.
|
||||||
|
*
|
||||||
|
* @cs_activelow: If true, the chip is selected when the CS line is low.
|
||||||
|
*
|
||||||
|
* @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
|
||||||
|
* Note that doing no delay is not standards compliant,
|
||||||
|
* but it might be needed to speed up transfers on some
|
||||||
|
* slow embedded machines.
|
||||||
|
*
|
||||||
|
* @boardinfo_setup: This callback is called after the
|
||||||
|
* SPI master device was registered, but before the
|
||||||
|
* device is registered.
|
||||||
|
* @boardinfo_setup_data: Data argument passed to boardinfo_setup().
|
||||||
|
*/
|
||||||
|
struct spi_gpio_platform_data {
|
||||||
|
unsigned int pin_clk;
|
||||||
|
unsigned int pin_miso;
|
||||||
|
unsigned int pin_mosi;
|
||||||
|
unsigned int pin_cs;
|
||||||
|
bool cs_activelow;
|
||||||
|
bool no_spi_delay;
|
||||||
|
int (*boardinfo_setup)(struct spi_board_info *bi,
|
||||||
|
struct spi_master *master,
|
||||||
|
void *data);
|
||||||
|
void *boardinfo_setup_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_SPI_SPI_GPIO */
|
|
@ -77,7 +77,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
|
||||||
+ .hook = imq_nf_hook,
|
+ .hook = imq_nf_hook,
|
||||||
+ .owner = THIS_MODULE,
|
+ .owner = THIS_MODULE,
|
||||||
+ .pf = PF_INET,
|
+ .pf = PF_INET,
|
||||||
+ .hooknum = NF_IP_PRE_ROUTING,
|
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||||
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
|
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
|
||||||
+ .priority = NF_IP_PRI_MANGLE + 1
|
+ .priority = NF_IP_PRI_MANGLE + 1
|
||||||
+#else
|
+#else
|
||||||
|
@ -89,7 +89,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
|
||||||
+ .hook = imq_nf_hook,
|
+ .hook = imq_nf_hook,
|
||||||
+ .owner = THIS_MODULE,
|
+ .owner = THIS_MODULE,
|
||||||
+ .pf = PF_INET,
|
+ .pf = PF_INET,
|
||||||
+ .hooknum = NF_IP_POST_ROUTING,
|
+ .hooknum = NF_INET_POST_ROUTING,
|
||||||
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
|
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
|
||||||
+ .priority = NF_IP_PRI_LAST
|
+ .priority = NF_IP_PRI_LAST
|
||||||
+#else
|
+#else
|
||||||
|
@ -102,7 +102,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
|
||||||
+ .hook = imq_nf_hook,
|
+ .hook = imq_nf_hook,
|
||||||
+ .owner = THIS_MODULE,
|
+ .owner = THIS_MODULE,
|
||||||
+ .pf = PF_INET6,
|
+ .pf = PF_INET6,
|
||||||
+ .hooknum = NF_IP6_PRE_ROUTING,
|
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||||
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
|
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
|
||||||
+ .priority = NF_IP6_PRI_MANGLE + 1
|
+ .priority = NF_IP6_PRI_MANGLE + 1
|
||||||
+#else
|
+#else
|
||||||
|
@ -114,7 +114,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
|
||||||
+ .hook = imq_nf_hook,
|
+ .hook = imq_nf_hook,
|
||||||
+ .owner = THIS_MODULE,
|
+ .owner = THIS_MODULE,
|
||||||
+ .pf = PF_INET6,
|
+ .pf = PF_INET6,
|
||||||
+ .hooknum = NF_IP6_POST_ROUTING,
|
+ .hooknum = NF_INET_POST_ROUTING,
|
||||||
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
|
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
|
||||||
+ .priority = NF_IP6_PRI_LAST
|
+ .priority = NF_IP6_PRI_LAST
|
||||||
+#else
|
+#else
|
||||||
|
@ -735,7 +735,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/Kconfig
|
||||||
|
|
||||||
+config IP_NF_TARGET_IMQ
|
+config IP_NF_TARGET_IMQ
|
||||||
+ tristate "IMQ target support"
|
+ tristate "IMQ target support"
|
||||||
+ depends on IP_NF_MANGLE
|
+ depends on IP_NF_MANGLE && IMQ
|
||||||
+ help
|
+ help
|
||||||
+ This option adds a `IMQ' target which is used to specify if and
|
+ This option adds a `IMQ' target which is used to specify if and
|
||||||
+ to which IMQ device packets should get enqueued/dequeued.
|
+ to which IMQ device packets should get enqueued/dequeued.
|
||||||
|
|
|
@ -1340,7 +1340,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/nf_nat_rtsp.c
|
||||||
+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
|
+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
|
||||||
+ mr.range[0].min_ip = mr.range[0].max_ip = newip;
|
+ mr.range[0].min_ip = mr.range[0].max_ip = newip;
|
||||||
+
|
+
|
||||||
+ nf_nat_setup_info(ct, &mr.range[0], NF_INET_PRE_ROUTING);
|
+ nf_nat_setup_info(ct, &mr.range[0], IP_NAT_MANIP_DST);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
|
|
27
target/linux/generic-2.6/patches-2.6.25/420-gpiodev.patch
Normal file
27
target/linux/generic-2.6/patches-2.6.25/420-gpiodev.patch
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Index: linux-2.6.25/drivers/gpio/Kconfig
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.orig/drivers/gpio/Kconfig 2008-04-27 23:35:57.000000000 +0100
|
||||||
|
+++ linux-2.6.25/drivers/gpio/Kconfig 2008-04-27 23:42:52.000000000 +0100
|
||||||
|
@@ -2,6 +2,13 @@
|
||||||
|
# GPIO infrastructure and expanders
|
||||||
|
#
|
||||||
|
|
||||||
|
+config GPIO_DEVICE
|
||||||
|
+ tristate "GPIO device support"
|
||||||
|
+ depends on GENERIC_GPIO
|
||||||
|
+ help
|
||||||
|
+ Say Y to enable Linux GPIO device support. This allows control of
|
||||||
|
+ GPIO pins using a character device
|
||||||
|
+
|
||||||
|
config HAVE_GPIO_LIB
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Index: linux-2.6.25/drivers/gpio/Makefile
|
||||||
|
===================================================================
|
||||||
|
--- linux-2.6.25.orig/drivers/gpio/Makefile 2008-04-27 23:42:59.000000000 +0100
|
||||||
|
+++ linux-2.6.25/drivers/gpio/Makefile 2008-04-27 23:43:41.000000000 +0100
|
||||||
|
@@ -7,3 +7,4 @@ obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o
|
||||||
|
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
|
||||||
|
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
|
||||||
|
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
|
||||||
|
+obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
|
Loading…
Reference in a new issue