summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/sleep/main.c67
-rw-r--r--drivers/acpi/sleep/proc.c2
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/ata/libata-core.c8
-rw-r--r--drivers/base/devres.c32
-rw-r--r--drivers/base/platform.c2
-rw-r--r--drivers/base/topology.c3
-rw-r--r--drivers/block/loop.c6
-rw-r--r--drivers/block/nbd.c15
-rw-r--r--drivers/block/rd.c2
-rw-r--r--drivers/char/Kconfig3
-rw-r--r--drivers/char/drm/drm_dma.c2
-rw-r--r--drivers/char/drm/drm_vm.c2
-rw-r--r--drivers/char/drm/r300_reg.h2
-rw-r--r--drivers/char/genrtc.c4
-rw-r--r--drivers/char/hw_random/Kconfig14
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/pasemi-rng.c156
-rw-r--r--drivers/char/mmtimer.c4
-rw-r--r--drivers/char/pcmcia/Kconfig1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c46
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c7
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tty_io.c22
-rw-r--r--drivers/cpufreq/cpufreq.c3
-rw-r--r--drivers/cpufreq/cpufreq_stats.c2
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/hwmon/coretemp.c2
-rw-r--r--drivers/i2c/chips/tps65010.c2
-rw-r--r--drivers/ide/pci/siimage.c2
-rw-r--r--drivers/ieee1394/nodemgr.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c6
-rw-r--r--drivers/isdn/capi/Kconfig2
-rw-r--r--drivers/isdn/hardware/eicon/divasync.h2
-rw-r--r--drivers/isdn/hisax/hfc_usb.c4
-rw-r--r--drivers/kvm/kvm_main.c3
-rw-r--r--drivers/leds/leds-h1940.c2
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/mca/mca-bus.c28
-rw-r--r--drivers/mca/mca-driver.c13
-rw-r--r--drivers/md/Kconfig9
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/dm-bio-list.h26
-rw-r--r--drivers/md/dm-crypt.c91
-rw-r--r--drivers/md/dm-delay.c383
-rw-r--r--drivers/md/dm-exception-store.c54
-rw-r--r--drivers/md/dm-hw-handler.h1
-rw-r--r--drivers/md/dm-io.c232
-rw-r--r--drivers/md/dm-io.h83
-rw-r--r--drivers/md/dm-log.c77
-rw-r--r--drivers/md/dm-mpath.c3
-rw-r--r--drivers/md/dm-raid1.c187
-rw-r--r--drivers/md/dm-table.c10
-rw-r--r--drivers/md/dm.c1
-rw-r--r--drivers/md/kcopyd.c28
-rw-r--r--drivers/md/md.c186
-rw-r--r--drivers/md/raid1.c1
-rw-r--r--drivers/md/raid5.c6
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c2
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c2
-rw-r--r--drivers/media/dvb/frontends/tda10021.c2
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/video/pwc/philips.txt6
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt2
-rw-r--r--drivers/message/fusion/mptbase.c2
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mtd/chips/Kconfig40
-rw-r--r--drivers/mtd/chips/Makefile4
-rw-r--r--drivers/mtd/chips/amd_flash.c1396
-rw-r--r--drivers/mtd/chips/jedec.c935
-rw-r--r--drivers/mtd/chips/sharp.c601
-rw-r--r--drivers/mtd/devices/block2mtd.c2
-rw-r--r--drivers/mtd/maps/Kconfig18
-rw-r--r--drivers/mtd/maps/Makefile2
-rw-r--r--drivers/mtd/maps/arctic-mtd.c145
-rw-r--r--drivers/mtd/maps/beech-mtd.c122
-rw-r--r--drivers/mtd/maps/nettel.c2
-rw-r--r--drivers/mtd/maps/physmap_of.c2
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--drivers/mtd/nand/Kconfig21
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/at91_nand.c10
-rw-r--r--drivers/mtd/nand/cafe_ecc.c1381
-rw-r--r--drivers/mtd/nand/cafe_nand.c (renamed from drivers/mtd/nand/cafe.c)137
-rw-r--r--drivers/mtd/nand/nand_base.c11
-rw-r--r--drivers/mtd/nand/plat_nand.c150
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/net/3c509.c5
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/atp.c8
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/e1000/e1000_main.c2
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/epic100.c10
-rw-r--r--drivers/net/hamradio/Kconfig2
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/ixgb/ixgb_ee.c2
-rw-r--r--drivers/net/meth.h2
-rw-r--r--drivers/net/natsemi.c1
-rw-r--r--drivers/net/ne2k-pci.c3
-rw-r--r--drivers/net/phy/phy.c6
-rw-r--r--drivers/net/sundance.c3
-rw-r--r--drivers/net/tg3.c11
-rw-r--r--drivers/net/tg3.h2
-rw-r--r--drivers/net/tulip/interrupt.c2
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c2
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/wireless/airport.c2
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.c4
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h2
-rw-r--r--drivers/net/yellowfin.c1
-rw-r--r--drivers/pci/pci-driver.c2
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/rtc-sh.c8
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/net/qeth_main.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c2
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c2
-rw-r--r--drivers/scsi/aic94xx/Makefile2
-rw-r--r--drivers/scsi/dc395x.c6
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/spi/atmel_spi.c5
-rw-r--r--drivers/usb/atm/usbatm.c2
-rw-r--r--drivers/usb/misc/auerswald.c2
-rw-r--r--drivers/usb/net/usbnet.h2
-rw-r--r--drivers/usb/serial/Kconfig2
-rw-r--r--drivers/usb/serial/aircable.c4
-rw-r--r--drivers/usb/serial/io_edgeport.c4
-rw-r--r--drivers/video/Kconfig28
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/arkfb.c1200
-rw-r--r--drivers/video/console/softcursor.c2
-rw-r--r--drivers/video/fbmem.c4
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c2
-rw-r--r--drivers/video/matrox/matroxfb_accel.c2
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/matrox/matroxfb_misc.c2
-rw-r--r--drivers/video/nvidia/nv_hw.c7
-rw-r--r--drivers/video/nvidia/nvidia.c1
-rw-r--r--drivers/video/s3fb.c19
-rw-r--r--drivers/video/skeletonfb.c2
-rw-r--r--drivers/video/svgalib.c17
-rw-r--r--drivers/video/vt8623fb.c927
153 files changed, 3939 insertions, 5296 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index f8c63410bcbf..52b23471dd69 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -29,7 +29,6 @@ static u32 acpi_suspend_states[] = {
[PM_SUSPEND_ON] = ACPI_STATE_S0,
[PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
[PM_SUSPEND_MEM] = ACPI_STATE_S3,
- [PM_SUSPEND_DISK] = ACPI_STATE_S4,
[PM_SUSPEND_MAX] = ACPI_STATE_S5
};
@@ -94,14 +93,6 @@ static int acpi_pm_enter(suspend_state_t pm_state)
do_suspend_lowlevel();
break;
- case PM_SUSPEND_DISK:
- if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
- status = acpi_enter_sleep_state(acpi_state);
- break;
- case PM_SUSPEND_MAX:
- acpi_power_off();
- break;
-
default:
return -EINVAL;
}
@@ -157,12 +148,13 @@ int acpi_suspend(u32 acpi_state)
suspend_state_t states[] = {
[1] = PM_SUSPEND_STANDBY,
[3] = PM_SUSPEND_MEM,
- [4] = PM_SUSPEND_DISK,
[5] = PM_SUSPEND_MAX
};
if (acpi_state < 6 && states[acpi_state])
return pm_suspend(states[acpi_state]);
+ if (acpi_state == 4)
+ return hibernate();
return -EINVAL;
}
@@ -189,6 +181,49 @@ static struct pm_ops acpi_pm_ops = {
.finish = acpi_pm_finish,
};
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static int acpi_hibernation_prepare(void)
+{
+ return acpi_sleep_prepare(ACPI_STATE_S4);
+}
+
+static int acpi_hibernation_enter(void)
+{
+ acpi_status status = AE_OK;
+ unsigned long flags = 0;
+
+ ACPI_FLUSH_CPU_CACHE();
+
+ local_irq_save(flags);
+ acpi_enable_wakeup_device(ACPI_STATE_S4);
+ /* This shouldn't return. If it returns, we have a problem */
+ status = acpi_enter_sleep_state(ACPI_STATE_S4);
+ local_irq_restore(flags);
+
+ return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_finish(void)
+{
+ acpi_leave_sleep_state(ACPI_STATE_S4);
+ acpi_disable_wakeup_device(ACPI_STATE_S4);
+
+ /* reset firmware waking vector */
+ acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ if (init_8259A_after_S1) {
+ printk("Broken toshiba laptop -> kicking interrupts\n");
+ init_8259A(0);
+ }
+}
+
+static struct hibernation_ops acpi_hibernation_ops = {
+ .prepare = acpi_hibernation_prepare,
+ .enter = acpi_hibernation_enter,
+ .finish = acpi_hibernation_finish,
+};
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
/*
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
@@ -227,14 +262,18 @@ int __init acpi_sleep_init(void)
sleep_states[i] = 1;
printk(" S%d", i);
}
- if (i == ACPI_STATE_S4) {
- if (sleep_states[i])
- acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
- }
}
printk(")\n");
pm_set_ops(&acpi_pm_ops);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+ if (sleep_states[ACPI_STATE_S4])
+ hibernation_set_ops(&acpi_hibernation_ops);
+#else
+ sleep_states[ACPI_STATE_S4] = 0;
+#endif
+
return 0;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 5a76e5be61d5..76b45f0b8341 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -60,7 +60,7 @@ acpi_system_write_sleep(struct file *file,
state = simple_strtoul(str, NULL, 0);
#ifdef CONFIG_SOFTWARE_SUSPEND
if (state == 4) {
- error = pm_suspend(PM_SUSPEND_DISK);
+ error = hibernate();
goto Done;
}
#endif
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 45dbdc14915f..c7219663f2b9 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -435,7 +435,7 @@ config PATA_OPTIDMA
help
This option enables DMA/PIO support for the later OPTi
controllers found on some old motherboards and in some
- latops
+ laptops.
If unsure, say N.
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index a7950885d18e..fef87dd70d17 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1316,7 +1316,7 @@ void ata_port_flush_task(struct ata_port *ap)
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
- flush_workqueue(ata_wq);
+ cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */
/*
* At this point, if a task is running, it's guaranteed to see
@@ -1327,7 +1327,7 @@ void ata_port_flush_task(struct ata_port *ap)
if (ata_msg_ctl(ap))
ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
__FUNCTION__);
- flush_workqueue(ata_wq);
+ cancel_work_sync(&ap->port_task.work);
}
spin_lock_irqsave(ap->lock, flags);
@@ -6475,9 +6475,9 @@ void ata_port_detach(struct ata_port *ap)
/* Flush hotplug task. The sequence is similar to
* ata_port_flush_task().
*/
- flush_workqueue(ata_aux_wq);
+ cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */
cancel_delayed_work(&ap->hotplug_task);
- flush_workqueue(ata_aux_wq);
+ cancel_work_sync(&ap->hotplug_task.work);
skip_eh:
/* remove the associated SCSI host */
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index e177c9533b6c..e1c0730a3b99 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -101,19 +101,6 @@ static void add_dr(struct device *dev, struct devres_node *node)
list_add_tail(&node->entry, &dev->devres_head);
}
-/**
- * devres_alloc - Allocate device resource data
- * @release: Release function devres will be associated with
- * @size: Allocation size
- * @gfp: Allocation flags
- *
- * allocate devres of @size bytes. The allocated area is zeroed, then
- * associated with @release. The returned pointer can be passed to
- * other devres_*() functions.
- *
- * RETURNS:
- * Pointer to allocated devres on success, NULL on failure.
- */
#ifdef CONFIG_DEBUG_DEVRES
void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
const char *name)
@@ -128,6 +115,19 @@ void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
}
EXPORT_SYMBOL_GPL(__devres_alloc);
#else
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * Allocate devres of @size bytes. The allocated area is zeroed, then
+ * associated with @release. The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
{
struct devres *dr;
@@ -416,7 +416,7 @@ static int release_nodes(struct device *dev, struct list_head *first,
}
/**
- * devres_release_all - Release all resources
+ * devres_release_all - Release all managed resources
* @dev: Device to release resources for
*
* Release all resources associated with @dev. This function is
@@ -600,7 +600,7 @@ static int devm_kzalloc_match(struct device *dev, void *res, void *data)
}
/**
- * devm_kzalloc - Managed kzalloc
+ * devm_kzalloc - Resource-managed kzalloc
* @dev: Device to allocate memory for
* @size: Allocation size
* @gfp: Allocation gfp flags
@@ -628,7 +628,7 @@ void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
EXPORT_SYMBOL_GPL(devm_kzalloc);
/**
- * devm_kfree - Managed kfree
+ * devm_kfree - Resource-managed kfree
* @dev: Device this memory belongs to
* @p: Memory to free
*
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index eb84d9d44645..869ff8c00146 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -360,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
* This function creates a simple platform device that requires minimal
* resource and memory management. Canned release function freeing
* memory allocated for the device allows drivers using such devices
- * to be unloaded iwithout waiting for the last reference to the device
+ * to be unloaded without waiting for the last reference to the device
* to be dropped.
*
* This interface is primarily intended for use with legacy drivers
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 067a9e8bc377..8d8cdfec6529 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -126,10 +126,13 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
rc = topology_add_dev(cpu);
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
topology_remove_dev(cpu);
break;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index af6d7274a7cc..18cdd8c77626 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -243,17 +243,13 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
transfer_result = lo_do_transfer(lo, WRITE, page, offset,
bvec->bv_page, bv_offs, size, IV);
if (unlikely(transfer_result)) {
- char *kaddr;
-
/*
* The transfer failed, but we still write the data to
* keep prepare/commit calls balanced.
*/
printk(KERN_ERR "loop: transfer error block %llu\n",
(unsigned long long)index);
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, size);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, size, KM_USER0);
}
flush_dcache_page(page);
ret = aops->commit_write(file, page, offset,
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 090796bef78f..069ae39a9cd9 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -366,20 +366,25 @@ static struct disk_attribute pid_attr = {
.show = pid_show,
};
-static void nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *lo)
{
struct request *req;
+ int ret;
BUG_ON(lo->magic != LO_MAGIC);
lo->pid = current->pid;
- sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+ ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+ if (ret) {
+ printk(KERN_ERR "nbd: sysfs_create_file failed!");
+ return ret;
+ }
while ((req = nbd_read_stat(lo)) != NULL)
nbd_end_request(req);
sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
- return;
+ return 0;
}
static void nbd_clear_que(struct nbd_device *lo)
@@ -569,7 +574,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
case NBD_DO_IT:
if (!lo->file)
return -EINVAL;
- nbd_do_it(lo);
+ error = nbd_do_it(lo);
+ if (error)
+ return error;
/* on return tidy up in case we have a signal */
/* Forcibly shutdown the socket causing all listeners
* to error
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 43d4ebcb3b44..a1512da32410 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -151,7 +151,7 @@ static int ramdisk_commit_write(struct file *file, struct page *page,
}
/*
- * ->writepage to the the blockdev's mapping has to redirty the page so that the
+ * ->writepage to the blockdev's mapping has to redirty the page so that the
* VM doesn't go and steal it. We return AOP_WRITEPAGE_ACTIVATE so that the VM
* won't try to (pointlessly) write the page again for a while.
*
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1e32fb834eb8..2df42fdcdc91 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -631,7 +631,8 @@ config HVC_CONSOLE
config HVC_ISERIES
bool "iSeries Hypervisor Virtual Console support"
- depends on PPC_ISERIES && !VIOCONS
+ depends on PPC_ISERIES
+ default y
select HVC_DRIVER
help
iSeries machines support a hypervisor virtual console.
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 892db7096986..32ed19c9ec1c 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -65,7 +65,7 @@ int drm_dma_setup(drm_device_t * dev)
* \param dev DRM device.
*
* Free all pages associated with DMA buffers, the buffers and pages lists, and
- * finally the the drm_device::dma structure itself.
+ * finally the drm_device::dma structure itself.
*/
void drm_dma_takedown(drm_device_t * dev)
{
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 35540cfb43dd..b5c5b9fa84c3 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -157,7 +157,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
* \param address access address.
* \return pointer to the page structure.
*
- * Get the the mapping, find the real physical page to map, get the page, and
+ * Get the mapping, find the real physical page to map, get the page, and
* return it.
*/
static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index a881f96c983e..ecda760ae8c0 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -293,7 +293,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0
# define R300_PVS_CNTL_1_POS_END_SHIFT 10
# define R300_PVS_CNTL_1_PROGRAM_END_SHIFT 20
-/* Addresses are relative the the vertex program parameters area. */
+/* Addresses are relative to the vertex program parameters area. */
#define R300_VAP_PVS_CNTL_2 0x22D4
# define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
# define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT 16
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 49f914e79216..9e1fc02967ff 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -12,7 +12,7 @@
*
* This driver allows use of the real time clock (built into
* nearly all computers) from user space. It exports the /dev/rtc
- * interface supporting various ioctl() and also the /proc/dev/rtc
+ * interface supporting various ioctl() and also the /proc/driver/rtc
* pseudo-file for status information.
*
* The ioctls can be used to set the interrupt behaviour where
@@ -377,7 +377,7 @@ static int gen_rtc_release(struct inode *inode, struct file *file)
#ifdef CONFIG_PROC_FS
/*
- * Info exported via "/proc/rtc".
+ * Info exported via "/proc/driver/rtc".
*/
static int gen_rtc_proc_output(char *buf)
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5f3acd8e64b8..7cda04b33534 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -91,3 +91,17 @@ config HW_RANDOM_OMAP
module will be called omap-rng.
If unsure, say Y.
+
+config HW_RANDOM_PASEMI
+ tristate "PA Semi HW Random Number Generator support"
+ depends on HW_RANDOM && PPC_PASEMI
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on PA6T-1682M processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pasemi-rng.
+
+ If unsure, say Y.
+
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c41fa19454e3..c8b7300e2fb1 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644
index 000000000000..fa6040b6c8f2
--- /dev/null
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip rng
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+
+#define SDCRNG_CTL_REG 0x00
+#define SDCRNG_CTL_FVLD_M 0x0000f000
+#define SDCRNG_CTL_FVLD_S 12
+#define SDCRNG_CTL_KSZ 0x00000800
+#define SDCRNG_CTL_RSRC_CRG 0x00000010
+#define SDCRNG_CTL_RSRC_RRG 0x00000000
+#define SDCRNG_CTL_CE 0x00000004
+#define SDCRNG_CTL_RE 0x00000002
+#define SDCRNG_CTL_DR 0x00000001
+#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
+#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
+#define SDCRNG_VAL_REG 0x20
+
+#define MODULE_NAME "pasemi_rng"
+
+static int pasemi_rng_data_present(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+
+ return (in_le32(rng_regs + SDCRNG_CTL_REG)
+ & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+}
+
+static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ *data = in_le32(rng_regs + SDCRNG_VAL_REG);
+ return 4;
+}
+
+static int pasemi_rng_init(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
+
+ return 0;
+}
+
+static void pasemi_rng_cleanup(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
+ out_le32(rng_regs + SDCRNG_CTL_REG,
+ in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
+}
+
+static struct hwrng pasemi_rng = {
+ .name = MODULE_NAME,
+ .init = pasemi_rng_init,
+ .cleanup = pasemi_rng_cleanup,
+ .data_present = pasemi_rng_data_present,
+ .data_read = pasemi_rng_data_read,
+};
+
+static int __devinit rng_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ void __iomem *rng_regs;
+ struct device_node *rng_np = ofdev->node;
+ struct resource res;
+ int err = 0;
+
+ err = of_address_to_resource(rng_np, 0, &res);
+ if (err)
+ return -ENODEV;
+
+ rng_regs = ioremap(res.start, 0x100);
+
+ if (!rng_regs)
+ return -ENOMEM;
+
+ pasemi_rng.priv = (unsigned long)rng_regs;
+
+ printk(KERN_INFO "Registering PA Semi RNG\n");
+
+ err = hwrng_register(&pasemi_rng);
+
+ if (err)
+ iounmap(rng_regs);
+
+ return err;
+}
+
+static int __devexit rng_remove(struct of_device *dev)
+{
+ void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
+
+ hwrng_unregister(&pasemi_rng);
+ iounmap(rng_regs);
+
+ return 0;
+}
+
+static struct of_device_id rng_match[] = {
+ {
+ .compatible = "1682m-rng",
+ },
+ {},
+};
+
+static struct of_platform_driver rng_driver = {
+ .name = "pasemi-rng",
+ .match_table = rng_match,
+ .probe = rng_probe,
+ .remove = rng_remove,
+};
+
+static int __init rng_init(void)
+{
+ return of_register_platform_driver(&rng_driver);
+}
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+ of_unregister_platform_driver(&rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index c09160383a53..6e55cfb9c65a 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -705,15 +705,13 @@ static int __init mmtimer_init(void)
maxn++;
/* Allocate list of node ptrs to mmtimer_t's */
- timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
if (timers == NULL) {
printk(KERN_ERR "%s: failed to allocate memory for device\n",
MMTIMER_NAME);
goto out3;
}
- memset(timers,0,(sizeof(mmtimer_t *)*maxn));
-
/* Allocate mmtimer_t's for each online node */
for_each_online_node(node) {
timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index 27c1179ee527..f25facd97bb4 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -21,6 +21,7 @@ config SYNCLINK_CS
config CARDMAN_4000
tristate "Omnikey Cardman 4000 support"
depends on PCMCIA
+ select BITREVERSE
help
Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
reader.
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e91b43a014b0..fee58e03dbe2 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
+#include <linux/bitrev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -194,41 +195,17 @@ static inline unsigned char xinb(unsigned short port)
}
#endif
-#define b_0000 15
-#define b_0001 14
-#define b_0010 13
-#define b_0011 12
-#define b_0100 11
-#define b_0101 10
-#define b_0110 9
-#define b_0111 8
-#define b_1000 7
-#define b_1001 6
-#define b_1010 5
-#define b_1011 4
-#define b_1100 3
-#define b_1101 2
-#define b_1110 1
-#define b_1111 0
-
-static unsigned char irtab[16] = {
- b_0000, b_1000, b_0100, b_1100,
- b_0010, b_1010, b_0110, b_1110,
- b_0001, b_1001, b_0101, b_1101,
- b_0011, b_1011, b_0111, b_1111
-};
+static inline unsigned char invert_revert(unsigned char ch)
+{
+ return bitrev8(~ch);
+}
static void str_invert_revert(unsigned char *b, int len)
{
int i;
for (i = 0; i < len; i++)
- b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
-}
-
-static unsigned char invert_revert(unsigned char ch)
-{
- return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+ b[i] = invert_revert(b[i]);
}
#define ATRLENCK(dev,pos) \
@@ -1114,7 +1091,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
/*
* wait for atr to become valid.
* note: it is important to lock this code. if we dont, the monitor
- * could be run between test_bit and the the call the sleep on the
+ * could be run between test_bit and the call to sleep on the
* atr-queue. if *then* the monitor detects atr valid, it will wake up
* any process on the atr-queue, *but* since we have been interrupted,
* we do not yet sleep on this queue. this would result in a missed
@@ -1881,8 +1858,11 @@ static int cm4000_probe(struct pcmcia_device *link)
init_waitqueue_head(&dev->readq);
ret = cm4000_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
"cmm%d", i);
@@ -1907,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
cm4000_release(link);
dev_table[devno] = NULL;
- kfree(dev);
+ kfree(dev);
class_device_destroy(cmm_class, MKDEV(major, devno));
@@ -1956,12 +1936,14 @@ static int __init cmm_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmm_class);
return major;
}
rc = pcmcia_register_driver(&cm4000_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmm_class);
return rc;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index f2e4ec4fd407..af88181a17f4 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -636,8 +636,11 @@ static int reader_probe(struct pcmcia_device *link)
setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
ret = reader_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
"cmx%d", i);
@@ -708,12 +711,14 @@ static int __init cm4040_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmx_class);
return major;
}
rc = pcmcia_register_driver(&reader_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmx_class);
return rc;
}
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index fe00c7dfb649..11089be0691b 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -33,7 +33,7 @@ config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on TCG_TPM && PNPACPI
---help---
- If you have a TPM security chip from National Semicondutor
+ If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
compile this driver as a module, choose M here; the module
will be called tpm_nsc.
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7710a6a77d97..fc662e4ce58a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -934,13 +934,6 @@ restart:
return -EINVAL;
/*
- * No more input please, we are switching. The new ldisc
- * will update this value in the ldisc open function
- */
-
- tty->receive_room = 0;
-
- /*
* Problem: What do we do if this blocks ?
*/
@@ -951,6 +944,13 @@ restart:
return 0;
}
+ /*
+ * No more input please, we are switching. The new ldisc
+ * will update this value in the ldisc open function
+ */
+
+ tty->receive_room = 0;
+
o_ldisc = tty->ldisc;
o_tty = tty->link;
@@ -1573,11 +1573,11 @@ void no_tty(void)
/**
- * stop_tty - propogate flow control
+ * stop_tty - propagate flow control
* @tty: tty to stop
*
* Perform flow control to the driver. For PTY/TTY pairs we
- * must also propogate the TIOCKPKT status. May be called
+ * must also propagate the TIOCKPKT status. May be called
* on an already stopped device and will not re-call the driver
* method.
*
@@ -1607,11 +1607,11 @@ void stop_tty(struct tty_struct *tty)
EXPORT_SYMBOL(stop_tty);
/**
- * start_tty - propogate flow control
+ * start_tty - propagate flow control
* @tty: tty to start
*
* Start a tty that has been stopped if at all possible. Perform
- * any neccessary wakeups and propogate the TIOCPKT status. If this
+ * any neccessary wakeups and propagate the TIOCPKT status. If this
* is the tty was previous stopped and is being started then the
* driver start method is invoked and the line discipline woken.
*
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 893dbaf386fb..eb37fba9b7ef 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1685,9 +1685,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
if (sys_dev) {
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpufreq_add_dev(sys_dev);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
if (unlikely(lock_policy_rwsem_write(cpu)))
BUG();
@@ -1699,6 +1701,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
__cpufreq_remove_dev(sys_dev);
break;
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
cpufreq_add_dev(sys_dev);
break;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d1c7cac9316c..d2f0cbd8b8f3 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -313,9 +313,11 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
break;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index f21fe66c9eef..f4c634504d1a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,7 +51,7 @@ config CRYPTO_DEV_GEODE
default m
help
Say 'Y' here to use the AMD Geode LX processor on-board AES
- engine for the CryptoAPI AES alogrithm.
+ engine for the CryptoAPI AES algorithm.
To compile this driver as a module, choose M here: the module
will be called geode-aes.
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 03b1f650d1c4..75e3911810a3 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -309,9 +309,11 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
coretemp_device_add(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
coretemp_device_remove(cpu);
break;
}
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 7ed92dc3d833..3c3f2ebf3fc9 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -354,7 +354,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
* also needs to get error handling and probably
* an #ifdef CONFIG_SOFTWARE_SUSPEND
*/
- pm_suspend(PM_SUSPEND_DISK);
+ hibernate();
#endif
poll = 1;
}
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 5314ec913724..d09e74c2996e 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -827,7 +827,7 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
/*
* Now set up the hw. We have to do this ourselves as
- * the MMIO layout isnt the same as the the standard port
+ * the MMIO layout isnt the same as the standard port
* based I/O
*/
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 6a1a0572275e..835937e38529 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -1702,7 +1702,7 @@ static int nodemgr_host_thread(void *__hi)
generation = get_hpsb_generation(host);
/* If we get a reset before we are done waiting, then
- * start the the waiting over again */
+ * start the waiting over again */
if (generation != g)
g = generation, i = 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index f284be1c9166..82dda2faf4d0 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -745,6 +745,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
if(!create_comp_task(pool, cpu)) {
ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
@@ -752,24 +753,29 @@ static int comp_pool_callback(struct notifier_block *nfb,
}
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
kthread_bind(cct->task, any_online_cpu(cpu_online_map));
destroy_comp_task(pool, cpu);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
kthread_bind(cct->task, cpu);
wake_up_process(cct->task);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
break;
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
destroy_comp_task(pool, cpu);
take_over_work(pool, cpu);
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index c921d6c522f5..c92f9d764fce 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -17,7 +17,7 @@ config CAPI_TRACE
help
If you say Y here, the kernelcapi driver can make verbose traces
of CAPI messages. This feature can be enabled/disabled via IOCTL for
- every controler (default disabled).
+ every controller (default disabled).
This will increase the size of the kernelcapi module by 20 KB.
If unsure, say Y.
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
index af3eb9e795b5..85784a7ffb25 100644
--- a/drivers/isdn/hardware/eicon/divasync.h
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -216,7 +216,7 @@ typedef struct
#define SERIAL_HOOK_RING 0x85
#define SERIAL_HOOK_DETACH 0x8f
unsigned char Flags; /* function refinements */
- /* parameters passed by the the ATTACH request */
+ /* parameters passed by the ATTACH request */
SERIAL_INT_CB InterruptHandler; /* called on each interrupt */
SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
void *HandlerContext; /* context for both handlers */
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 99e70d4103b6..1f18f1993387 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1217,11 +1217,11 @@ usb_init(hfcusb_data * hfc)
/* aux = output, reset off */
write_usb(hfc, HFCUSB_CIRM, 0x10);
- /* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+ /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
write_usb(hfc, HFCUSB_USB_SIZE,
(hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
- /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+ /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
/* enable PCM/GCI master mode */
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index c8b8cfa332bb..0d892600ff00 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -2889,7 +2889,9 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
switch (val) {
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
cpu);
decache_vcpus_on_cpu(cpu);
@@ -2897,6 +2899,7 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
NULL, 0, 1);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
cpu);
smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 1d49d2ade557..677c99325be5 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -1,5 +1,5 @@
/*
- * drivers/leds/h1940-leds.c
+ * drivers/leds/leds-h1940.c
* Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
*
* This file is subject to the terms and conditions of the GNU General Public
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a32c91e27b3c..58926da0ae18 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -237,7 +237,7 @@ config PMAC_RACKMETER
tristate "Support for Apple XServe front panel LEDs"
depends on PPC_PMAC
help
- This driver procides some support to control the front panel
+ This driver provides some support to control the front panel
blue LEDs "vu-meter" of the XServer macs.
endif # MACINTOSH_DRIVERS
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
index da862e4632dd..67b8e9453b19 100644
--- a/drivers/mca/mca-bus.c
+++ b/drivers/mca/mca-bus.c
@@ -47,19 +47,25 @@ static int mca_bus_match (struct device *dev, struct device_driver *drv)
{
struct mca_device *mca_dev = to_mca_device (dev);
struct mca_driver *mca_drv = to_mca_driver (drv);
- const short *mca_ids = mca_drv->id_table;
- int i;
-
- if (!mca_ids)
- return 0;
-
- for(i = 0; mca_ids[i]; i++) {
- if (mca_ids[i] == mca_dev->pos_id) {
- mca_dev->index = i;
- return 1;
+ const unsigned short *mca_ids = mca_drv->id_table;
+ int i = 0;
+
+ if (mca_ids) {
+ for(i = 0; mca_ids[i]; i++) {
+ if (mca_ids[i] == mca_dev->pos_id) {
+ mca_dev->index = i;
+ return 1;
+ }
}
}
-
+ /* If the integrated id is present, treat it as though it were an
+ * additional id in the id_table (it can't be because by definition,
+ * integrated id's overflow a short */
+ if (mca_drv->integrated_id && mca_dev->pos_id ==
+ mca_drv->integrated_id) {
+ mca_dev->index = i;
+ return 1;
+ }
return 0;
}
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
index 2223466b3d8a..32cd39bcc715 100644
--- a/drivers/mca/mca-driver.c
+++ b/drivers/mca/mca-driver.c
@@ -36,12 +36,25 @@ int mca_register_driver(struct mca_driver *mca_drv)
mca_drv->driver.bus = &mca_bus_type;
if ((r = driver_register(&mca_drv->driver)) < 0)
return r;
+ mca_drv->integrated_id = 0;
}
return 0;
}
EXPORT_SYMBOL(mca_register_driver);
+int mca_register_driver_integrated(struct mca_driver *mca_driver,
+ int integrated_id)
+{
+ int r = mca_register_driver(mca_driver);
+
+ if (!r)
+ mca_driver->integrated_id = integrated_id;
+
+ return r;
+}
+EXPORT_SYMBOL(mca_register_driver_integrated);
+
void mca_unregister_driver(struct mca_driver *mca_drv)
{
if (MCA_bus)
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 4540ade6b6b5..7df934d69134 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -262,6 +262,15 @@ config DM_MULTIPATH_EMC
---help---
Multipath support for EMC CX/AX series hardware.
+config DM_DELAY
+ tristate "I/O delaying target (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ A target that delays reads and/or writes and can send
+ them to different devices. Useful for testing.
+
+ If unsure, say N.
+
endmenu
endif
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 34957a68d921..38754084eac7 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MD_FAULTY) += faulty.o
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
+obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index da4349649f7f..c6be88826fae 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -8,17 +8,43 @@
#define DM_BIO_LIST_H
#include <linux/bio.h>
+#include <linux/prefetch.h>
struct bio_list {
struct bio *head;
struct bio *tail;
};
+static inline int bio_list_empty(const struct bio_list *bl)
+{
+ return bl->head == NULL;
+}
+
+#define BIO_LIST_INIT { .head = NULL, .tail = NULL }
+
+#define BIO_LIST(bl) \
+ struct bio_list bl = BIO_LIST_INIT
+
static inline void bio_list_init(struct bio_list *bl)
{
bl->head = bl->tail = NULL;
}
+#define bio_list_for_each(bio, bl) \
+ for (bio = (bl)->head; bio && ({ prefetch(bio->bi_next); 1; }); \
+ bio = bio->bi_next)
+
+static inline unsigned bio_list_size(const struct bio_list *bl)
+{
+ unsigned sz = 0;
+ struct bio *bio;
+
+ bio_list_for_each(bio, bl)
+ sz++;
+
+ return sz;
+}
+
static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
{
bio->bi_next = NULL;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index d8121234c347..7b0fcfc9eaa5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -33,7 +33,6 @@
struct crypt_io {
struct dm_target *target;
struct bio *base_bio;
- struct bio *first_clone;
struct work_struct work;
atomic_t pending;
int error;
@@ -107,6 +106,8 @@ struct crypt_config {
static struct kmem_cache *_crypt_io_pool;
+static void clone_init(struct crypt_io *, struct bio *);
+
/*
* Different IV generation algorithms:
*
@@ -120,6 +121,9 @@ static struct kmem_cache *_crypt_io_pool;
* benbi: the 64-bit "big-endian 'narrow block'-count", starting at 1
* (needed for LRW-32-AES and possible other narrow block modes)
*
+ * null: the initial vector is always zero. Provides compatibility with
+ * obsolete loop_fish2 devices. Do not use for new devices.
+ *
* plumb: unimplemented, see:
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
*/
@@ -256,6 +260,13 @@ static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
return 0;
}
+static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+ memset(iv, 0, cc->iv_size);
+
+ return 0;
+}
+
static struct crypt_iv_operations crypt_iv_plain_ops = {
.generator = crypt_iv_plain_gen
};
@@ -272,6 +283,10 @@ static struct crypt_iv_operations crypt_iv_benbi_ops = {
.generator = crypt_iv_benbi_gen
};
+static struct crypt_iv_operations crypt_iv_null_ops = {
+ .generator = crypt_iv_null_gen
+};
+
static int
crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
struct scatterlist *in, unsigned int length,
@@ -378,36 +393,21 @@ static int crypt_convert(struct crypt_config *cc,
* This should never violate the device limitations
* May return a smaller bio when running out of pages
*/
-static struct bio *
-crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
- struct bio *base_bio, unsigned int *bio_vec_idx)
+static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int size)
{
+ struct crypt_config *cc = io->target->private;
struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
unsigned int i;
- if (base_bio) {
- clone = bio_alloc_bioset(GFP_NOIO, base_bio->bi_max_vecs, cc->bs);
- __bio_clone(clone, base_bio);
- } else
- clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
-
+ clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
if (!clone)
return NULL;
- clone->bi_destructor = dm_crypt_bio_destructor;
-
- /* if the last bio was not complete, continue where that one ended */
- clone->bi_idx = *bio_vec_idx;
- clone->bi_vcnt = *bio_vec_idx;
- clone->bi_size = 0;
- clone->bi_flags &= ~(1 << BIO_SEG_VALID);
-
- /* clone->bi_idx pages have already been allocated */
- size -= clone->bi_idx * PAGE_SIZE;
+ clone_init(io, clone);
- for (i = clone->bi_idx; i < nr_iovecs; i++) {
+ for (i = 0; i < nr_iovecs; i++) {
struct bio_vec *bv = bio_iovec_idx(clone, i);
bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
@@ -419,7 +419,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
* return a partially allocated bio, the caller will then try
* to allocate additional bios while submitting this partial bio
*/
- if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
+ if (i == (MIN_BIO_PAGES - 1))
gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
bv->bv_offset = 0;
@@ -438,12 +438,6 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
return NULL;
}
- /*
- * Remember the last bio_vec allocated to be able
- * to correctly continue after the splitting.
- */
- *bio_vec_idx = clone->bi_vcnt;
-
return clone;
}
@@ -495,9 +489,6 @@ static void dec_pending(struct crypt_io *io, int error)
if (!atomic_dec_and_test(&io->pending))
return;
- if (io->first_clone)
- bio_put(io->first_clone);
-
bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
mempool_free(io, cc->io_pool);
@@ -562,6 +553,7 @@ static void clone_init(struct crypt_io *io, struct bio *clone)
clone->bi_end_io = crypt_endio;
clone->bi_bdev = cc->dev->bdev;
clone->bi_rw = io->base_bio->bi_rw;
+ clone->bi_destructor = dm_crypt_bio_destructor;
}
static void process_read(struct crypt_io *io)
@@ -585,7 +577,6 @@ static void process_read(struct crypt_io *io)
}
clone_init(io, clone);
- clone->bi_destructor = dm_crypt_bio_destructor;
clone->bi_idx = 0;
clone->bi_vcnt = bio_segments(base_bio);
clone->bi_size = base_bio->bi_size;
@@ -604,7 +595,6 @@ static void process_write(struct crypt_io *io)
struct convert_context ctx;
unsigned remaining = base_bio->bi_size;
sector_t sector = base_bio->bi_sector - io->target->begin;
- unsigned bvec_idx = 0;
atomic_inc(&io->pending);
@@ -615,14 +605,14 @@ static void process_write(struct crypt_io *io)
* so repeat the whole process until all the data can be handled.
*/
while (remaining) {
- clone = crypt_alloc_buffer(cc, base_bio->bi_size,
- io->first_clone, &bvec_idx);
+ clone = crypt_alloc_buffer(io, remaining);
if (unlikely(!clone)) {
dec_pending(io, -ENOMEM);
return;
}
ctx.bio_out = clone;
+ ctx.idx_out = 0;
if (unlikely(crypt_convert(cc, &ctx) < 0)) {
crypt_free_buffer_pages(cc, clone, clone->bi_size);
@@ -631,31 +621,26 @@ static void process_write(struct crypt_io *io)
return;
}
- clone_init(io, clone);
- clone->bi_sector = cc->start + sector;
-
- if (!io->first_clone) {
- /*
- * hold a reference to the first clone, because it
- * holds the bio_vec array and that can't be freed
- * before all other clones are released
- */
- bio_get(clone);
- io->first_clone = clone;
- }
+ /* crypt_convert should have filled the clone bio */
+ BUG_ON(ctx.idx_out < clone->bi_vcnt);
+ clone->bi_sector = cc->start + sector;
remaining -= clone->bi_size;
sector += bio_sectors(clone);
- /* prevent bio_put of first_clone */
+ /* Grab another reference to the io struct
+ * before we kick off the request */
if (remaining)
atomic_inc(&io->pending);
generic_make_request(clone);
+ /* Do not reference clone after this - it
+ * may be gone already. */
+
/* out of memory -> run queues */
if (remaining)
- congestion_wait(bio_data_dir(clone), HZ/100);
+ congestion_wait(WRITE, HZ/100);
}
}
@@ -832,6 +817,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_gen_ops = &crypt_iv_essiv_ops;
else if (strcmp(ivmode, "benbi") == 0)
cc->iv_gen_ops = &crypt_iv_benbi_ops;
+ else if (strcmp(ivmode, "null") == 0)
+ cc->iv_gen_ops = &crypt_iv_null_ops;
else {
ti->error = "Invalid IV mode";
goto bad2;
@@ -954,10 +941,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
struct crypt_config *cc = ti->private;
struct crypt_io *io;
+ if (bio_barrier(bio))
+ return -EOPNOTSUPP;
+
io = mempool_alloc(cc->io_pool, GFP_NOIO);
io->target = ti;
io->base_bio = bio;
- io->first_clone = NULL;
io->error = io->post_process = 0;
atomic_set(&io->pending, 0);
kcryptd_queue_io(io);
@@ -1057,7 +1046,7 @@ error:
static struct target_type crypt_target = {
.name = "crypt",
- .version= {1, 3, 0},
+ .version= {1, 5, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
new file mode 100644
index 000000000000..52c7cf9e5803
--- /dev/null
+++ b/drivers/md/dm-delay.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2005-2007 Red Hat GmbH
+ *
+ * A target that delays reads and/or writes and can send
+ * them to different devices.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+
+#include "dm.h"
+#include "dm-bio-list.h"
+
+#define DM_MSG_PREFIX "delay"
+
+struct delay_c {
+ struct timer_list delay_timer;
+ struct semaphore timer_lock;
+ struct work_struct flush_expired_bios;
+ struct list_head delayed_bios;
+ atomic_t may_delay;
+ mempool_t *delayed_pool;
+
+ struct dm_dev *dev_read;
+ sector_t start_read;
+ unsigned read_delay;
+ unsigned reads;
+
+ struct dm_dev *dev_write;
+ sector_t start_write;
+ unsigned write_delay;
+ unsigned writes;
+};
+
+struct delay_info {
+ struct delay_c *context;
+ struct list_head list;
+ struct bio *bio;
+ unsigned long expires;
+};
+
+static DEFINE_MUTEX(delayed_bios_lock);
+
+static struct workqueue_struct *kdelayd_wq;
+static struct kmem_cache *delayed_cache;
+
+static void handle_delayed_timer(unsigned long data)
+{
+ struct delay_c *dc = (struct delay_c *)data;
+
+ queue_work(kdelayd_wq, &dc->flush_expired_bios);
+}
+
+static void queue_timeout(struct delay_c *dc, unsigned long expires)
+{
+ down(&dc->timer_lock);
+
+ if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
+ mod_timer(&dc->delay_timer, expires);
+
+ up(&dc->timer_lock);
+}
+
+static void flush_bios(struct bio *bio)
+{
+ struct bio *n;
+
+ while (bio) {
+ n = bio->bi_next;
+ bio->bi_next = NULL;
+ generic_make_request(bio);
+ bio = n;
+ }
+}
+
+static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
+{
+ struct delay_info *delayed, *next;
+ unsigned long next_expires = 0;
+ int start_timer = 0;
+ BIO_LIST(flush_bios);
+
+ mutex_lock(&delayed_bios_lock);
+ list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
+ if (flush_all || time_after_eq(jiffies, delayed->expires)) {
+ list_del(&delayed->list);
+ bio_list_add(&flush_bios, delayed->bio);
+ if ((bio_data_dir(delayed->bio) == WRITE))
+ delayed->context->writes--;
+ else
+ delayed->context->reads--;
+ mempool_free(delayed, dc->delayed_pool);
+ continue;
+ }
+
+ if (!start_timer) {
+ start_timer = 1;
+ next_expires = delayed->expires;
+ } else
+ next_expires = min(next_expires, delayed->expires);
+ }
+
+ mutex_unlock(&delayed_bios_lock);
+
+ if (start_timer)
+ queue_timeout(dc, next_expires);
+
+ return bio_list_get(&flush_bios);
+}
+
+static void flush_expired_bios(struct work_struct *work)
+{
+ struct delay_c *dc;
+
+ dc = container_of(work, struct delay_c, flush_expired_bios);
+ flush_bios(flush_delayed_bios(dc, 0));
+}
+
+/*
+ * Mapping parameters:
+ * <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+ *
+ * With separate write parameters, the first set is only used for reads.
+ * Delays are specified in milliseconds.
+ */
+static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+ struct delay_c *dc;
+ unsigned long long tmpll;
+
+ if (argc != 3 && argc != 6) {
+ ti->error = "requires exactly 3 or 6 arguments";
+ return -EINVAL;
+ }
+
+ dc = kmalloc(sizeof(*dc), GFP_KERNEL);
+ if (!dc) {
+ ti->error = "Cannot allocate context";
+ return -ENOMEM;
+ }
+
+ dc->reads = dc->writes = 0;
+
+ if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid device sector";
+ goto bad;
+ }
+ dc->start_read = tmpll;
+
+ if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+ ti->error = "Invalid delay";
+ goto bad;
+ }
+
+ if (dm_get_device(ti, argv[0], dc->start_read, ti->len,
+ dm_table_get_mode(ti->table), &dc->dev_read)) {
+ ti->error = "Device lookup failed";
+ goto bad;
+ }
+
+ if (argc == 3) {
+ dc->dev_write = NULL;
+ goto out;
+ }
+
+ if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid write device sector";
+ goto bad;
+ }
+ dc->start_write = tmpll;
+
+ if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+ ti->error = "Invalid write delay";
+ goto bad;
+ }
+
+ if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
+ dm_table_get_mode(ti->table), &dc->dev_write)) {
+ ti->error = "Write device lookup failed";
+ dm_put_device(ti, dc->dev_read);
+ goto bad;
+ }
+
+out:
+ dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
+ if (!dc->delayed_pool) {
+ DMERR("Couldn't create delayed bio pool.");
+ goto bad;
+ }
+
+ init_timer(&dc->delay_timer);
+ dc->delay_timer.function = handle_delayed_timer;
+ dc->delay_timer.data = (unsigned long)dc;
+
+ INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
+ INIT_LIST_HEAD(&dc->delayed_bios);
+ init_MUTEX(&dc->timer_lock);
+ atomic_set(&dc->may_delay, 1);
+
+ ti->private = dc;
+ return 0;
+
+bad:
+ kfree(dc);
+ return -EINVAL;
+}
+
+static void delay_dtr(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ flush_workqueue(kdelayd_wq);
+
+ dm_put_device(ti, dc->dev_read);
+
+ if (dc->dev_write)
+ dm_put_device(ti, dc->dev_write);
+
+ mempool_destroy(dc->delayed_pool);
+ kfree(dc);
+}
+
+static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
+{
+ struct delay_info *delayed;
+ unsigned long expires = 0;
+
+ if (!delay || !atomic_read(&dc->may_delay))
+ return 1;
+
+ delayed = mempool_alloc(dc->delayed_pool, GFP_NOIO);
+
+ delayed->context = dc;
+ delayed->bio = bio;
+ delayed->expires = expires = jiffies + (delay * HZ / 1000);
+
+ mutex_lock(&delayed_bios_lock);
+
+ if (bio_data_dir(bio) == WRITE)
+ dc->writes++;
+ else
+ dc->reads++;
+
+ list_add_tail(&delayed->list, &dc->delayed_bios);
+
+ mutex_unlock(&delayed_bios_lock);
+
+ queue_timeout(dc, expires);
+
+ return 0;
+}
+
+static void delay_presuspend(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ atomic_set(&dc->may_delay, 0);
+ del_timer_sync(&dc->delay_timer);
+ flush_bios(flush_delayed_bios(dc, 1));
+}
+
+static void delay_resume(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ atomic_set(&dc->may_delay, 1);
+}
+
+static int delay_map(struct dm_target *ti, struct bio *bio,
+ union map_info *map_context)
+{
+ struct delay_c *dc = ti->private;
+
+ if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
+ bio->bi_bdev = dc->dev_write->bdev;
+ bio->bi_sector = dc->start_write +
+ (bio->bi_sector - ti->begin);
+
+ return delay_bio(dc, dc->write_delay, bio);
+ }
+
+ bio->bi_bdev = dc->dev_read->bdev;
+ bio->bi_sector = dc->start_read +
+ (bio->bi_sector - ti->begin);
+
+ return delay_bio(dc, dc->read_delay, bio);
+}
+
+static int delay_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ struct delay_c *dc = ti->private;
+ int sz = 0;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ DMEMIT("%u %u", dc->reads, dc->writes);
+ break;
+
+ case STATUSTYPE_TABLE:
+ DMEMIT("%s %llu %u", dc->dev_read->name,
+ (unsigned long long) dc->start_read,
+ dc->read_delay);
+ if (dc->dev_write)
+ DMEMIT("%s %llu %u", dc->dev_write->name,
+ (unsigned long long) dc->start_write,
+ dc->write_delay);
+ break;
+ }
+
+ return 0;
+}
+
+static struct target_type delay_target = {
+ .name = "delay",
+ .version = {1, 0, 2},
+ .module = THIS_MODULE,
+ .ctr = delay_ctr,
+ .dtr = delay_dtr,
+ .map = delay_map,
+ .presuspend = delay_presuspend,
+ .resume = delay_resume,
+ .status = delay_status,
+};
+
+static int __init dm_delay_init(void)
+{
+ int r = -ENOMEM;
+
+ kdelayd_wq = create_workqueue("kdelayd");
+ if (!kdelayd_wq) {
+ DMERR("Couldn't start kdelayd");
+ goto bad_queue;
+ }
+
+ delayed_cache = kmem_cache_create("dm-delay",
+ sizeof(struct delay_info),
+ __alignof__(struct delay_info),
+ 0, NULL, NULL);
+ if (!delayed_cache) {
+ DMERR("Couldn't create delayed bio cache.");
+ goto bad_memcache;
+ }
+
+ r = dm_register_target(&delay_target);
+ if (r < 0) {
+ DMERR("register failed %d", r);
+ goto bad_register;
+ }
+
+ return 0;
+
+bad_register:
+ kmem_cache_destroy(delayed_cache);
+bad_memcache:
+ destroy_workqueue(kdelayd_wq);
+bad_queue:
+ return r;
+}
+
+static void __exit dm_delay_exit(void)
+{
+ int r = dm_unregister_target(&delay_target);
+
+ if (r < 0)
+ DMERR("unregister failed %d", r);
+
+ kmem_cache_destroy(delayed_cache);
+ destroy_workqueue(kdelayd_wq);
+}
+
+/* Module hooks */
+module_init(dm_delay_init);
+module_exit(dm_delay_exit);
+
+MODULE_DESCRIPTION(DM_NAME " delay target");
+MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 99cdffa7fbfe..07e0a0c84f6e 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -1,7 +1,8 @@
/*
- * dm-snapshot.c
+ * dm-exception-store.c
*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*/
@@ -123,6 +124,7 @@ struct pstore {
atomic_t pending_count;
uint32_t callback_count;
struct commit_callback *callbacks;
+ struct dm_io_client *io_client;
};
static inline unsigned int sectors_to_pages(unsigned int sectors)
@@ -159,14 +161,20 @@ static void free_area(struct pstore *ps)
*/
static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
{
- struct io_region where;
- unsigned long bits;
-
- where.bdev = ps->snap->cow->bdev;
- where.sector = ps->snap->chunk_size * chunk;
- where.count = ps->snap->chunk_size;
-
- return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
+ struct io_region where = {
+ .bdev = ps->snap->cow->bdev,
+ .sector = ps->snap->chunk_size * chunk,
+ .count = ps->snap->chunk_size,
+ };
+ struct dm_io_request io_req = {
+ .bi_rw = rw,
+ .mem.type = DM_IO_VMA,
+ .mem.ptr.vma = ps->area,
+ .client = ps->io_client,
+ .notify.fn = NULL,
+ };
+
+ return dm_io(&io_req, 1, &where, NULL);
}
/*
@@ -213,17 +221,18 @@ static int read_header(struct pstore *ps, int *new_snapshot)
chunk_size_supplied = 0;
}
- r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
- if (r)
- return r;
+ ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+ chunk_size));
+ if (IS_ERR(ps->io_client))
+ return PTR_ERR(ps->io_client);
r = alloc_area(ps);
if (r)
- goto bad1;
+ return r;
r = chunk_io(ps, 0, READ);
if (r)
- goto bad2;
+ goto bad;
dh = (struct disk_header *) ps->area;
@@ -235,7 +244,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
DMWARN("Invalid or corrupt snapshot");
r = -ENXIO;
- goto bad2;
+ goto bad;
}
*new_snapshot = 0;
@@ -252,27 +261,22 @@ static int read_header(struct pstore *ps, int *new_snapshot)
(unsigned long long)ps->snap->chunk_size);
/* We had a bogus chunk_size. Fix stuff up. */
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
free_area(ps);
ps->snap->chunk_size = chunk_size;
ps->snap->chunk_mask = chunk_size - 1;
ps->snap->chunk_shift = ffs(chunk_size) - 1;
- r = dm_io_get(sectors_to_pages(chunk_size));
+ r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+ ps->io_client);
if (r)
return r;
r = alloc_area(ps);
- if (r)
- goto bad1;
-
- return 0;
+ return r;
-bad2:
+bad:
free_area(ps);
-bad1:
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
return r;
}
@@ -405,7 +409,7 @@ static void persistent_destroy(struct exception_store *store)
{
struct pstore *ps = get_info(store);
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+ dm_io_client_destroy(ps->io_client);
vfree(ps->callbacks);
free_area(ps);
kfree(ps);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index 32eff28e4adc..e0832e6fcf36 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -16,6 +16,7 @@
struct hw_handler_type;
struct hw_handler {
struct hw_handler_type *type;
+ struct mapped_device *md;
void *context;
};
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 8bdc8a87b249..352c6fbeac53 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*/
@@ -12,13 +13,17 @@
#include <linux/sched.h>
#include <linux/slab.h>
-static struct bio_set *_bios;
+struct dm_io_client {
+ mempool_t *pool;
+ struct bio_set *bios;
+};
/* FIXME: can we shrink this ? */
struct io {
unsigned long error;
atomic_t count;
struct task_struct *sleeper;
+ struct dm_io_client *client;
io_notify_fn callback;
void *context;
};
@@ -26,63 +31,58 @@ struct io {
/*
* io contexts are only dynamically allocated for asynchronous
* io. Since async io is likely to be the majority of io we'll
- * have the same number of io contexts as buffer heads ! (FIXME:
- * must reduce this).
+ * have the same number of io contexts as bios! (FIXME: must reduce this).
*/
-static unsigned _num_ios;
-static mempool_t *_io_pool;
static unsigned int pages_to_ios(unsigned int pages)
{
return 4 * pages; /* too many ? */
}
-static int resize_pool(unsigned int new_ios)
+/*
+ * Create a client with mempool and bioset.
+ */
+struct dm_io_client *dm_io_client_create(unsigned num_pages)
{
- int r = 0;
-
- if (_io_pool) {
- if (new_ios == 0) {
- /* free off the pool */
- mempool_destroy(_io_pool);
- _io_pool = NULL;
- bioset_free(_bios);
-
- } else {
- /* resize the pool */
- r = mempool_resize(_io_pool, new_ios, GFP_KERNEL);
- }
+ unsigned ios = pages_to_ios(num_pages);
+ struct dm_io_client *client;
- } else {
- /* create new pool */
- _io_pool = mempool_create_kmalloc_pool(new_ios,
- sizeof(struct io));
- if (!_io_pool)
- return -ENOMEM;
-
- _bios = bioset_create(16, 16);
- if (!_bios) {
- mempool_destroy(_io_pool);
- _io_pool = NULL;
- return -ENOMEM;
- }
- }
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io));
+ if (!client->pool)
+ goto bad;
- if (!r)
- _num_ios = new_ios;
+ client->bios = bioset_create(16, 16);
+ if (!client->bios)
+ goto bad;
- return r;
+ return client;
+
+ bad:
+ if (client->pool)
+ mempool_destroy(client->pool);
+ kfree(client);
+ return ERR_PTR(-ENOMEM);
}
+EXPORT_SYMBOL(dm_io_client_create);
-int dm_io_get(unsigned int num_pages)
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client)
{
- return resize_pool(_num_ios + pages_to_ios(num_pages));
+ return mempool_resize(client->pool, pages_to_ios(num_pages),
+ GFP_KERNEL);
}
+EXPORT_SYMBOL(dm_io_client_resize);
-void dm_io_put(unsigned int num_pages)
+void dm_io_client_destroy(struct dm_io_client *client)
{
- resize_pool(_num_ios - pages_to_ios(num_pages));
+ mempool_destroy(client->pool);
+ bioset_free(client->bios);
+ kfree(client);
}
+EXPORT_SYMBOL(dm_io_client_destroy);
/*-----------------------------------------------------------------
* We need to keep track of which region a bio is doing io for.
@@ -118,7 +118,7 @@ static void dec_count(struct io *io, unsigned int region, int error)
io_notify_fn fn = io->callback;
void *context = io->context;
- mempool_free(io, _io_pool);
+ mempool_free(io, io->client->pool);
fn(r, context);
}
}
@@ -126,7 +126,8 @@ static void dec_count(struct io *io, unsigned int region, int error)
static int endio(struct bio *bio, unsigned int done, int error)
{
- struct io *io = (struct io *) bio->bi_private;
+ struct io *io;
+ unsigned region;
/* keep going until we've finished */
if (bio->bi_size)
@@ -135,10 +136,17 @@ static int endio(struct bio *bio, unsigned int done, int error)
if (error && bio_data_dir(bio) == READ)
zero_fill_bio(bio);
- dec_count(io, bio_get_region(bio), error);
+ /*
+ * The bio destructor in bio_put() may use the io object.
+ */
+ io = bio->bi_private;
+ region = bio_get_region(bio);
+
bio->bi_max_vecs++;
bio_put(bio);
+ dec_count(io, region, error);
+
return 0;
}
@@ -209,6 +217,9 @@ static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec)
dp->context_ptr = bvec;
}
+/*
+ * Functions for getting the pages from a VMA.
+ */
static void vm_get_page(struct dpages *dp,
struct page **p, unsigned long *len, unsigned *offset)
{
@@ -233,7 +244,34 @@ static void vm_dp_init(struct dpages *dp, void *data)
static void dm_bio_destructor(struct bio *bio)
{
- bio_free(bio, _bios);
+ struct io *io = bio->bi_private;
+
+ bio_free(bio, io->client->bios);
+}
+
+/*
+ * Functions for getting the pages from kernel memory.
+ */
+static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len,
+ unsigned *offset)
+{
+ *p = virt_to_page(dp->context_ptr);
+ *offset = dp->context_u;
+ *len = PAGE_SIZE - dp->context_u;
+}
+
+static void km_next_page(struct dpages *dp)
+{
+ dp->context_ptr += PAGE_SIZE - dp->context_u;
+ dp->context_u = 0;
+}
+
+static void km_dp_init(struct dpages *dp, void *data)
+{
+ dp->get_page = km_get_page;
+ dp->next_page = km_next_page;
+ dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+ dp->context_ptr = data;
}
/*-----------------------------------------------------------------
@@ -256,7 +294,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
* to hide it from bio_add_page().
*/
num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
- bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
+ bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
@@ -311,8 +349,9 @@ static void dispatch_io(int rw, unsigned int num_regions,
dec_count(io, 0, 0);
}
-static int sync_io(unsigned int num_regions, struct io_region *where,
- int rw, struct dpages *dp, unsigned long *error_bits)
+static int sync_io(struct dm_io_client *client, unsigned int num_regions,
+ struct io_region *where, int rw, struct dpages *dp,
+ unsigned long *error_bits)
{
struct io io;
@@ -324,6 +363,7 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
io.error = 0;
atomic_set(&io.count, 1); /* see dispatch_io() */
io.sleeper = current;
+ io.client = client;
dispatch_io(rw, num_regions, where, dp, &io, 1);
@@ -340,12 +380,15 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
if (atomic_read(&io.count))
return -EINTR;
- *error_bits = io.error;
+ if (error_bits)
+ *error_bits = io.error;
+
return io.error ? -EIO : 0;
}
-static int async_io(unsigned int num_regions, struct io_region *where, int rw,
- struct dpages *dp, io_notify_fn fn, void *context)
+static int async_io(struct dm_io_client *client, unsigned int num_regions,
+ struct io_region *where, int rw, struct dpages *dp,
+ io_notify_fn fn, void *context)
{
struct io *io;
@@ -355,10 +398,11 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
return -EIO;
}
- io = mempool_alloc(_io_pool, GFP_NOIO);
+ io = mempool_alloc(client->pool, GFP_NOIO);
io->error = 0;
atomic_set(&io->count, 1); /* see dispatch_io() */
io->sleeper = NULL;
+ io->client = client;
io->callback = fn;
io->context = context;
@@ -366,61 +410,51 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
return 0;
}
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- unsigned long *error_bits)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
{
- struct dpages dp;
- list_dp_init(&dp, pl, offset);
- return sync_io(num_regions, where, rw, &dp, error_bits);
-}
+ /* Set up dpages based on memory type */
+ switch (io_req->mem.type) {
+ case DM_IO_PAGE_LIST:
+ list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
+ break;
+
+ case DM_IO_BVEC:
+ bvec_dp_init(dp, io_req->mem.ptr.bvec);
+ break;
+
+ case DM_IO_VMA:
+ vm_dp_init(dp, io_req->mem.ptr.vma);
+ break;
+
+ case DM_IO_KMEM:
+ km_dp_init(dp, io_req->mem.ptr.addr);
+ break;
+
+ default:
+ return -EINVAL;
+ }
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, unsigned long *error_bits)
-{
- struct dpages dp;
- bvec_dp_init(&dp, bvec);
- return sync_io(num_regions, where, rw, &dp, error_bits);
+ return 0;
}
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, unsigned long *error_bits)
+/*
+ * New collapsed (a)synchronous interface
+ */
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+ struct io_region *where, unsigned long *sync_error_bits)
{
+ int r;
struct dpages dp;
- vm_dp_init(&dp, data);
- return sync_io(num_regions, where, rw, &dp, error_bits);
-}
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- io_notify_fn fn, void *context)
-{
- struct dpages dp;
- list_dp_init(&dp, pl, offset);
- return async_io(num_regions, where, rw, &dp, fn, context);
-}
+ r = dp_init(io_req, &dp);
+ if (r)
+ return r;
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, io_notify_fn fn, void *context)
-{
- struct dpages dp;
- bvec_dp_init(&dp, bvec);
- return async_io(num_regions, where, rw, &dp, fn, context);
-}
+ if (!io_req->notify.fn)
+ return sync_io(io_req->client, num_regions, where,
+ io_req->bi_rw, &dp, sync_error_bits);
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, io_notify_fn fn, void *context)
-{
- struct dpages dp;
- vm_dp_init(&dp, data);
- return async_io(num_regions, where, rw, &dp, fn, context);
+ return async_io(io_req->client, num_regions, where, io_req->bi_rw,
+ &dp, io_req->notify.fn, io_req->notify.context);
}
-
-EXPORT_SYMBOL(dm_io_get);
-EXPORT_SYMBOL(dm_io_put);
-EXPORT_SYMBOL(dm_io_sync);
-EXPORT_SYMBOL(dm_io_async);
-EXPORT_SYMBOL(dm_io_sync_bvec);
-EXPORT_SYMBOL(dm_io_async_bvec);
-EXPORT_SYMBOL(dm_io_sync_vm);
-EXPORT_SYMBOL(dm_io_async_vm);
+EXPORT_SYMBOL(dm_io);
diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h
index f9035bfd1a9f..f647e2cceaa6 100644
--- a/drivers/md/dm-io.h
+++ b/drivers/md/dm-io.h
@@ -12,7 +12,7 @@
struct io_region {
struct block_device *bdev;
sector_t sector;
- sector_t count;
+ sector_t count; /* If this is zero the region is ignored. */
};
struct page_list {
@@ -20,55 +20,60 @@ struct page_list {
struct page *page;
};
-
-/*
- * 'error' is a bitset, with each bit indicating whether an error
- * occurred doing io to the corresponding region.
- */
typedef void (*io_notify_fn)(unsigned long error, void *context);
+enum dm_io_mem_type {
+ DM_IO_PAGE_LIST,/* Page list */
+ DM_IO_BVEC, /* Bio vector */
+ DM_IO_VMA, /* Virtual memory area */
+ DM_IO_KMEM, /* Kernel memory */
+};
+
+struct dm_io_memory {
+ enum dm_io_mem_type type;
+
+ union {
+ struct page_list *pl;
+ struct bio_vec *bvec;
+ void *vma;
+ void *addr;
+ } ptr;
+
+ unsigned offset;
+};
+
+struct dm_io_notify {
+ io_notify_fn fn; /* Callback for asynchronous requests */
+ void *context; /* Passed to callback */
+};
/*
- * Before anyone uses the IO interface they should call
- * dm_io_get(), specifying roughly how many pages they are
- * expecting to perform io on concurrently.
- *
- * This function may block.
+ * IO request structure
*/
-int dm_io_get(unsigned int num_pages);
-void dm_io_put(unsigned int num_pages);
+struct dm_io_client;
+struct dm_io_request {
+ int bi_rw; /* READ|WRITE - not READA */
+ struct dm_io_memory mem; /* Memory to use for io */
+ struct dm_io_notify notify; /* Synchronous if notify.fn is NULL */
+ struct dm_io_client *client; /* Client memory handler */
+};
/*
- * Synchronous IO.
+ * For async io calls, users can alternatively use the dm_io() function below
+ * and dm_io_client_create() to create private mempools for the client.
*
- * Please ensure that the rw flag in the next two functions is
- * either READ or WRITE, ie. we don't take READA. Any
- * regions with a zero count field will be ignored.
+ * Create/destroy may block.
*/
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- unsigned long *error_bits);
-
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, unsigned long *error_bits);
-
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, unsigned long *error_bits);
+struct dm_io_client *dm_io_client_create(unsigned num_pages);
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client);
+void dm_io_client_destroy(struct dm_io_client *client);
/*
- * Aynchronous IO.
- *
- * The 'where' array may be safely allocated on the stack since
- * the function takes a copy.
+ * IO interface using private per-client pools.
+ * Each bit in the optional 'sync_error_bits' bitset indicates whether an
+ * error occurred doing io to the corresponding region.
*/
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- io_notify_fn fn, void *context);
-
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, io_notify_fn fn, void *context);
-
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, io_notify_fn fn, void *context);
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+ struct io_region *region, unsigned long *sync_error_bits);
#endif
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 6a9261351848..a66428d860fe 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -149,9 +149,12 @@ struct log_c {
FORCESYNC, /* Force a sync to happen */
} sync;
+ struct dm_io_request io_req;
+
/*
* Disk log fields
*/
+ int log_dev_failed;
struct dm_dev *log_dev;
struct log_header header;
@@ -199,13 +202,20 @@ static void header_from_disk(struct log_header *core, struct log_header *disk)
core->nr_regions = le64_to_cpu(disk->nr_regions);
}
+static int rw_header(struct log_c *lc, int rw)
+{
+ lc->io_req.bi_rw = rw;
+ lc->io_req.mem.ptr.vma = lc->disk_header;
+ lc->io_req.notify.fn = NULL;
+
+ return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
+}
+
static int read_header(struct log_c *log)
{
int r;
- unsigned long ebits;
- r = dm_io_sync_vm(1, &log->header_location, READ,
- log->disk_header, &ebits);
+ r = rw_header(log, READ);
if (r)
return r;
@@ -233,11 +243,8 @@ static int read_header(struct log_c *log)
static inline int write_header(struct log_c *log)
{
- unsigned long ebits;
-
header_to_disk(&log->header, log->disk_header);
- return dm_io_sync_vm(1, &log->header_location, WRITE,
- log->disk_header, &ebits);
+ return rw_header(log, WRITE);
}
/*----------------------------------------------------------------
@@ -256,6 +263,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
uint32_t region_size;
unsigned int region_count;
size_t bitset_size, buf_size;
+ int r;
if (argc < 1 || argc > 2) {
DMWARN("wrong number of arguments to mirror log");
@@ -315,6 +323,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
lc->disk_header = NULL;
} else {
lc->log_dev = dev;
+ lc->log_dev_failed = 0;
lc->header_location.bdev = lc->log_dev->bdev;
lc->header_location.sector = 0;
@@ -324,6 +333,15 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
bitset_size, ti->limits.hardsect_size);
lc->header_location.count = buf_size >> SECTOR_SHIFT;
+ lc->io_req.mem.type = DM_IO_VMA;
+ lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
+ PAGE_SIZE));
+ if (IS_ERR(lc->io_req.client)) {
+ r = PTR_ERR(lc->io_req.client);
+ DMWARN("couldn't allocate disk io client");
+ kfree(lc);
+ return -ENOMEM;
+ }
lc->disk_header = vmalloc(buf_size);
if (!lc->disk_header) {
@@ -424,6 +442,7 @@ static void disk_dtr(struct dirty_log *log)
dm_put_device(lc->ti, lc->log_dev);
vfree(lc->disk_header);
+ dm_io_client_destroy(lc->io_req.client);
destroy_log_context(lc);
}
@@ -437,6 +456,15 @@ static int count_bits32(uint32_t *addr, unsigned size)
return count;
}
+static void fail_log_device(struct log_c *lc)
+{
+ if (lc->log_dev_failed)
+ return;
+
+ lc->log_dev_failed = 1;
+ dm_table_event(lc->ti->table);
+}
+
static int disk_resume(struct dirty_log *log)
{
int r;
@@ -446,8 +474,19 @@ static int disk_resume(struct dirty_log *log)
/* read the disk header */
r = read_header(lc);
- if (r)
- return r;
+ if (r) {
+ DMWARN("%s: Failed to read header on mirror log device",
+ lc->log_dev->name);
+ fail_log_device(lc);
+ /*
+ * If the log device cannot be read, we must assume
+ * all regions are out-of-sync. If we simply return
+ * here, the state will be uninitialized and could
+ * lead us to return 'in-sync' status for regions
+ * that are actually 'out-of-sync'.
+ */
+ lc->header.nr_regions = 0;
+ }
/* set or clear any new bits -- device has grown */
if (lc->sync == NOSYNC)
@@ -472,7 +511,14 @@ static int disk_resume(struct dirty_log *log)
lc->header.nr_regions = lc->region_count;
/* write the new header */
- return write_header(lc);
+ r = write_header(lc);
+ if (r) {
+ DMWARN("%s: Failed to write header on mirror log device",
+ lc->log_dev->name);
+ fail_log_device(lc);
+ }
+
+ return r;
}
static uint32_t core_get_region_size(struct dirty_log *log)
@@ -516,7 +562,9 @@ static int disk_flush(struct dirty_log *log)
return 0;
r = write_header(lc);
- if (!r)
+ if (r)
+ fail_log_device(lc);
+ else
lc->touched = 0;
return r;
@@ -591,6 +639,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
switch(status) {
case STATUSTYPE_INFO:
+ DMEMIT("1 %s", log->type->name);
break;
case STATUSTYPE_TABLE:
@@ -606,17 +655,17 @@ static int disk_status(struct dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
- char buffer[16];
struct log_c *lc = log->context;
switch(status) {
case STATUSTYPE_INFO:
+ DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
+ lc->log_dev_failed ? 'D' : 'A');
break;
case STATUSTYPE_TABLE:
- format_dev_t(buffer, lc->log_dev->bdev->bd_dev);
DMEMIT("%s %u %s %u ", log->type->name,
- lc->sync == DEFAULTSYNC ? 2 : 3, buffer,
+ lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
lc->region_size);
DMEMIT_SYNC;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 3aa013506967..de54b39e6ffe 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -668,6 +668,9 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
return -EINVAL;
}
+ m->hw_handler.md = dm_table_get_md(ti->table);
+ dm_put(m->hw_handler.md);
+
r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
if (r) {
dm_put_hw_handler(hwht);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 23a642619bed..ef124b71ccc8 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -21,15 +21,11 @@
#include <linux/workqueue.h>
#define DM_MSG_PREFIX "raid1"
+#define DM_IO_PAGES 64
-static struct workqueue_struct *_kmirrord_wq;
-static struct work_struct _kmirrord_work;
-static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
+#define DM_RAID1_HANDLE_ERRORS 0x01
-static inline void wake(void)
-{
- queue_work(_kmirrord_wq, &_kmirrord_work);
-}
+static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
/*-----------------------------------------------------------------
* Region hash
@@ -125,17 +121,23 @@ struct mirror_set {
struct list_head list;
struct region_hash rh;
struct kcopyd_client *kcopyd_client;
+ uint64_t features;
spinlock_t lock; /* protects the next two lists */
struct bio_list reads;
struct bio_list writes;
+ struct dm_io_client *io_client;
+
/* recovery */
region_t nr_regions;
int in_sync;
struct mirror *default_mirror; /* Default mirror */
+ struct workqueue_struct *kmirrord_wq;
+ struct work_struct kmirrord_work;
+
unsigned int nr_mirrors;
struct mirror mirror[0];
};
@@ -153,6 +155,11 @@ static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
return region << rh->region_shift;
}
+static void wake(struct mirror_set *ms)
+{
+ queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
+}
+
/* FIXME move this */
static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
@@ -398,8 +405,7 @@ static void rh_update_states(struct region_hash *rh)
mempool_free(reg, rh->region_pool);
}
- if (!list_empty(&recovered))
- rh->log->type->flush(rh->log);
+ rh->log->type->flush(rh->log);
list_for_each_entry_safe (reg, next, &clean, list)
mempool_free(reg, rh->region_pool);
@@ -471,7 +477,7 @@ static void rh_dec(struct region_hash *rh, region_t region)
spin_unlock_irqrestore(&rh->region_lock, flags);
if (should_wake)
- wake();
+ wake(rh->ms);
}
/*
@@ -558,7 +564,7 @@ static void rh_recovery_end(struct region *reg, int success)
list_add(&reg->list, &reg->rh->recovered_regions);
spin_unlock_irq(&rh->region_lock);
- wake();
+ wake(rh->ms);
}
static void rh_flush(struct region_hash *rh)
@@ -592,7 +598,7 @@ static void rh_start_recovery(struct region_hash *rh)
for (i = 0; i < MAX_RECOVERY; i++)
up(&rh->recovery_count);
- wake();
+ wake(rh->ms);
}
/*
@@ -735,7 +741,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
/*
* We can only read balance if the region is in sync.
*/
- if (rh_in_sync(&ms->rh, region, 0))
+ if (rh_in_sync(&ms->rh, region, 1))
m = choose_mirror(ms, bio->bi_sector);
else
m = ms->default_mirror;
@@ -792,6 +798,14 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
unsigned int i;
struct io_region io[KCOPYD_MAX_REGIONS+1];
struct mirror *m;
+ struct dm_io_request io_req = {
+ .bi_rw = WRITE,
+ .mem.type = DM_IO_BVEC,
+ .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+ .notify.fn = write_callback,
+ .notify.context = bio,
+ .client = ms->io_client,
+ };
for (i = 0; i < ms->nr_mirrors; i++) {
m = ms->mirror + i;
@@ -802,9 +816,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
}
bio_set_ms(bio, ms);
- dm_io_async_bvec(ms->nr_mirrors, io, WRITE,
- bio->bi_io_vec + bio->bi_idx,
- write_callback, bio);
+
+ (void) dm_io(&io_req, ms->nr_mirrors, io, NULL);
}
static void do_writes(struct mirror_set *ms, struct bio_list *writes)
@@ -870,11 +883,10 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
/*-----------------------------------------------------------------
* kmirrord
*---------------------------------------------------------------*/
-static LIST_HEAD(_mirror_sets);
-static DECLARE_RWSEM(_mirror_sets_lock);
-
-static void do_mirror(struct mirror_set *ms)
+static void do_mirror(struct work_struct *work)
{
+ struct mirror_set *ms =container_of(work, struct mirror_set,
+ kmirrord_work);
struct bio_list reads, writes;
spin_lock(&ms->lock);
@@ -890,16 +902,6 @@ static void do_mirror(struct mirror_set *ms)
do_writes(ms, &writes);
}
-static void do_work(struct work_struct *ignored)
-{
- struct mirror_set *ms;
-
- down_read(&_mirror_sets_lock);
- list_for_each_entry (ms, &_mirror_sets, list)
- do_mirror(ms);
- up_read(&_mirror_sets_lock);
-}
-
/*-----------------------------------------------------------------
* Target functions
*---------------------------------------------------------------*/
@@ -931,6 +933,13 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
ms->in_sync = 0;
ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
+ ms->io_client = dm_io_client_create(DM_IO_PAGES);
+ if (IS_ERR(ms->io_client)) {
+ ti->error = "Error creating dm_io client";
+ kfree(ms);
+ return NULL;
+ }
+
if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
ti->error = "Error creating dirty region hash";
kfree(ms);
@@ -946,6 +955,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
while (m--)
dm_put_device(ti, ms->mirror[m].dev);
+ dm_io_client_destroy(ms->io_client);
rh_exit(&ms->rh);
kfree(ms);
}
@@ -978,23 +988,6 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
return 0;
}
-static int add_mirror_set(struct mirror_set *ms)
-{
- down_write(&_mirror_sets_lock);
- list_add_tail(&ms->list, &_mirror_sets);
- up_write(&_mirror_sets_lock);
- wake();
-
- return 0;
-}
-
-static void del_mirror_set(struct mirror_set *ms)
-{
- down_write(&_mirror_sets_lock);
- list_del(&ms->list);
- up_write(&_mirror_sets_lock);
-}
-
/*
* Create dirty log: log_type #log_params <log_params>
*/
@@ -1037,16 +1030,55 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
return dl;
}
+static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
+ unsigned *args_used)
+{
+ unsigned num_features;
+ struct dm_target *ti = ms->ti;
+
+ *args_used = 0;
+
+ if (!argc)
+ return 0;
+
+ if (sscanf(argv[0], "%u", &num_features) != 1) {
+ ti->error = "Invalid number of features";
+ return -EINVAL;
+ }
+
+ argc--;
+ argv++;
+ (*args_used)++;
+
+ if (num_features > argc) {
+ ti->error = "Not enough arguments to support feature count";
+ return -EINVAL;
+ }
+
+ if (!strcmp("handle_errors", argv[0]))
+ ms->features |= DM_RAID1_HANDLE_ERRORS;
+ else {
+ ti->error = "Unrecognised feature requested";
+ return -EINVAL;
+ }
+
+ (*args_used)++;
+
+ return 0;
+}
+
/*
* Construct a mirror mapping:
*
* log_type #log_params <log_params>
* #mirrors [mirror_path offset]{2,}
+ * [#features <features>]
*
* log_type is "core" or "disk"
* #log_params is between 1 and 3
+ *
+ * If present, features must be "handle_errors".
*/
-#define DM_IO_PAGES 64
static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r;
@@ -1070,8 +1102,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv++, argc--;
- if (argc != nr_mirrors * 2) {
- ti->error = "Wrong number of mirror arguments";
+ if (argc < nr_mirrors * 2) {
+ ti->error = "Too few mirror arguments";
dm_destroy_dirty_log(dl);
return -EINVAL;
}
@@ -1096,13 +1128,37 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = ms;
ti->split_io = ms->rh.region_size;
+ ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
+ if (!ms->kmirrord_wq) {
+ DMERR("couldn't start kmirrord");
+ free_context(ms, ti, m);
+ return -ENOMEM;
+ }
+ INIT_WORK(&ms->kmirrord_work, do_mirror);
+
+ r = parse_features(ms, argc, argv, &args_used);
+ if (r) {
+ free_context(ms, ti, ms->nr_mirrors);
+ return r;
+ }
+
+ argv += args_used;
+ argc -= args_used;
+
+ if (argc) {
+ ti->error = "Too many mirror arguments";
+ free_context(ms, ti, ms->nr_mirrors);
+ return -EINVAL;
+ }
+
r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
if (r) {
+ destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
return r;
}
- add_mirror_set(ms);
+ wake(ms);
return 0;
}
@@ -1110,8 +1166,9 @@ static void mirror_dtr(struct dm_target *ti)
{
struct mirror_set *ms = (struct mirror_set *) ti->private;
- del_mirror_set(ms);
+ flush_workqueue(ms->kmirrord_wq);
kcopyd_client_destroy(ms->kcopyd_client);
+ destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
}
@@ -1127,7 +1184,7 @@ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
spin_unlock(&ms->lock);
if (should_wake)
- wake();
+ wake(ms);
}
/*
@@ -1222,11 +1279,9 @@ static void mirror_resume(struct dm_target *ti)
static int mirror_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen)
{
- unsigned int m, sz;
+ unsigned int m, sz = 0;
struct mirror_set *ms = (struct mirror_set *) ti->private;
- sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
-
switch (type) {
case STATUSTYPE_INFO:
DMEMIT("%d ", ms->nr_mirrors);
@@ -1237,13 +1292,21 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
(unsigned long long)ms->rh.log->type->
get_sync_count(ms->rh.log),
(unsigned long long)ms->nr_regions);
+
+ sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
break;
case STATUSTYPE_TABLE:
+ sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
DMEMIT("%d", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++)
DMEMIT(" %s %llu", ms->mirror[m].dev->name,
(unsigned long long)ms->mirror[m].offset);
+
+ if (ms->features & DM_RAID1_HANDLE_ERRORS)
+ DMEMIT(" 1 handle_errors");
}
return 0;
@@ -1251,7 +1314,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
static struct target_type mirror_target = {
.name = "mirror",
- .version = {1, 0, 2},
+ .version = {1, 0, 3},
.module = THIS_MODULE,
.ctr = mirror_ctr,
.dtr = mirror_dtr,
@@ -1270,20 +1333,11 @@ static int __init dm_mirror_init(void)
if (r)
return r;
- _kmirrord_wq = create_singlethread_workqueue("kmirrord");
- if (!_kmirrord_wq) {
- DMERR("couldn't start kmirrord");
- dm_dirty_log_exit();
- return r;
- }
- INIT_WORK(&_kmirrord_work, do_work);
-
r = dm_register_target(&mirror_target);
if (r < 0) {
DMERR("%s: Failed to register mirror target",
mirror_target.name);
dm_dirty_log_exit();
- destroy_workqueue(_kmirrord_wq);
}
return r;
@@ -1297,7 +1351,6 @@ static void __exit dm_mirror_exit(void)
if (r < 0)
DMERR("%s: unregister failed %d", mirror_target.name, r);
- destroy_workqueue(_kmirrord_wq);
dm_dirty_log_exit();
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 05befa91807a..2fc199b0016b 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -425,13 +425,15 @@ static void close_dev(struct dm_dev *d, struct mapped_device *md)
}
/*
- * If possible (ie. blk_size[major] is set), this checks an area
- * of a destination device is valid.
+ * If possible, this checks an area of a destination device is valid.
*/
static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
{
- sector_t dev_size;
- dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+ sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+
+ if (!dev_size)
+ return 1;
+
return ((start < dev_size) && (len <= (dev_size - start)));
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 11a98df298ec..2717a355dc5b 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1236,6 +1236,7 @@ void dm_put(struct mapped_device *md)
free_dev(md);
}
}
+EXPORT_SYMBOL_GPL(dm_put);
/*
* Process the deferred bios
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index b46f6c575f7e..dbc234e3c69f 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*
@@ -45,6 +46,8 @@ struct kcopyd_client {
unsigned int nr_pages;
unsigned int nr_free_pages;
+ struct dm_io_client *io_client;
+
wait_queue_head_t destroyq;
atomic_t nr_jobs;
};
@@ -342,16 +345,20 @@ static void complete_io(unsigned long error, void *context)
static int run_io_job(struct kcopyd_job *job)
{
int r;
+ struct dm_io_request io_req = {
+ .bi_rw = job->rw,
+ .mem.type = DM_IO_PAGE_LIST,
+ .mem.ptr.pl = job->pages,
+ .mem.offset = job->offset,
+ .notify.fn = complete_io,
+ .notify.context = job,
+ .client = job->kc->io_client,
+ };
if (job->rw == READ)
- r = dm_io_async(1, &job->source, job->rw,
- job->pages,
- job->offset, complete_io, job);
-
+ r = dm_io(&io_req, 1, &job->source, NULL);
else
- r = dm_io_async(job->num_dests, job->dests, job->rw,
- job->pages,
- job->offset, complete_io, job);
+ r = dm_io(&io_req, job->num_dests, job->dests, NULL);
return r;
}
@@ -670,8 +677,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
return r;
}
- r = dm_io_get(nr_pages);
- if (r) {
+ kc->io_client = dm_io_client_create(nr_pages);
+ if (IS_ERR(kc->io_client)) {
+ r = PTR_ERR(kc->io_client);
client_free_pages(kc);
kfree(kc);
kcopyd_exit();
@@ -691,7 +699,7 @@ void kcopyd_client_destroy(struct kcopyd_client *kc)
/* Wait for completion of all jobs submitted by this client. */
wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
- dm_io_put(kc->nr_pages);
+ dm_io_client_destroy(kc->io_client);
client_free_pages(kc);
client_del(kc);
kfree(kc);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 2b4315d7e5d6..2901d0c0ee9e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -33,6 +33,7 @@
*/
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/linkage.h>
#include <linux/raid/md.h>
@@ -273,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit)
atomic_set(&new->active, 1);
spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait);
+ new->reshape_position = MaxSector;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
@@ -589,14 +591,41 @@ abort:
return ret;
}
+
+static u32 md_csum_fold(u32 csum)
+{
+ csum = (csum & 0xffff) + (csum >> 16);
+ return (csum & 0xffff) + (csum >> 16);
+}
+
static unsigned int calc_sb_csum(mdp_super_t * sb)
{
+ u64 newcsum = 0;
+ u32 *sb32 = (u32*)sb;
+ int i;
unsigned int disk_csum, csum;
disk_csum = sb->sb_csum;
sb->sb_csum = 0;
- csum = csum_partial((void *)sb, MD_SB_BYTES, 0);
+
+ for (i = 0; i < MD_SB_BYTES/4 ; i++)
+ newcsum += sb32[i];
+ csum = (newcsum & 0xffffffff) + (newcsum>>32);
+
+
+#ifdef CONFIG_ALPHA
+ /* This used to use csum_partial, which was wrong for several
+ * reasons including that different results are returned on
+ * different architectures. It isn't critical that we get exactly
+ * the same return value as before (we always csum_fold before
+ * testing, and that removes any differences). However as we
+ * know that csum_partial always returned a 16bit value on
+ * alphas, do a fold to maximise conformity to previous behaviour.
+ */
+ sb->sb_csum = md_csum_fold(disk_csum);
+#else
sb->sb_csum = disk_csum;
+#endif
return csum;
}
@@ -684,7 +713,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
if (sb->raid_disks <= 0)
goto abort;
- if (csum_fold(calc_sb_csum(sb)) != csum_fold(sb->sb_csum)) {
+ if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
printk(KERN_WARNING "md: invalid superblock checksum on %s\n",
b);
goto abort;
@@ -694,6 +723,17 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
rdev->data_offset = 0;
rdev->sb_size = MD_SB_BYTES;
+ if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+ if (sb->level != 1 && sb->level != 4
+ && sb->level != 5 && sb->level != 6
+ && sb->level != 10) {
+ /* FIXME use a better test */
+ printk(KERN_WARNING
+ "md: bitmaps not supported for this level.\n");
+ goto abort;
+ }
+ }
+
if (sb->level == LEVEL_MULTIPATH)
rdev->desc_nr = -1;
else
@@ -792,16 +832,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->max_disks = MD_SB_DISKS;
if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
- mddev->bitmap_file == NULL) {
- if (mddev->level != 1 && mddev->level != 4
- && mddev->level != 5 && mddev->level != 6
- && mddev->level != 10) {
- /* FIXME use a better test */
- printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
- return -EINVAL;
- }
+ mddev->bitmap_file == NULL)
mddev->bitmap_offset = mddev->default_bitmap_offset;
- }
} else if (mddev->pers == NULL) {
/* Insist on good event counter while assembling */
@@ -1058,6 +1090,18 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
bdevname(rdev->bdev,b));
return -EINVAL;
}
+ if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) {
+ if (sb->level != cpu_to_le32(1) &&
+ sb->level != cpu_to_le32(4) &&
+ sb->level != cpu_to_le32(5) &&
+ sb->level != cpu_to_le32(6) &&
+ sb->level != cpu_to_le32(10)) {
+ printk(KERN_WARNING
+ "md: bitmaps not supported for this level.\n");
+ return -EINVAL;
+ }
+ }
+
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
@@ -1141,14 +1185,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->max_disks = (4096-256)/2;
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
- mddev->bitmap_file == NULL ) {
- if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
- && mddev->level != 10) {
- printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
- return -EINVAL;
- }
+ mddev->bitmap_file == NULL )
mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
- }
+
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
mddev->delta_disks = le32_to_cpu(sb->delta_disks);
@@ -2204,6 +2243,10 @@ static ssize_t
layout_show(mddev_t *mddev, char *page)
{
/* just a number, not meaningful for all levels */
+ if (mddev->reshape_position != MaxSector &&
+ mddev->layout != mddev->new_layout)
+ return sprintf(page, "%d (%d)\n",
+ mddev->new_layout, mddev->layout);
return sprintf(page, "%d\n", mddev->layout);
}
@@ -2212,13 +2255,16 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
- if (mddev->pers)
- return -EBUSY;
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
- mddev->layout = n;
+ if (mddev->pers)
+ return -EBUSY;
+ if (mddev->reshape_position != MaxSector)
+ mddev->new_layout = n;
+ else
+ mddev->layout = n;
return len;
}
static struct md_sysfs_entry md_layout =
@@ -2230,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page)
{
if (mddev->raid_disks == 0)
return 0;
+ if (mddev->reshape_position != MaxSector &&
+ mddev->delta_disks != 0)
+ return sprintf(page, "%d (%d)\n", mddev->raid_disks,
+ mddev->raid_disks - mddev->delta_disks);
return sprintf(page, "%d\n", mddev->raid_disks);
}
@@ -2247,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
if (mddev->pers)
rv = update_raid_disks(mddev, n);
- else
+ else if (mddev->reshape_position != MaxSector) {
+ int olddisks = mddev->raid_disks - mddev->delta_disks;
+ mddev->delta_disks = n - olddisks;
+ mddev->raid_disks = n;
+ } else
mddev->raid_disks = n;
return rv ? rv : len;
}
@@ -2257,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
static ssize_t
chunk_size_show(mddev_t *mddev, char *page)
{
+ if (mddev->reshape_position != MaxSector &&
+ mddev->chunk_size != mddev->new_chunk)
+ return sprintf(page, "%d (%d)\n", mddev->new_chunk,
+ mddev->chunk_size);
return sprintf(page, "%d\n", mddev->chunk_size);
}
@@ -2267,12 +2325,15 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
- if (mddev->pers)
- return -EBUSY;
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
- mddev->chunk_size = n;
+ if (mddev->pers)
+ return -EBUSY;
+ else if (mddev->reshape_position != MaxSector)
+ mddev->new_chunk = n;
+ else
+ mddev->chunk_size = n;
return len;
}
static struct md_sysfs_entry md_chunk_size =
@@ -2637,8 +2698,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
minor = simple_strtoul(buf, &e, 10);
if (e==buf || (*e && *e != '\n') )
return -EINVAL;
- if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
- super_types[major].name == NULL)
+ if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
return -ENOENT;
mddev->major_version = major;
mddev->minor_version = minor;
@@ -2859,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
+static ssize_t
+reshape_position_show(mddev_t *mddev, char *page)
+{
+ if (mddev->reshape_position != MaxSector)
+ return sprintf(page, "%llu\n",
+ (unsigned long long)mddev->reshape_position);
+ strcpy(page, "none\n");
+ return 5;
+}
+
+static ssize_t
+reshape_position_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ char *e;
+ unsigned long long new = simple_strtoull(buf, &e, 10);
+ if (mddev->pers)
+ return -EBUSY;
+ if (buf == e || (*e && *e != '\n'))
+ return -EINVAL;
+ mddev->reshape_position = new;
+ mddev->delta_disks = 0;
+ mddev->new_level = mddev->level;
+ mddev->new_layout = mddev->layout;
+ mddev->new_chunk = mddev->chunk_size;
+ return len;
+}
+
+static struct md_sysfs_entry md_reshape_position =
+__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
+ reshape_position_store);
+
static struct attribute *md_default_attrs[] = {
&md_level.attr,
@@ -2871,6 +2962,7 @@ static struct attribute *md_default_attrs[] = {
&md_new_device.attr,
&md_safe_delay.attr,
&md_array_state.attr,
+ &md_reshape_position.attr,
NULL,
};
@@ -3012,6 +3104,7 @@ static int do_md_run(mddev_t * mddev)
struct gendisk *disk;
struct mdk_personality *pers;
char b[BDEVNAME_SIZE];
+ struct block_device *bdev;
if (list_empty(&mddev->disks))
/* cannot run an array with no devices.. */
@@ -3239,7 +3332,13 @@ static int do_md_run(mddev_t * mddev)
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
- mddev->changed = 1;
+ bdev = bdget_disk(mddev->gendisk, 0);
+ if (bdev) {
+ bd_set_size(bdev, mddev->array_size << 1);
+ blkdev_ioctl(bdev->bd_inode, NULL, BLKRRPART, 0);
+ bdput(bdev);
+ }
+
md_new_event(mddev);
kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
return 0;
@@ -3361,7 +3460,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->pers = NULL;
set_capacity(disk, 0);
- mddev->changed = 1;
if (mddev->ro)
mddev->ro = 0;
@@ -3409,6 +3507,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->size = 0;
mddev->raid_disks = 0;
mddev->recovery_cp = 0;
+ mddev->reshape_position = MaxSector;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4019,7 +4118,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
if (info->raid_disks == 0) {
/* just setting version number for superblock loading */
if (info->major_version < 0 ||
- info->major_version >= sizeof(super_types)/sizeof(super_types[0]) ||
+ info->major_version >= ARRAY_SIZE(super_types) ||
super_types[info->major_version].name == NULL) {
/* maybe try to auto-load a module? */
printk(KERN_INFO
@@ -4500,20 +4599,6 @@ static int md_release(struct inode *inode, struct file * file)
return 0;
}
-static int md_media_changed(struct gendisk *disk)
-{
- mddev_t *mddev = disk->private_data;
-
- return mddev->changed;
-}
-
-static int md_revalidate(struct gendisk *disk)
-{
- mddev_t *mddev = disk->private_data;
-
- mddev->changed = 0;
- return 0;
-}
static struct block_device_operations md_fops =
{
.owner = THIS_MODULE,
@@ -4521,8 +4606,6 @@ static struct block_device_operations md_fops =
.release = md_release,
.ioctl = md_ioctl,
.getgeo = md_getgeo,
- .media_changed = md_media_changed,
- .revalidate_disk= md_revalidate,
};
static int md_thread(void * arg)
@@ -4941,15 +5024,6 @@ static int md_seq_open(struct inode *inode, struct file *file)
return error;
}
-static int md_seq_release(struct inode *inode, struct file *file)
-{
- struct seq_file *m = file->private_data;
- struct mdstat_info *mi = m->private;
- m->private = NULL;
- kfree(mi);
- return seq_release(inode, file);
-}
-
static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
{
struct seq_file *m = filp->private_data;
@@ -4971,7 +5045,7 @@ static const struct file_operations md_seq_fops = {
.open = md_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = md_seq_release,
+ .release = seq_release_private,
.poll = mdstat_poll,
};
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 97ee870b265d..1b7130cad21f 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2063,7 +2063,6 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
*/
mddev->array_size = sectors>>1;
set_capacity(mddev->gendisk, mddev->array_size << 1);
- mddev->changed = 1;
if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->size << 1;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8d59914f2057..a72e70ad0975 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -353,8 +353,8 @@ static int grow_stripes(raid5_conf_t *conf, int num)
struct kmem_cache *sc;
int devs = conf->raid_disks;
- sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev));
- sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev));
+ sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev));
+ sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev));
conf->active_name = 0;
sc = kmem_cache_create(conf->cache_name[conf->active_name],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
@@ -3864,7 +3864,6 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1;
set_capacity(mddev->gendisk, mddev->array_size << 1);
- mddev->changed = 1;
if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->size << 1;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -3999,7 +3998,6 @@ static void end_reshape(raid5_conf_t *conf)
conf->mddev->array_size = conf->mddev->size *
(conf->raid_disks - conf->max_degraded);
set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1);
- conf->mddev->changed = 1;
bdev = bdget_disk(conf->mddev->gendisk, 0);
if (bdev) {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 68ed3a788083..9200a30dd1b9 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -3,7 +3,7 @@
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
- * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
*/
#include "dvb-usb-common.h"
#include <linux/usb/input.h>
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f5d40aa3d27f..f64546c6aeb5 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -266,7 +266,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
{
/* internal */
-// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 0349a4b5da3f..aece458cfe12 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -223,7 +223,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
static int dib7000p_sad_calib(struct dib7000p_state *state)
{
/* internal */
-// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 110536843e8e..e725f612a6b7 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -1,6 +1,6 @@
/*
TDA10021 - Single Chip Cable Channel Receiver driver module
- used on the the Siemens DVB-C cards
+ used on the Siemens DVB-C cards
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 54d7b07571b8..23fd0303c91b 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -306,7 +306,7 @@ static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
* The ves1893 sometimes returns sync values that make no sense,
* because, e.g., the SIGNAL bit is 0, while some of the higher
* bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
- * Tests showed that the the VITERBI and SYNC bits are returned
+ * Tests showed that the VITERBI and SYNC bits are returned
* reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
* If such a case occurs, we read the value again, until we get a
* valid value.
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 563a8319e608..54ccc6e1f92e 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -70,7 +70,7 @@ static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
if (ret != 2 + len) {
- em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+ em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
return -EIO;
}
for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index bec67609500f..2c7b158ce7e1 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1729,7 +1729,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
endpoint = &interface->cur_altsetting->endpoint[1].desc;
- /* check if the the device has the iso in endpoint at the correct place */
+ /* check if the device has the iso in endpoint at the correct place */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
index f5e848410311..f9f3584281d8 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/video/pwc/philips.txt
@@ -54,9 +54,9 @@ fps
Specifies the desired framerate. Is an integer in the range of 4-30.
fbufs
- This paramter specifies the number of internal buffers to use for storing
+ This parameter specifies the number of internal buffers to use for storing
frames from the cam. This will help if the process that reads images from
- the cam is a bit slow or momentarely busy. However, on slow machines it
+ the cam is a bit slow or momentarily busy. However, on slow machines it
only introduces lag, so choose carefully. The default is 3, which is
reasonable. You can set it between 2 and 5.
@@ -209,7 +209,7 @@ trace
128 0x80 PWCX debugging Off
- For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+ For example, to trace the open() & read() functions, sum 8 + 4 = 12,
so you would supply trace=12 during insmod or modprobe. If
you want to turn the initialization and probing tracing off, set trace=0.
The default value for trace is 35 (0x23).
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 876fd2768242..982b115193f8 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -28,7 +28,7 @@
*
* Portions of this code were also copied from usbvideo.c
*
- * Special thanks to the the whole team at Sourceforge for help making
+ * Special thanks to the whole team at Sourceforge for help making
* this driver become a reality. Notably:
* Andy Armstrong who reverse engineered the color encoding and
* Pavel Machek and Chris Cheney who worked on reverse engineering the
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index d6b4c607453b..ddc7ae029dd3 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -571,7 +571,7 @@ mpi_fc.h
* 11-02-00 01.01.01 Original release for post 1.0 work
* 12-04-00 01.01.02 Added messages for Common Transport Send and
* Primitive Send.
- * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
+ * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix
* and modified the FcPrimitiveSend flags.
* 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
* field.
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 97471af4309c..5021d1a2a1d4 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -3585,7 +3585,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
* index = chain_idx
*
* Calculate the number of chain buffers needed(plus 1) per I/O
- * then multiply the the maximum number of simultaneous cmds
+ * then multiply the maximum number of simultaneous cmds
*
* num_sge = num sge in request frame + last chain buffer
* scale = num sge per chain buffer if no chain element
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b6c16704aaab..7385acfa1dd9 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -501,9 +501,9 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
- spin_lock_irqsave(host->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->removed);
- spin_unlock_irqrestore(host->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
#endif
mmc_schedule_delayed_work(&host->detect, delay);
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index d28e0fc85e12..479d32b57a1e 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,4 @@
# drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -231,45 +230,6 @@ config MTD_ABSENT
the system regardless of media presence. Device nodes created
with this driver will return -ENODEV upon access.
-config MTD_OBSOLETE_CHIPS
- bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
- help
- This option does not enable any code directly, but will allow you to
- select some other chip drivers which are now considered obsolete,
- because the generic CONFIG_JEDECPROBE code above should now detect
- the chips which are supported by these drivers, and allow the generic
- CFI-compatible drivers to drive the chips. Say 'N' here unless you have
- already tried the CONFIG_JEDECPROBE method and reported its failure
- to the MTD mailing list at <linux-mtd@lists.infradead.org>
-
-config MTD_AMDSTD
- tristate "AMD compatible flash chip support (non-CFI)"
- depends on MTD_OBSOLETE_CHIPS && BROKEN
- help
- This option enables support for flash chips using AMD-compatible
- commands, including some which are not CFI-compatible and hence
- cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
- It also works on AMD compatible chips that do conform to CFI.
-
-config MTD_SHARP
- tristate "pre-CFI Sharp chip support"
- depends on MTD_OBSOLETE_CHIPS
- help
- This option enables support for flash chips using Sharp-compatible
- commands, including some which are not CFI-compatible and hence
- cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
-
-config MTD_JEDEC
- tristate "JEDEC device support"
- depends on MTD_OBSOLETE_CHIPS && BROKEN
- help
- Enable older JEDEC flash interface devices for self
- programming flash. It is commonly used in older AMD chips. It is
- only called JEDEC because the JEDEC association
- <http://www.jedec.org/> distributes the identification codes for the
- chips.
-
config MTD_XIP
bool "XIP aware MTD support"
depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
index 75bc1c2a0f43..36582412ccda 100644
--- a/drivers/mtd/chips/Makefile
+++ b/drivers/mtd/chips/Makefile
@@ -1,19 +1,15 @@
#
# linux/drivers/chips/Makefile
#
-# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
obj-$(CONFIG_MTD) += chipreg.o
-obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
obj-$(CONFIG_MTD_CFI) += cfi_probe.o
obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o
obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
-obj-$(CONFIG_MTD_JEDEC) += jedec.o
obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o
obj-$(CONFIG_MTD_RAM) += map_ram.o
obj-$(CONFIG_MTD_ROM) += map_rom.o
-obj-$(CONFIG_MTD_SHARP) += sharp.o
obj-$(CONFIG_MTD_ABSENT) += map_absent.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
deleted file mode 100644
index e7999f15d85a..000000000000
--- a/drivers/mtd/chips/amd_flash.c
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- * MTD map driver for AMD compatible flash chips (non-CFI)
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
- * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
- *
- * Copyright (c) 2001 Axis Communications AB
- *
- * This file is under GPL.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/flashchip.h>
-
-/* There's no limit. It exists only to avoid realloc. */
-#define MAX_AMD_CHIPS 8
-
-#define DEVICE_TYPE_X8 (8 / 8)
-#define DEVICE_TYPE_X16 (16 / 8)
-#define DEVICE_TYPE_X32 (32 / 8)
-
-/* Addresses */
-#define ADDR_MANUFACTURER 0x0000
-#define ADDR_DEVICE_ID 0x0001
-#define ADDR_SECTOR_LOCK 0x0002
-#define ADDR_HANDSHAKE 0x0003
-#define ADDR_UNLOCK_1 0x0555
-#define ADDR_UNLOCK_2 0x02AA
-
-/* Commands */
-#define CMD_UNLOCK_DATA_1 0x00AA
-#define CMD_UNLOCK_DATA_2 0x0055
-#define CMD_MANUFACTURER_UNLOCK_DATA 0x0090
-#define CMD_UNLOCK_BYPASS_MODE 0x0020
-#define CMD_PROGRAM_UNLOCK_DATA 0x00A0
-#define CMD_RESET_DATA 0x00F0
-#define CMD_SECTOR_ERASE_UNLOCK_DATA 0x0080
-#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x0030
-
-#define CMD_UNLOCK_SECTOR 0x0060
-
-/* Manufacturers */
-#define MANUFACTURER_AMD 0x0001
-#define MANUFACTURER_ATMEL 0x001F
-#define MANUFACTURER_FUJITSU 0x0004
-#define MANUFACTURER_ST 0x0020
-#define MANUFACTURER_SST 0x00BF
-#define MANUFACTURER_TOSHIBA 0x0098
-
-/* AMD */
-#define AM29F800BB 0x2258
-#define AM29F800BT 0x22D6
-#define AM29LV800BB 0x225B
-#define AM29LV800BT 0x22DA
-#define AM29LV160DT 0x22C4
-#define AM29LV160DB 0x2249
-#define AM29BDS323D 0x22D1
-
-/* Atmel */
-#define AT49xV16x 0x00C0
-#define AT49xV16xT 0x00C2
-
-/* Fujitsu */
-#define MBM29LV160TE 0x22C4
-#define MBM29LV160BE 0x2249
-#define MBM29LV800BB 0x225B
-
-/* ST - www.st.com */
-#define M29W800T 0x00D7
-#define M29W160DT 0x22C4
-#define M29W160DB 0x2249
-
-/* SST */
-#define SST39LF800 0x2781
-#define SST39LF160 0x2782
-
-/* Toshiba */
-#define TC58FVT160 0x00C2
-#define TC58FVB160 0x0043
-
-#define D6_MASK 0x40
-
-struct amd_flash_private {
- int device_type;
- int interleave;
- int numchips;
- unsigned long chipshift;
- struct flchip chips[0];
-};
-
-struct amd_flash_info {
- const __u16 mfr_id;
- const __u16 dev_id;
- const char *name;
- const u_long size;
- const int numeraseregions;
- const struct mtd_erase_region_info regions[4];
-};
-
-
-
-static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
- u_char *);
-static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
- const u_char *);
-static int amd_flash_erase(struct mtd_info *, struct erase_info *);
-static void amd_flash_sync(struct mtd_info *);
-static int amd_flash_suspend(struct mtd_info *);
-static void amd_flash_resume(struct mtd_info *);
-static void amd_flash_destroy(struct mtd_info *);
-static struct mtd_info *amd_flash_probe(struct map_info *map);
-
-
-static struct mtd_chip_driver amd_flash_chipdrv = {
- .probe = amd_flash_probe,
- .destroy = amd_flash_destroy,
- .name = "amd_flash",
- .module = THIS_MODULE
-};
-
-static inline __u32 wide_read(struct map_info *map, __u32 addr)
-{
- if (map->buswidth == 1) {
- return map_read8(map, addr);
- } else if (map->buswidth == 2) {
- return map_read16(map, addr);
- } else if (map->buswidth == 4) {
- return map_read32(map, addr);
- }
-
- return 0;
-}
-
-static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
-{
- if (map->buswidth == 1) {
- map_write8(map, val, addr);
- } else if (map->buswidth == 2) {
- map_write16(map, val, addr);
- } else if (map->buswidth == 4) {
- map_write32(map, val, addr);
- }
-}
-
-static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
-{
- const struct amd_flash_private *private = map->fldrv_priv;
- if ((private->interleave == 2) &&
- (private->device_type == DEVICE_TYPE_X16)) {
- cmd |= (cmd << 16);
- }
-
- return cmd;
-}
-
-static inline void send_unlock(struct map_info *map, unsigned long base)
-{
- wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
- base + (map->buswidth * ADDR_UNLOCK_1));
- wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
- base + (map->buswidth * ADDR_UNLOCK_2));
-}
-
-static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
-{
- send_unlock(map, base);
- wide_write(map, make_cmd(map, cmd),
- base + (map->buswidth * ADDR_UNLOCK_1));
-}
-
-static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
- __u32 cmd, unsigned long addr)
-{
- send_unlock(map, base);
- wide_write(map, make_cmd(map, cmd), addr);
-}
-
-static inline int flash_is_busy(struct map_info *map, unsigned long addr,
- int interleave)
-{
-
- if ((interleave == 2) && (map->buswidth == 4)) {
- __u32 read1, read2;
-
- read1 = wide_read(map, addr);
- read2 = wide_read(map, addr);
-
- return (((read1 >> 16) & D6_MASK) !=
- ((read2 >> 16) & D6_MASK)) ||
- (((read1 & 0xffff) & D6_MASK) !=
- ((read2 & 0xffff) & D6_MASK));
- }
-
- return ((wide_read(map, addr) & D6_MASK) !=
- (wide_read(map, addr) & D6_MASK));
-}
-
-static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
- int unlock)
-{
- /* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
- int SLA = unlock ?
- (sect_addr | (0x40 * map->buswidth)) :
- (sect_addr & ~(0x40 * map->buswidth)) ;
-
- __u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
-
- wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
- wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
- wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
- wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
-}
-
-static inline int is_sector_locked(struct map_info *map,
- unsigned long sect_addr)
-{
- int status;
-
- wide_write(map, CMD_RESET_DATA, 0);
- send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
-
- /* status is 0x0000 for unlocked and 0x0001 for locked */
- status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
- wide_write(map, CMD_RESET_DATA, 0);
- return status;
-}
-
-static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
- int is_unlock)
-{
- struct map_info *map;
- struct mtd_erase_region_info *merip;
- int eraseoffset, erasesize, eraseblocks;
- int i;
- int retval = 0;
- int lock_status;
-
- map = mtd->priv;
-
- /* Pass the whole chip through sector by sector and check for each
- sector if the sector and the given interval overlap */
- for(i = 0; i < mtd->numeraseregions; i++) {
- merip = &mtd->eraseregions[i];
-
- eraseoffset = merip->offset;
- erasesize = merip->erasesize;
- eraseblocks = merip->numblocks;
-
- if (ofs > eraseoffset + erasesize)
- continue;
-
- while (eraseblocks > 0) {
- if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
- unlock_sector(map, eraseoffset, is_unlock);
-
- lock_status = is_sector_locked(map, eraseoffset);
-
- if (is_unlock && lock_status) {
- printk("Cannot unlock sector at address %x length %xx\n",
- eraseoffset, merip->erasesize);
- retval = -1;
- } else if (!is_unlock && !lock_status) {
- printk("Cannot lock sector at address %x length %x\n",
- eraseoffset, merip->erasesize);
- retval = -1;
- }
- }
- eraseoffset += erasesize;
- eraseblocks --;
- }
- }
- return retval;
-}
-
-static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
- return amd_flash_do_unlock(mtd, ofs, len, 1);
-}
-
-static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
- return amd_flash_do_unlock(mtd, ofs, len, 0);
-}
-
-
-/*
- * Reads JEDEC manufacturer ID and device ID and returns the index of the first
- * matching table entry (-1 if not found or alias for already found chip).
- */
-static int probe_new_chip(struct mtd_info *mtd, __u32 base,
- struct flchip *chips,
- struct amd_flash_private *private,
- const struct amd_flash_info *table, int table_size)
-{
- __u32 mfr_id;
- __u32 dev_id;
- struct map_info *map = mtd->priv;
- struct amd_flash_private temp;
- int i;
-
- temp.device_type = DEVICE_TYPE_X16; // Assume X16 (FIXME)
- temp.interleave = 2;
- map->fldrv_priv = &temp;
-
- /* Enter autoselect mode. */
- send_cmd(map, base, CMD_RESET_DATA);
- send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
-
- mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
- dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
-
- if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
- ((dev_id >> 16) == (dev_id & 0xffff))) {
- mfr_id &= 0xffff;
- dev_id &= 0xffff;
- } else {
- temp.interleave = 1;
- }
-
- for (i = 0; i < table_size; i++) {
- if ((mfr_id == table[i].mfr_id) &&
- (dev_id == table[i].dev_id)) {
- if (chips) {
- int j;
-
- /* Is this an alias for an already found chip?
- * In that case that chip should be in
- * autoselect mode now.
- */
- for (j = 0; j < private->numchips; j++) {
- __u32 mfr_id_other;
- __u32 dev_id_other;
-
- mfr_id_other =
- wide_read(map, chips[j].start +
- (map->buswidth *
- ADDR_MANUFACTURER
- ));
- dev_id_other =
- wide_read(map, chips[j].start +
- (map->buswidth *
- ADDR_DEVICE_ID));
- if (temp.interleave == 2) {
- mfr_id_other &= 0xffff;
- dev_id_other &= 0xffff;
- }
- if ((mfr_id_other == mfr_id) &&
- (dev_id_other == dev_id)) {
-
- /* Exit autoselect mode. */
- send_cmd(map, base,
- CMD_RESET_DATA);
-
- return -1;
- }
- }
-
- if (private->numchips == MAX_AMD_CHIPS) {
- printk(KERN_WARNING
- "%s: Too many flash chips "
- "detected. Increase "
- "MAX_AMD_CHIPS from %d.\n",
- map->name, MAX_AMD_CHIPS);
-
- return -1;
- }
-
- chips[private->numchips].start = base;
- chips[private->numchips].state = FL_READY;
- chips[private->numchips].mutex =
- &chips[private->numchips]._spinlock;
- private->numchips++;
- }
-
- printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
- temp.interleave, (table[i].size)/(1024*1024),
- table[i].name, base);
-
- mtd->size += table[i].size * temp.interleave;
- mtd->numeraseregions += table[i].numeraseregions;
-
- break;
- }
- }
-
- /* Exit autoselect mode. */
- send_cmd(map, base, CMD_RESET_DATA);
-
- if (i == table_size) {
- printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
- "mfr id 0x%x, dev id 0x%x\n", map->name,
- base, mfr_id, dev_id);
- map->fldrv_priv = NULL;
-
- return -1;
- }
-
- private->device_type = temp.device_type;
- private->interleave = temp.interleave;
-
- return i;
-}
-
-
-
-static struct mtd_info *amd_flash_probe(struct map_info *map)
-{
- static const struct amd_flash_info table[] = {
- {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29LV160DT,
- .name = "AMD AM29LV160DT",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29LV160DB,
- .name = "AMD AM29LV160DB",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
- .mfr_id = MANUFACTURER_TOSHIBA,
- .dev_id = TC58FVT160,
- .name = "Toshiba TC58FVT160",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_FUJITSU,
- .dev_id = MBM29LV160TE,
- .name = "Fujitsu MBM29LV160TE",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_TOSHIBA,
- .dev_id = TC58FVB160,
- .name = "Toshiba TC58FVB160",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
- .mfr_id = MANUFACTURER_FUJITSU,
- .dev_id = MBM29LV160BE,
- .name = "Fujitsu MBM29LV160BE",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29LV800BB,
- .name = "AMD AM29LV800BB",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29F800BB,
- .name = "AMD AM29F800BB",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29LV800BT,
- .name = "AMD AM29LV800BT",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
- { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29F800BT,
- .name = "AMD AM29F800BT",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
- { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29LV800BB,
- .name = "AMD AM29LV800BB",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
- { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_FUJITSU,
- .dev_id = MBM29LV800BB,
- .name = "Fujitsu MBM29LV800BB",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
- }
- }, {
- .mfr_id = MANUFACTURER_ST,
- .dev_id = M29W800T,
- .name = "ST M29W800T",
- .size = 0x00100000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
- { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_ST,
- .dev_id = M29W160DT,
- .name = "ST M29W160DT",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
- }
- }, {
- .mfr_id = MANUFACTURER_ST,
- .dev_id = M29W160DB,
- .name = "ST M29W160DB",
- .size = 0x00200000,
- .numeraseregions = 4,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
- { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
- { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29BDS323D,
- .name = "AMD AM29BDS323D",
- .size = 0x00400000,
- .numeraseregions = 3,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
- { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
- { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
- .mfr_id = MANUFACTURER_ATMEL,
- .dev_id = AT49xV16x,
- .name = "Atmel AT49xV16x",
- .size = 0x00200000,
- .numeraseregions = 2,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 },
- { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
- }
- }, {
- .mfr_id = MANUFACTURER_ATMEL,
- .dev_id = AT49xV16xT,
- .name = "Atmel AT49xV16xT",
- .size = 0x00200000,
- .numeraseregions = 2,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 }
- }
- }
- };
-
- struct mtd_info *mtd;
- struct flchip chips[MAX_AMD_CHIPS];
- int table_pos[MAX_AMD_CHIPS];
- struct amd_flash_private temp;
- struct amd_flash_private *private;
- u_long size;
- unsigned long base;
- int i;
- int reg_idx;
- int offset;
-
- mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
- if (!mtd) {
- printk(KERN_WARNING
- "%s: kmalloc failed for info structure\n", map->name);
- return NULL;
- }
- mtd->priv = map;
-
- memset(&temp, 0, sizeof(temp));
-
- printk("%s: Probing for AMD compatible flash...\n", map->name);
-
- if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
- ARRAY_SIZE(table)))
- == -1) {
- printk(KERN_WARNING
- "%s: Found no AMD compatible device at location zero\n",
- map->name);
- kfree(mtd);
-
- return NULL;
- }
-
- chips[0].start = 0;
- chips[0].state = FL_READY;
- chips[0].mutex = &chips[0]._spinlock;
- temp.numchips = 1;
- for (size = mtd->size; size > 1; size >>= 1) {
- temp.chipshift++;
- }
- switch (temp.interleave) {
- case 2:
- temp.chipshift += 1;
- break;
- case 4:
- temp.chipshift += 2;
- break;
- }
-
- /* Find out if there are any more chips in the map. */
- for (base = (1 << temp.chipshift);
- base < map->size;
- base += (1 << temp.chipshift)) {
- int numchips = temp.numchips;
- table_pos[numchips] = probe_new_chip(mtd, base, chips,
- &temp, table, ARRAY_SIZE(table));
- }
-
- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
- mtd->numeraseregions, GFP_KERNEL);
- if (!mtd->eraseregions) {
- printk(KERN_WARNING "%s: Failed to allocate "
- "memory for MTD erase region info\n", map->name);
- kfree(mtd);
- map->fldrv_priv = NULL;
- return NULL;
- }
-
- reg_idx = 0;
- offset = 0;
- for (i = 0; i < temp.numchips; i++) {
- int dev_size;
- int j;
-
- dev_size = 0;
- for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
- mtd->eraseregions[reg_idx].offset = offset +
- (table[table_pos[i]].regions[j].offset *
- temp.interleave);
- mtd->eraseregions[reg_idx].erasesize =
- table[table_pos[i]].regions[j].erasesize *
- temp.interleave;
- mtd->eraseregions[reg_idx].numblocks =
- table[table_pos[i]].regions[j].numblocks;
- if (mtd->erasesize <
- mtd->eraseregions[reg_idx].erasesize) {
- mtd->erasesize =
- mtd->eraseregions[reg_idx].erasesize;
- }
- dev_size += mtd->eraseregions[reg_idx].erasesize *
- mtd->eraseregions[reg_idx].numblocks;
- reg_idx++;
- }
- offset += dev_size;
- }
- mtd->type = MTD_NORFLASH;
- mtd->writesize = 1;
- mtd->flags = MTD_CAP_NORFLASH;
- mtd->name = map->name;
- mtd->erase = amd_flash_erase;
- mtd->read = amd_flash_read;
- mtd->write = amd_flash_write;
- mtd->sync = amd_flash_sync;
- mtd->suspend = amd_flash_suspend;
- mtd->resume = amd_flash_resume;
- mtd->lock = amd_flash_lock;
- mtd->unlock = amd_flash_unlock;
-
- private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
- temp.numchips), GFP_KERNEL);
- if (!private) {
- printk(KERN_WARNING
- "%s: kmalloc failed for private structure\n", map->name);
- kfree(mtd);
- map->fldrv_priv = NULL;
- return NULL;
- }
- memcpy(private, &temp, sizeof(temp));
- memcpy(private->chips, chips,
- sizeof(struct flchip) * private->numchips);
- for (i = 0; i < private->numchips; i++) {
- init_waitqueue_head(&private->chips[i].wq);
- spin_lock_init(&private->chips[i]._spinlock);
- }
-
- map->fldrv_priv = private;
-
- map->fldrv = &amd_flash_chipdrv;
-
- __module_get(THIS_MODULE);
- return mtd;
-}
-
-
-
-static inline int read_one_chip(struct map_info *map, struct flchip *chip,
- loff_t adr, size_t len, u_char *buf)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long timeo = jiffies + HZ;
-
-retry:
- spin_lock_bh(chip->mutex);
-
- if (chip->state != FL_READY){
- printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
- map->name, chip->state);
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
-
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-
- if(signal_pending(current)) {
- return -EINTR;
- }
-
- timeo = jiffies + HZ;
-
- goto retry;
- }
-
- adr += chip->start;
-
- chip->state = FL_READY;
-
- map_copy_from(map, buf, adr, len);
-
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-
- return 0;
-}
-
-
-
-static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct amd_flash_private *private = map->fldrv_priv;
- unsigned long ofs;
- int chipnum;
- int ret = 0;
-
- if ((from + len) > mtd->size) {
- printk(KERN_WARNING "%s: read request past end of device "
- "(0x%lx)\n", map->name, (unsigned long)from + len);
-
- return -EINVAL;
- }
-
- /* Offset within the first chip that the first read should start. */
- chipnum = (from >> private->chipshift);
- ofs = from - (chipnum << private->chipshift);
-
- *retlen = 0;
-
- while (len) {
- unsigned long this_len;
-
- if (chipnum >= private->numchips) {
- break;
- }
-
- if ((len + ofs - 1) >> private->chipshift) {
- this_len = (1 << private->chipshift) - ofs;
- } else {
- this_len = len;
- }
-
- ret = read_one_chip(map, &private->chips[chipnum], ofs,
- this_len, buf);
- if (ret) {
- break;
- }
-
- *retlen += this_len;
- len -= this_len;
- buf += this_len;
-
- ofs = 0;
- chipnum++;
- }
-
- return ret;
-}
-
-
-
-static int write_one_word(struct map_info *map, struct flchip *chip,
- unsigned long adr, __u32 datum)
-{
- unsigned long timeo = jiffies + HZ;
- struct amd_flash_private *private = map->fldrv_priv;
- DECLARE_WAITQUEUE(wait, current);
- int ret = 0;
- int times_left;
-
-retry:
- spin_lock_bh(chip->mutex);
-
- if (chip->state != FL_READY){
- printk("%s: waiting for chip to write, state = %d\n",
- map->name, chip->state);
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
-
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- printk(KERN_INFO "%s: woke up to write\n", map->name);
- if(signal_pending(current))
- return -EINTR;
-
- timeo = jiffies + HZ;
-
- goto retry;
- }
-
- chip->state = FL_WRITING;
-
- adr += chip->start;
- ENABLE_VPP(map);
- send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
- wide_write(map, datum, adr);
-
- times_left = 500000;
- while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
- if (need_resched()) {
- spin_unlock_bh(chip->mutex);
- schedule();
- spin_lock_bh(chip->mutex);
- }
- }
-
- if (!times_left) {
- printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
- map->name, adr);
- ret = -EIO;
- } else {
- __u32 verify;
- if ((verify = wide_read(map, adr)) != datum) {
- printk(KERN_WARNING "%s: write to 0x%lx failed. "
- "datum = %x, verify = %x\n",
- map->name, adr, datum, verify);
- ret = -EIO;
- }
- }
-
- DISABLE_VPP(map);
- chip->state = FL_READY;
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-
- return ret;
-}
-
-
-
-static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct amd_flash_private *private = map->fldrv_priv;
- int ret = 0;
- int chipnum;
- unsigned long ofs;
- unsigned long chipstart;
-
- *retlen = 0;
- if (!len) {
- return 0;
- }
-
- chipnum = to >> private->chipshift;
- ofs = to - (chipnum << private->chipshift);
- chipstart = private->chips[chipnum].start;
-
- /* If it's not bus-aligned, do the first byte write. */
- if (ofs & (map->buswidth - 1)) {
- unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
- int i = ofs - bus_ofs;
- int n = 0;
- u_char tmp_buf[4];
- __u32 datum;
-
- map_copy_from(map, tmp_buf,
- bus_ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len && i < map->buswidth)
- tmp_buf[i++] = buf[n++], len--;
-
- if (map->buswidth == 2) {
- datum = *(__u16*)tmp_buf;
- } else if (map->buswidth == 4) {
- datum = *(__u32*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
- }
-
- ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
- datum);
- if (ret) {
- return ret;
- }
-
- ofs += n;
- buf += n;
- (*retlen) += n;
-
- if (ofs >> private->chipshift) {
- chipnum++;
- ofs = 0;
- if (chipnum == private->numchips) {
- return 0;
- }
- }
- }
-
- /* We are now aligned, write as much as possible. */
- while(len >= map->buswidth) {
- __u32 datum;
-
- if (map->buswidth == 1) {
- datum = *(__u8*)buf;
- } else if (map->buswidth == 2) {
- datum = *(__u16*)buf;
- } else if (map->buswidth == 4) {
- datum = *(__u32*)buf;
- } else {
- return -EINVAL;
- }
-
- ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
- if (ret) {
- return ret;
- }
-
- ofs += map->buswidth;
- buf += map->buswidth;
- (*retlen) += map->buswidth;
- len -= map->buswidth;
-
- if (ofs >> private->chipshift) {
- chipnum++;
- ofs = 0;
- if (chipnum == private->numchips) {
- return 0;
- }
- chipstart = private->chips[chipnum].start;
- }
- }
-
- if (len & (map->buswidth - 1)) {
- int i = 0, n = 0;
- u_char tmp_buf[2];
- __u32 datum;
-
- map_copy_from(map, tmp_buf,
- ofs + private->chips[chipnum].start,
- map->buswidth);
- while (len--) {
- tmp_buf[i++] = buf[n++];
- }
-
- if (map->buswidth == 2) {
- datum = *(__u16*)tmp_buf;
- } else if (map->buswidth == 4) {
- datum = *(__u32*)tmp_buf;
- } else {
- return -EINVAL; /* should never happen, but be safe */
- }
-
- ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
- if (ret) {
- return ret;
- }
-
- (*retlen) += n;
- }
-
- return 0;
-}
-
-
-
-static inline int erase_one_block(struct map_info *map, struct flchip *chip,
- unsigned long adr, u_long size)
-{
- unsigned long timeo = jiffies + HZ;
- struct amd_flash_private *private = map->fldrv_priv;
- DECLARE_WAITQUEUE(wait, current);
-
-retry:
- spin_lock_bh(chip->mutex);
-
- if (chip->state != FL_READY){
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
-
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-
- if (signal_pending(current)) {
- return -EINTR;
- }
-
- timeo = jiffies + HZ;
-
- goto retry;
- }
-
- chip->state = FL_ERASING;
-
- adr += chip->start;
- ENABLE_VPP(map);
- send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
- send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
-
- timeo = jiffies + (HZ * 20);
-
- spin_unlock_bh(chip->mutex);
- msleep(1000);
- spin_lock_bh(chip->mutex);
-
- while (flash_is_busy(map, adr, private->interleave)) {
-
- if (chip->state != FL_ERASING) {
- /* Someone's suspended the erase. Sleep */
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
- printk(KERN_INFO "%s: erase suspended. Sleeping\n",
- map->name);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-
- if (signal_pending(current)) {
- return -EINTR;
- }
-
- timeo = jiffies + (HZ*2); /* FIXME */
- spin_lock_bh(chip->mutex);
- continue;
- }
-
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
- chip->state = FL_READY;
- spin_unlock_bh(chip->mutex);
- printk(KERN_WARNING "%s: waiting for erase to complete "
- "timed out.\n", map->name);
- DISABLE_VPP(map);
-
- return -EIO;
- }
-
- /* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock_bh(chip->mutex);
-
- if (need_resched())
- schedule();
- else
- udelay(1);
-
- spin_lock_bh(chip->mutex);
- }
-
- /* Verify every single word */
- {
- int address;
- int error = 0;
- __u8 verify;
-
- for (address = adr; address < (adr + size); address++) {
- if ((verify = map_read8(map, address)) != 0xFF) {
- error = 1;
- break;
- }
- }
- if (error) {
- chip->state = FL_READY;
- spin_unlock_bh(chip->mutex);
- printk(KERN_WARNING
- "%s: verify error at 0x%x, size %ld.\n",
- map->name, address, size);
- DISABLE_VPP(map);
-
- return -EIO;
- }
- }
-
- DISABLE_VPP(map);
- chip->state = FL_READY;
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-
- return 0;
-}
-
-
-
-static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- struct map_info *map = mtd->priv;
- struct amd_flash_private *private = map->fldrv_priv;
- unsigned long adr, len;
- int chipnum;
- int ret = 0;
- int i;
- int first;
- struct mtd_erase_region_info *regions = mtd->eraseregions;
-
- if (instr->addr > mtd->size) {
- return -EINVAL;
- }
-
- if ((instr->len + instr->addr) > mtd->size) {
- return -EINVAL;
- }
-
- /* Check that both start and end of the requested erase are
- * aligned with the erasesize at the appropriate addresses.
- */
-
- i = 0;
-
- /* Skip all erase regions which are ended before the start of
- the requested erase. Actually, to save on the calculations,
- we skip to the first erase region which starts after the
- start of the requested erase, and then go back one.
- */
-
- while ((i < mtd->numeraseregions) &&
- (instr->addr >= regions[i].offset)) {
- i++;
- }
- i--;
-
- /* OK, now i is pointing at the erase region in which this
- * erase request starts. Check the start of the requested
- * erase range is aligned with the erase size which is in
- * effect here.
- */
-
- if (instr->addr & (regions[i].erasesize-1)) {
- return -EINVAL;
- }
-
- /* Remember the erase region we start on. */
-
- first = i;
-
- /* Next, check that the end of the requested erase is aligned
- * with the erase region at that address.
- */
-
- while ((i < mtd->numeraseregions) &&
- ((instr->addr + instr->len) >= regions[i].offset)) {
- i++;
- }
-
- /* As before, drop back one to point at the region in which
- * the address actually falls.
- */
-
- i--;
-
- if ((instr->addr + instr->len) & (regions[i].erasesize-1)) {
- return -EINVAL;
- }
-
- chipnum = instr->addr >> private->chipshift;
- adr = instr->addr - (chipnum << private->chipshift);
- len = instr->len;
-
- i = first;
-
- while (len) {
- ret = erase_one_block(map, &private->chips[chipnum], adr,
- regions[i].erasesize);
-
- if (ret) {
- return ret;
- }
-
- adr += regions[i].erasesize;
- len -= regions[i].erasesize;
-
- if ((adr % (1 << private->chipshift)) ==
- ((regions[i].offset + (regions[i].erasesize *
- regions[i].numblocks))
- % (1 << private->chipshift))) {
- i++;
- }
-
- if (adr >> private->chipshift) {
- adr = 0;
- chipnum++;
- if (chipnum >= private->numchips) {
- break;
- }
- }
- }
-
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
-
- return 0;
-}
-
-
-
-static void amd_flash_sync(struct mtd_info *mtd)
-{
- struct map_info *map = mtd->priv;
- struct amd_flash_private *private = map->fldrv_priv;
- int i;
- struct flchip *chip;
- int ret = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- for (i = 0; !ret && (i < private->numchips); i++) {
- chip = &private->chips[i];
-
- retry:
- spin_lock_bh(chip->mutex);
-
- switch(chip->state) {
- case FL_READY:
- case FL_STATUS:
- case FL_CFI_QUERY:
- case FL_JEDEC_QUERY:
- chip->oldstate = chip->state;
- chip->state = FL_SYNCING;
- /* No need to wake_up() on this state change -
- * as the whole point is that nobody can do anything
- * with the chip now anyway.
- */
- case FL_SYNCING:
- spin_unlock_bh(chip->mutex);
- break;
-
- default:
- /* Not an idle state */
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
-
- schedule();
-
- remove_wait_queue(&chip->wq, &wait);
-
- goto retry;
- }
- }
-
- /* Unlock the chips again */
- for (i--; i >= 0; i--) {
- chip = &private->chips[i];
-
- spin_lock_bh(chip->mutex);
-
- if (chip->state == FL_SYNCING) {
- chip->state = chip->oldstate;
- wake_up(&chip->wq);
- }
- spin_unlock_bh(chip->mutex);
- }
-}
-
-
-
-static int amd_flash_suspend(struct mtd_info *mtd)
-{
-printk("amd_flash_suspend(): not implemented!\n");
- return -EINVAL;
-}
-
-
-
-static void amd_flash_resume(struct mtd_info *mtd)
-{
-printk("amd_flash_resume(): not implemented!\n");
-}
-
-
-
-static void amd_flash_destroy(struct mtd_info *mtd)
-{
- struct map_info *map = mtd->priv;
- struct amd_flash_private *private = map->fldrv_priv;
- kfree(private);
-}
-
-int __init amd_flash_init(void)
-{
- register_mtd_chip_driver(&amd_flash_chipdrv);
- return 0;
-}
-
-void __exit amd_flash_exit(void)
-{
- unregister_mtd_chip_driver(&amd_flash_chipdrv);
-}
-
-module_init(amd_flash_init);
-module_exit(amd_flash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
-MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
deleted file mode 100644
index 14e57b2bf842..000000000000
--- a/drivers/mtd/chips/jedec.c
+++ /dev/null
@@ -1,935 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * This code does not support anything wider than 8 bit flash chips, I am
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
- * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mtd/jedec.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-
-static struct mtd_info *jedec_probe(struct map_info *);
-static int jedec_probe8(struct map_info *map,unsigned long base,
- struct jedec_private *priv);
-static int jedec_probe16(struct map_info *map,unsigned long base,
- struct jedec_private *priv);
-static int jedec_probe32(struct map_info *map,unsigned long base,
- struct jedec_private *priv);
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
- unsigned long len);
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
- size_t *retlen, const u_char *buf);
-
-static unsigned long my_bank_size;
-
-/* Listing of parts and sizes. We need this table to learn the sector
- size of the chip and the total length */
-static const struct JEDECTable JEDEC_table[] = {
- {
- .jedec = 0x013D,
- .name = "AMD Am29F017D",
- .size = 2*1024*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- {
- .jedec = 0x01AD,
- .name = "AMD Am29F016",
- .size = 2*1024*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- {
- .jedec = 0x01D5,
- .name = "AMD Am29F080",
- .size = 1*1024*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- {
- .jedec = 0x01A4,
- .name = "AMD Am29F040",
- .size = 512*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- {
- .jedec = 0x20E3,
- .name = "AMD Am29W040B",
- .size = 512*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- {
- .jedec = 0xC2AD,
- .name = "Macronix MX29F016",
- .size = 2*1024*1024,
- .sectorsize = 64*1024,
- .capabilities = MTD_CAP_NORFLASH
- },
- { .jedec = 0x0 }
-};
-
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
-static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-
-
-static struct mtd_chip_driver jedec_chipdrv = {
- .probe = jedec_probe,
- .name = "jedec",
- .module = THIS_MODULE
-};
-
-/* Probe entry point */
-
-static struct mtd_info *jedec_probe(struct map_info *map)
-{
- struct mtd_info *MTD;
- struct jedec_private *priv;
- unsigned long Base;
- unsigned long SectorSize;
- unsigned count;
- unsigned I,Uniq;
- char Part[200];
- memset(&priv,0,sizeof(priv));
-
- MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
- if (!MTD)
- return NULL;
-
- priv = (struct jedec_private *)&MTD[1];
-
- my_bank_size = map->size;
-
- if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
- {
- printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
- kfree(MTD);
- return NULL;
- }
-
- for (Base = 0; Base < map->size; Base += my_bank_size)
- {
- // Perhaps zero could designate all tests?
- if (map->buswidth == 0)
- map->buswidth = 1;
-
- if (map->buswidth == 1){
- if (jedec_probe8(map,Base,priv) == 0) {
- printk("did recognize jedec chip\n");
- kfree(MTD);
- return NULL;
- }
- }
- if (map->buswidth == 2)
- jedec_probe16(map,Base,priv);
- if (map->buswidth == 4)
- jedec_probe32(map,Base,priv);
- }
-
- // Get the biggest sector size
- SectorSize = 0;
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- // printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
- // printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
- if (priv->chips[I].sectorsize > SectorSize)
- SectorSize = priv->chips[I].sectorsize;
- }
-
- // Quickly ensure that the other sector sizes are factors of the largest
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
- {
- printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
- kfree(MTD);
- return NULL;
- }
- }
-
- /* Generate a part name that includes the number of different chips and
- other configuration information */
- count = 1;
- strlcpy(Part,map->name,sizeof(Part)-10);
- strcat(Part," ");
- Uniq = 0;
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- const struct JEDECTable *JEDEC;
-
- if (priv->chips[I+1].jedec == priv->chips[I].jedec)
- {
- count++;
- continue;
- }
-
- // Locate the chip in the jedec table
- JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
- if (JEDEC == 0)
- {
- printk("mtd: Internal Error, JEDEC not set\n");
- kfree(MTD);
- return NULL;
- }
-
- if (Uniq != 0)
- strcat(Part,",");
- Uniq++;
-
- if (count != 1)
- sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
- else
- sprintf(Part+strlen(Part),"%s",JEDEC->name);
- if (strlen(Part) > sizeof(Part)*2/3)
- break;
- count = 1;
- }
-
- /* Determine if the chips are organized in a linear fashion, or if there
- are empty banks. Note, the last bank does not count here, only the
- first banks are important. Holes on non-bank boundaries can not exist
- due to the way the detection algorithm works. */
- if (priv->size < my_bank_size)
- my_bank_size = priv->size;
- priv->is_banked = 0;
- //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
- //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
- if (!priv->size) {
- printk("priv->size is zero\n");
- kfree(MTD);
- return NULL;
- }
- if (priv->size/my_bank_size) {
- if (priv->size/my_bank_size == 1) {
- priv->size = my_bank_size;
- }
- else {
- for (I = 0; I != priv->size/my_bank_size - 1; I++)
- {
- if (priv->bank_fill[I] != my_bank_size)
- priv->is_banked = 1;
-
- /* This even could be eliminated, but new de-optimized read/write
- functions have to be written */
- printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
- if (priv->bank_fill[I] != priv->bank_fill[0])
- {
- printk("mtd: Failed. Cannot handle unsymmetric banking\n");
- kfree(MTD);
- return NULL;
- }
- }
- }
- }
- if (priv->is_banked == 1)
- strcat(Part,", banked");
-
- // printk("Part: '%s'\n",Part);
-
- memset(MTD,0,sizeof(*MTD));
- // strlcpy(MTD->name,Part,sizeof(MTD->name));
- MTD->name = map->name;
- MTD->type = MTD_NORFLASH;
- MTD->flags = MTD_CAP_NORFLASH;
- MTD->writesize = 1;
- MTD->erasesize = SectorSize*(map->buswidth);
- // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
- MTD->size = priv->size;
- // printk("MTD->size is %x\n",(unsigned int)MTD->size);
- //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
- MTD->erase = flash_erase;
- if (priv->is_banked == 1)
- MTD->read = jedec_read_banked;
- else
- MTD->read = jedec_read;
- MTD->write = flash_write;
- MTD->sync = jedec_sync;
- MTD->priv = map;
- map->fldrv_priv = priv;
- map->fldrv = &jedec_chipdrv;
- __module_get(THIS_MODULE);
- return MTD;
-}
-
-/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
-static int checkparity(u_char C)
-{
- u_char parity = 0;
- while (C != 0)
- {
- parity ^= C & 1;
- C >>= 1;
- }
-
- return parity == 1;
-}
-
-
-/* Take an array of JEDEC numbers that represent interleved flash chips
- and process them. Check to make sure they are good JEDEC numbers, look
- them up and then add them to the chip list */
-static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
- unsigned long base,struct jedec_private *priv)
-{
- unsigned I,J;
- unsigned long Size;
- unsigned long SectorSize;
- const struct JEDECTable *JEDEC;
-
- // Test #2 JEDEC numbers exhibit odd parity
- for (I = 0; I != Count; I++)
- {
- if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
- return 0;
- }
-
- // Finally, just make sure all the chip sizes are the same
- JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-
- if (JEDEC == 0)
- {
- printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
- return 0;
- }
-
- Size = JEDEC->size;
- SectorSize = JEDEC->sectorsize;
- for (I = 0; I != Count; I++)
- {
- JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
- if (JEDEC == 0)
- {
- printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
- return 0;
- }
-
- if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
- {
- printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
- return 0;
- }
- }
-
- // Load the Chips
- for (I = 0; I != MAX_JEDEC_CHIPS; I++)
- {
- if (priv->chips[I].jedec == 0)
- break;
- }
-
- if (I + Count > MAX_JEDEC_CHIPS)
- {
- printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
- return 0;
- }
-
- // Add them to the table
- for (J = 0; J != Count; J++)
- {
- unsigned long Bank;
-
- JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
- priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
- priv->chips[I].size = JEDEC->size;
- priv->chips[I].sectorsize = JEDEC->sectorsize;
- priv->chips[I].base = base + J;
- priv->chips[I].datashift = J*8;
- priv->chips[I].capabilities = JEDEC->capabilities;
- priv->chips[I].offset = priv->size + J;
-
- // log2 n :|
- priv->chips[I].addrshift = 0;
- for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-
- // Determine how filled this bank is.
- Bank = base & (~(my_bank_size-1));
- if (priv->bank_fill[Bank/my_bank_size] < base +
- (JEDEC->size << priv->chips[I].addrshift) - Bank)
- priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
- I++;
- }
-
- priv->size += priv->chips[I-1].size*Count;
-
- return priv->chips[I-1].size;
-}
-
-/* Lookup the chip information from the JEDEC ID table. */
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
-{
- __u16 Id = (mfr << 8) | id;
- unsigned long I = 0;
- for (I = 0; JEDEC_table[I].jedec != 0; I++)
- if (JEDEC_table[I].jedec == Id)
- return JEDEC_table + I;
- return NULL;
-}
-
-// Look for flash using an 8 bit bus interface
-static int jedec_probe8(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
-{
- #define flread(x) map_read8(map,base+x)
- #define flwrite(v,x) map_write8(map,v,base+x)
-
- const unsigned long AutoSel1 = 0xAA;
- const unsigned long AutoSel2 = 0x55;
- const unsigned long AutoSel3 = 0x90;
- const unsigned long Reset = 0xF0;
- __u32 OldVal;
- __u8 Mfg[1];
- __u8 Id[1];
- unsigned I;
- unsigned long Size;
-
- // Wait for any write/erase operation to settle
- OldVal = flread(base);
- for (I = 0; OldVal != flread(base) && I < 10000; I++)
- OldVal = flread(base);
-
- // Reset the chip
- flwrite(Reset,0x555);
-
- // Send the sequence
- flwrite(AutoSel1,0x555);
- flwrite(AutoSel2,0x2AA);
- flwrite(AutoSel3,0x555);
-
- // Get the JEDEC numbers
- Mfg[0] = flread(0);
- Id[0] = flread(1);
- // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
-
- Size = handle_jedecs(map,Mfg,Id,1,base,priv);
- // printk("handle_jedecs Size is %x\n",(unsigned int)Size);
- if (Size == 0)
- {
- flwrite(Reset,0x555);
- return 0;
- }
-
-
- // Reset.
- flwrite(Reset,0x555);
-
- return 1;
-
- #undef flread
- #undef flwrite
-}
-
-// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
-static int jedec_probe16(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
-{
- return 0;
-}
-
-// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
-static int jedec_probe32(struct map_info *map,unsigned long base,
- struct jedec_private *priv)
-{
- #define flread(x) map_read32(map,base+((x)<<2))
- #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
- const unsigned long AutoSel1 = 0xAAAAAAAA;
- const unsigned long AutoSel2 = 0x55555555;
- const unsigned long AutoSel3 = 0x90909090;
- const unsigned long Reset = 0xF0F0F0F0;
- __u32 OldVal;
- __u8 Mfg[4];
- __u8 Id[4];
- unsigned I;
- unsigned long Size;
-
- // Wait for any write/erase operation to settle
- OldVal = flread(base);
- for (I = 0; OldVal != flread(base) && I < 10000; I++)
- OldVal = flread(base);
-
- // Reset the chip
- flwrite(Reset,0x555);
-
- // Send the sequence
- flwrite(AutoSel1,0x555);
- flwrite(AutoSel2,0x2AA);
- flwrite(AutoSel3,0x555);
-
- // Test #1, JEDEC numbers are readable from 0x??00/0x??01
- if (flread(0) != flread(0x100) ||
- flread(1) != flread(0x101))
- {
- flwrite(Reset,0x555);
- return 0;
- }
-
- // Split up the JEDEC numbers
- OldVal = flread(0);
- for (I = 0; I != 4; I++)
- Mfg[I] = (OldVal >> (I*8));
- OldVal = flread(1);
- for (I = 0; I != 4; I++)
- Id[I] = (OldVal >> (I*8));
-
- Size = handle_jedecs(map,Mfg,Id,4,base,priv);
- if (Size == 0)
- {
- flwrite(Reset,0x555);
- return 0;
- }
-
- /* Check if there is address wrap around within a single bank, if this
- returns JEDEC numbers then we assume that it is wrap around. Notice
- we call this routine with the JEDEC return still enabled, if two or
- more flashes have a truncated address space the probe test will still
- work */
- if (base + (Size<<2)+0x555 < map->size &&
- base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
- {
- if (flread(base+Size) != flread(base+Size + 0x100) ||
- flread(base+Size + 1) != flread(base+Size + 0x101))
- {
- jedec_probe32(map,base+Size,priv);
- }
- }
-
- // Reset.
- flwrite(0xF0F0F0F0,0x555);
-
- return 1;
-
- #undef flread
- #undef flwrite
-}
-
-/* Linear read. */
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
-
- map_copy_from(map, buf, from, len);
- *retlen = len;
- return 0;
-}
-
-/* Banked read. Take special care to jump past the holes in the bank
- mapping. This version assumes symetry in the holes.. */
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct jedec_private *priv = map->fldrv_priv;
-
- *retlen = 0;
- while (len > 0)
- {
- // Determine what bank and offset into that bank the first byte is
- unsigned long bank = from & (~(priv->bank_fill[0]-1));
- unsigned long offset = from & (priv->bank_fill[0]-1);
- unsigned long get = len;
- if (priv->bank_fill[0] - offset < len)
- get = priv->bank_fill[0] - offset;
-
- bank /= priv->bank_fill[0];
- map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
- len -= get;
- *retlen += get;
- from += get;
- }
- return 0;
-}
-
-/* Pass the flags value that the flash return before it re-entered read
- mode. */
-static void jedec_flash_failed(unsigned char code)
-{
- /* Bit 5 being high indicates that there was an internal device
- failure, erasure time limits exceeded or something */
- if ((code & (1 << 5)) != 0)
- {
- printk("mtd: Internal Flash failure\n");
- return;
- }
- printk("mtd: Programming didn't take\n");
-}
-
-/* This uses the erasure function described in the AMD Flash Handbook,
- it will work for flashes with a fixed sector size only. Flashes with
- a selection of sector sizes (ie the AMD Am29F800B) will need a different
- routine. This routine tries to parallize erasing multiple chips/sectors
- where possible */
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- // Does IO to the currently selected chip
- #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
- #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
- unsigned long Time = 0;
- unsigned long NoTime = 0;
- unsigned long start = instr->addr, len = instr->len;
- unsigned int I;
- struct map_info *map = mtd->priv;
- struct jedec_private *priv = map->fldrv_priv;
-
- // Verify the arguments..
- if (start + len > mtd->size ||
- (start % mtd->erasesize) != 0 ||
- (len % mtd->erasesize) != 0 ||
- (len/mtd->erasesize) == 0)
- return -EINVAL;
-
- jedec_flash_chip_scan(priv,start,len);
-
- // Start the erase sequence on each chip
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- unsigned long off;
- struct jedec_flash_chip *chip = priv->chips + I;
-
- if (chip->length == 0)
- continue;
-
- if (chip->start + chip->length > chip->size)
- {
- printk("DIE\n");
- return -EIO;
- }
-
- flwrite(0xF0,chip->start + 0x555);
- flwrite(0xAA,chip->start + 0x555);
- flwrite(0x55,chip->start + 0x2AA);
- flwrite(0x80,chip->start + 0x555);
- flwrite(0xAA,chip->start + 0x555);
- flwrite(0x55,chip->start + 0x2AA);
-
- /* Once we start selecting the erase sectors the delay between each
- command must not exceed 50us or it will immediately start erasing
- and ignore the other sectors */
- for (off = 0; off < len; off += chip->sectorsize)
- {
- // Check to make sure we didn't timeout
- flwrite(0x30,chip->start + off);
- if (off == 0)
- continue;
- if ((flread(chip->start + off) & (1 << 3)) != 0)
- {
- printk("mtd: Ack! We timed out the erase timer!\n");
- return -EIO;
- }
- }
- }
-
- /* We could split this into a timer routine and return early, performing
- background erasure.. Maybe later if the need warrents */
-
- /* Poll the flash for erasure completion, specs say this can take as long
- as 480 seconds to do all the sectors (for a 2 meg flash).
- Erasure time is dependent on chip age, temp and wear.. */
-
- /* This being a generic routine assumes a 32 bit bus. It does read32s
- and bundles interleved chips into the same grouping. This will work
- for all bus widths */
- Time = 0;
- NoTime = 0;
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- struct jedec_flash_chip *chip = priv->chips + I;
- unsigned long off = 0;
- unsigned todo[4] = {0,0,0,0};
- unsigned todo_left = 0;
- unsigned J;
-
- if (chip->length == 0)
- continue;
-
- /* Find all chips in this data line, realistically this is all
- or nothing up to the interleve count */
- for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
- {
- if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
- (chip->base & (~((1<<chip->addrshift)-1))))
- {
- todo_left++;
- todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
- }
- }
-
- /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
- (short)todo[2],(short)todo[3]);
- */
- while (1)
- {
- __u32 Last[4];
- unsigned long Count = 0;
-
- /* During erase bit 7 is held low and bit 6 toggles, we watch this,
- should it stop toggling or go high then the erase is completed,
- or this is not really flash ;> */
- switch (map->buswidth) {
- case 1:
- Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
- Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 3:
- Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count = 3;
- while (todo_left != 0)
- {
- for (J = 0; J != 4; J++)
- {
- __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
- __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
- __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
- if (todo[J] == 0)
- continue;
-
- if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
- {
-// printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
- continue;
- }
-
- if (Byte1 == Byte2)
- {
- jedec_flash_failed(Byte3);
- return -EIO;
- }
-
- todo[J] = 0;
- todo_left--;
- }
-
-/* if (NoTime == 0)
- Time += HZ/10 - schedule_timeout(HZ/10);*/
- NoTime = 0;
-
- switch (map->buswidth) {
- case 1:
- Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 2:
- Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- case 4:
- Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
- break;
- }
- Count++;
-
-/* // Count time, max of 15s per sector (according to AMD)
- if (Time > 15*len/mtd->erasesize*HZ)
- {
- printk("mtd: Flash Erase Timed out\n");
- return -EIO;
- } */
- }
-
- // Skip to the next chip if we used chip erase
- if (chip->length == chip->size)
- off = chip->size;
- else
- off += chip->sectorsize;
-
- if (off >= chip->length)
- break;
- NoTime = 1;
- }
-
- for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
- {
- if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
- (chip->base & (~((1<<chip->addrshift)-1))))
- priv->chips[J].length = 0;
- }
- }
-
- //printk("done\n");
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
- return 0;
-
- #undef flread
- #undef flwrite
-}
-
-/* This is the simple flash writing function. It writes to every byte, in
- sequence. It takes care of how to properly address the flash if
- the flash is interleved. It can only be used if all the chips in the
- array are identical!*/
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
- size_t *retlen, const u_char *buf)
-{
- /* Does IO to the currently selected chip. It takes the bank addressing
- base (which is divisible by the chip size) adds the necessary lower bits
- of addrshift (interleave index) and then adds the control register index. */
- #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
- #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
- struct map_info *map = mtd->priv;
- struct jedec_private *priv = map->fldrv_priv;
- unsigned long base;
- unsigned long off;
- size_t save_len = len;
-
- if (start + len > mtd->size)
- return -EIO;
-
- //printk("Here");
-
- //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
- while (len != 0)
- {
- struct jedec_flash_chip *chip = priv->chips;
- unsigned long bank;
- unsigned long boffset;
-
- // Compute the base of the flash.
- off = ((unsigned long)start) % (chip->size << chip->addrshift);
- base = start - off;
-
- // Perform banked addressing translation.
- bank = base & (~(priv->bank_fill[0]-1));
- boffset = base & (priv->bank_fill[0]-1);
- bank = (bank/priv->bank_fill[0])*my_bank_size;
- base = bank + boffset;
-
- // printk("Flasing %X %X %X\n",base,chip->size,len);
- // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
-
- // Loop over this page
- for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
- {
- unsigned char oldbyte = map_read8(map,base+off);
- unsigned char Last[4];
- unsigned long Count = 0;
-
- if (oldbyte == *buf) {
- // printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
- continue;
- }
- if (((~oldbyte) & *buf) != 0)
- printk("mtd: warn: Trying to set a 0 to a 1\n");
-
- // Write
- flwrite(0xAA,0x555);
- flwrite(0x55,0x2AA);
- flwrite(0xA0,0x555);
- map_write8(map,*buf,base + off);
- Last[0] = map_read8(map,base + off);
- Last[1] = map_read8(map,base + off);
- Last[2] = map_read8(map,base + off);
-
- /* Wait for the flash to finish the operation. We store the last 4
- status bytes that have been retrieved so we can determine why
- it failed. The toggle bits keep toggling when there is a
- failure */
- for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
- Count < 10000; Count++)
- Last[Count % 4] = map_read8(map,base + off);
- if (Last[(Count - 1) % 4] != *buf)
- {
- jedec_flash_failed(Last[(Count - 3) % 4]);
- return -EIO;
- }
- }
- }
- *retlen = save_len;
- return 0;
-}
-
-/* This is used to enhance the speed of the erase routine,
- when things are being done to multiple chips it is possible to
- parallize the operations, particularly full memory erases of multi
- chip memories benifit */
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
- unsigned long len)
-{
- unsigned int I;
-
- // Zero the records
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- priv->chips[I].start = priv->chips[I].length = 0;
-
- // Intersect the region with each chip
- for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
- {
- struct jedec_flash_chip *chip = priv->chips + I;
- unsigned long ByteStart;
- unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-
- // End is before this chip or the start is after it
- if (start+len < chip->offset ||
- ChipEndByte - (1 << chip->addrshift) < start)
- continue;
-
- if (start < chip->offset)
- {
- ByteStart = chip->offset;
- chip->start = 0;
- }
- else
- {
- chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
- ByteStart = start;
- }
-
- if (start + len >= ChipEndByte)
- chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
- else
- chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
- }
-}
-
-int __init jedec_init(void)
-{
- register_mtd_chip_driver(&jedec_chipdrv);
- return 0;
-}
-
-static void __exit jedec_exit(void)
-{
- unregister_mtd_chip_driver(&jedec_chipdrv);
-}
-
-module_init(jedec_init);
-module_exit(jedec_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
-MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
deleted file mode 100644
index c9cd3d21ccfa..000000000000
--- a/drivers/mtd/chips/sharp.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * MTD chip driver for pre-CFI Sharp flash chips
- *
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- * 2000,2001 Lineo, Inc.
- *
- * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
- *
- * Devices supported:
- * LH28F016SCT Symmetrical block flash memory, 2Mx8
- * LH28F008SCT Symmetrical block flash memory, 1Mx8
- *
- * Documentation:
- * http://www.sharpmeg.com/datasheets/memic/flashcmp/
- * http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
- * 016sctl9.pdf
- *
- * Limitations:
- * This driver only supports 4x1 arrangement of chips.
- * Not tested on anything but PowerPC.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/cfi.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#define CMD_RESET 0xffffffff
-#define CMD_READ_ID 0x90909090
-#define CMD_READ_STATUS 0x70707070
-#define CMD_CLEAR_STATUS 0x50505050
-#define CMD_BLOCK_ERASE_1 0x20202020
-#define CMD_BLOCK_ERASE_2 0xd0d0d0d0
-#define CMD_BYTE_WRITE 0x40404040
-#define CMD_SUSPEND 0xb0b0b0b0
-#define CMD_RESUME 0xd0d0d0d0
-#define CMD_SET_BLOCK_LOCK_1 0x60606060
-#define CMD_SET_BLOCK_LOCK_2 0x01010101
-#define CMD_SET_MASTER_LOCK_1 0x60606060
-#define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1
-#define CMD_CLEAR_BLOCK_LOCKS_1 0x60606060
-#define CMD_CLEAR_BLOCK_LOCKS_2 0xd0d0d0d0
-
-#define SR_READY 0x80808080 // 1 = ready
-#define SR_ERASE_SUSPEND 0x40404040 // 1 = block erase suspended
-#define SR_ERROR_ERASE 0x20202020 // 1 = error in block erase or clear lock bits
-#define SR_ERROR_WRITE 0x10101010 // 1 = error in byte write or set lock bit
-#define SR_VPP 0x08080808 // 1 = Vpp is low
-#define SR_WRITE_SUSPEND 0x04040404 // 1 = byte write suspended
-#define SR_PROTECT 0x02020202 // 1 = lock bit set
-#define SR_RESERVED 0x01010101
-
-#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
-
-/* Configuration options */
-
-#undef AUTOUNLOCK /* automatically unlocks blocks before erasing */
-
-static struct mtd_info *sharp_probe(struct map_info *);
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf);
-static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, const u_char *buf);
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
-static void sharp_sync(struct mtd_info *mtd);
-static int sharp_suspend(struct mtd_info *mtd);
-static void sharp_resume(struct mtd_info *mtd);
-static void sharp_destroy(struct mtd_info *mtd);
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
- unsigned long adr, __u32 datum);
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
- unsigned long adr);
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
- unsigned long adr);
-#endif
-
-
-struct sharp_info{
- struct flchip *chip;
- int bogus;
- int chipshift;
- int numchips;
- struct flchip chips[1];
-};
-
-static void sharp_destroy(struct mtd_info *mtd);
-
-static struct mtd_chip_driver sharp_chipdrv = {
- .probe = sharp_probe,
- .destroy = sharp_destroy,
- .name = "sharp",
- .module = THIS_MODULE
-};
-
-
-static struct mtd_info *sharp_probe(struct map_info *map)
-{
- struct mtd_info *mtd = NULL;
- struct sharp_info *sharp = NULL;
- int width;
-
- mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
- if(!mtd)
- return NULL;
-
- sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
- if(!sharp) {
- kfree(mtd);
- return NULL;
- }
-
- width = sharp_probe_map(map,mtd);
- if(!width){
- kfree(mtd);
- kfree(sharp);
- return NULL;
- }
-
- mtd->priv = map;
- mtd->type = MTD_NORFLASH;
- mtd->erase = sharp_erase;
- mtd->read = sharp_read;
- mtd->write = sharp_write;
- mtd->sync = sharp_sync;
- mtd->suspend = sharp_suspend;
- mtd->resume = sharp_resume;
- mtd->flags = MTD_CAP_NORFLASH;
- mtd->writesize = 1;
- mtd->name = map->name;
-
- sharp->chipshift = 23;
- sharp->numchips = 1;
- sharp->chips[0].start = 0;
- sharp->chips[0].state = FL_READY;
- sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
- sharp->chips[0].word_write_time = 0;
- init_waitqueue_head(&sharp->chips[0].wq);
- spin_lock_init(&sharp->chips[0]._spinlock);
-
- map->fldrv = &sharp_chipdrv;
- map->fldrv_priv = sharp;
-
- __module_get(THIS_MODULE);
- return mtd;
-}
-
-static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
-{
- map_word map_cmd;
- map_cmd.x[0] = cmd;
- map_write(map, map_cmd, adr);
-}
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
-{
- map_word tmp, read0, read4;
- unsigned long base = 0;
- int width = 4;
-
- tmp = map_read(map, base+0);
-
- sharp_send_cmd(map, CMD_READ_ID, base+0);
-
- read0 = map_read(map, base+0);
- read4 = map_read(map, base+4);
- if(read0.x[0] == 0x89898989){
- printk("Looks like sharp flash\n");
- switch(read4.x[0]){
- case 0xaaaaaaaa:
- case 0xa0a0a0a0:
- /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
- /* a0 - LH28F016SCT-Z4 2Mx8, 32 64k blocks*/
- mtd->erasesize = 0x10000 * width;
- mtd->size = 0x200000 * width;
- return width;
- case 0xa6a6a6a6:
- /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
- /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
- mtd->erasesize = 0x10000 * width;
- mtd->size = 0x100000 * width;
- return width;
-#if 0
- case 0x00000000: /* unknown */
- /* XX - LH28F004SCT 512kx8, 8 64k blocks*/
- mtd->erasesize = 0x10000 * width;
- mtd->size = 0x80000 * width;
- return width;
-#endif
- default:
- printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
- read0.x[0], read4.x[0]);
- }
- }else if((map_read(map, base+0).x[0] == CMD_READ_ID)){
- /* RAM, probably */
- printk("Looks like RAM\n");
- map_write(map, tmp, base+0);
- }else{
- printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
- read0.x[0], read4.x[0]);
- }
-
- return 0;
-}
-
-/* This function returns with the chip->mutex lock held. */
-static int sharp_wait(struct map_info *map, struct flchip *chip)
-{
- int i;
- map_word status;
- unsigned long timeo = jiffies + HZ;
- DECLARE_WAITQUEUE(wait, current);
- int adr = 0;
-
-retry:
- spin_lock_bh(chip->mutex);
-
- switch(chip->state){
- case FL_READY:
- sharp_send_cmd(map, CMD_READ_STATUS, adr);
- chip->state = FL_STATUS;
- case FL_STATUS:
- for(i=0;i<100;i++){
- status = map_read(map, adr);
- if((status.x[0] & SR_READY)==SR_READY)
- break;
- udelay(1);
- }
- break;
- default:
- printk("Waiting for chip\n");
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- spin_unlock_bh(chip->mutex);
-
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-
- if(signal_pending(current))
- return -EINTR;
-
- timeo = jiffies + HZ;
-
- goto retry;
- }
-
- sharp_send_cmd(map, CMD_RESET, adr);
-
- chip->state = FL_READY;
-
- return 0;
-}
-
-static void sharp_release(struct flchip *chip)
-{
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-}
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct sharp_info *sharp = map->fldrv_priv;
- int chipnum;
- int ret = 0;
- int ofs = 0;
-
- chipnum = (from >> sharp->chipshift);
- ofs = from & ((1 << sharp->chipshift)-1);
-
- *retlen = 0;
-
- while(len){
- unsigned long thislen;
-
- if(chipnum>=sharp->numchips)
- break;
-
- thislen = len;
- if(ofs+thislen >= (1<<sharp->chipshift))
- thislen = (1<<sharp->chipshift) - ofs;
-
- ret = sharp_wait(map,&sharp->chips[chipnum]);
- if(ret<0)
- break;
-
- map_copy_from(map,buf,ofs,thislen);
-
- sharp_release(&sharp->chips[chipnum]);
-
- *retlen += thislen;
- len -= thislen;
- buf += thislen;
-
- ofs = 0;
- chipnum++;
- }
- return ret;
-}
-
-static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct sharp_info *sharp = map->fldrv_priv;
- int ret = 0;
- int i,j;
- int chipnum;
- unsigned long ofs;
- union { u32 l; unsigned char uc[4]; } tbuf;
-
- *retlen = 0;
-
- while(len){
- tbuf.l = 0xffffffff;
- chipnum = to >> sharp->chipshift;
- ofs = to & ((1<<sharp->chipshift)-1);
-
- j=0;
- for(i=ofs&3;i<4 && len;i++){
- tbuf.uc[i] = *buf;
- buf++;
- to++;
- len--;
- j++;
- }
- sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
- if(ret<0)
- return ret;
- (*retlen)+=j;
- }
-
- return 0;
-}
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
- unsigned long adr, __u32 datum)
-{
- int ret;
- int timeo;
- int try;
- int i;
- map_word data, status;
-
- status.x[0] = 0;
- ret = sharp_wait(map,chip);
-
- for(try=0;try<10;try++){
- sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
- /* cpu_to_le32 -> hack to fix the writel be->le conversion */
- data.x[0] = cpu_to_le32(datum);
- map_write(map, data, adr);
-
- chip->state = FL_WRITING;
-
- timeo = jiffies + (HZ/2);
-
- sharp_send_cmd(map, CMD_READ_STATUS, adr);
- for(i=0;i<100;i++){
- status = map_read(map, adr);
- if((status.x[0] & SR_READY) == SR_READY)
- break;
- }
- if(i==100){
- printk("sharp: timed out writing\n");
- }
-
- if(!(status.x[0] & SR_ERRORS))
- break;
-
- printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
-
- sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
- }
- sharp_send_cmd(map, CMD_RESET, adr);
- chip->state = FL_READY;
-
- wake_up(&chip->wq);
- spin_unlock_bh(chip->mutex);
-
- return 0;
-}
-
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- struct map_info *map = mtd->priv;
- struct sharp_info *sharp = map->fldrv_priv;
- unsigned long adr,len;
- int chipnum, ret=0;
-
-//printk("sharp_erase()\n");
- if(instr->addr & (mtd->erasesize - 1))
- return -EINVAL;
- if(instr->len & (mtd->erasesize - 1))
- return -EINVAL;
- if(instr->len + instr->addr > mtd->size)
- return -EINVAL;
-
- chipnum = instr->addr >> sharp->chipshift;
- adr = instr->addr & ((1<<sharp->chipshift)-1);
- len = instr->len;
-
- while(len){
- ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
- if(ret)return ret;
-
- adr += mtd->erasesize;
- len -= mtd->erasesize;
- if(adr >> sharp->chipshift){
- adr = 0;
- chipnum++;
- if(chipnum>=sharp->numchips)
- break;
- }
- }
-
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
-
- return 0;
-}
-
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
- unsigned long adr)
-{
- int ret;
- unsigned long timeo;
- map_word status;
- DECLARE_WAITQUEUE(wait, current);
-
- sharp_send_cmd(map, CMD_READ_STATUS, adr);
- status = map_read(map, adr);
-
- timeo = jiffies + HZ;
-
- while(time_before(jiffies, timeo)){
- sharp_send_cmd(map, CMD_READ_STATUS, adr);
- status = map_read(map, adr);
- if((status.x[0] & SR_READY)==SR_READY){
- ret = 0;
- goto out;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
-
- //spin_unlock_bh(chip->mutex);
-
- schedule_timeout(1);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
-
- //spin_lock_bh(chip->mutex);
-
- if (signal_pending(current)){
- ret = -EINTR;
- goto out;
- }
-
- }
- ret = -ETIME;
-out:
- return ret;
-}
-
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
- unsigned long adr)
-{
- int ret;
- //int timeo;
- map_word status;
- //int i;
-
-//printk("sharp_erase_oneblock()\n");
-
-#ifdef AUTOUNLOCK
- /* This seems like a good place to do an unlock */
- sharp_unlock_oneblock(map,chip,adr);
-#endif
-
- sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
- sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
-
- chip->state = FL_ERASING;
-
- ret = sharp_do_wait_for_ready(map,chip,adr);
- if(ret<0)return ret;
-
- sharp_send_cmd(map, CMD_READ_STATUS, adr);
- status = map_read(map, adr);
-
- if(!(status.x[0] & SR_ERRORS)){
- sharp_send_cmd(map, CMD_RESET, adr);
- chip->state = FL_READY;
- //spin_unlock_bh(chip->mutex);
- return 0;
- }
-
- printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
- sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-
- //spin_unlock_bh(chip->mutex);
-
- return -EIO;
-}
-
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
- unsigned long adr)
-{
- int i;
- map_word status;
-
- sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr);
- sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr);
-
- udelay(100);
-
- status = map_read(map, adr);
- printk("status=%08lx\n", status.x[0]);
-
- for(i=0;i<1000;i++){
- //sharp_send_cmd(map, CMD_READ_STATUS, adr);
- status = map_read(map, adr);
- if((status.x[0] & SR_READY) == SR_READY)
- break;
- udelay(100);
- }
- if(i==1000){
- printk("sharp: timed out unlocking block\n");
- }
-
- if(!(status.x[0] & SR_ERRORS)){
- sharp_send_cmd(map, CMD_RESET, adr);
- chip->state = FL_READY;
- return;
- }
-
- printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
- sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-}
-#endif
-
-static void sharp_sync(struct mtd_info *mtd)
-{
- //printk("sharp_sync()\n");
-}
-
-static int sharp_suspend(struct mtd_info *mtd)
-{
- printk("sharp_suspend()\n");
- return -EINVAL;
-}
-
-static void sharp_resume(struct mtd_info *mtd)
-{
- printk("sharp_resume()\n");
-
-}
-
-static void sharp_destroy(struct mtd_info *mtd)
-{
- printk("sharp_destroy()\n");
-
-}
-
-static int __init sharp_probe_init(void)
-{
- printk("MTD Sharp chip driver <ds@lineo.com>\n");
-
- register_mtd_chip_driver(&sharp_chipdrv);
-
- return 0;
-}
-
-static void __exit sharp_probe_exit(void)
-{
- unregister_mtd_chip_driver(&sharp_chipdrv);
-}
-
-module_init(sharp_probe_init);
-module_exit(sharp_probe_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Schleef <ds@schleef.org>");
-MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index fc4cc8ba9e29..be4b9948c762 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -373,7 +373,7 @@ static inline void kill_final_newline(char *str)
#ifndef MODULE
static int block2mtd_init_called = 0;
-static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
+static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
#endif
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index d990d8141ef5..b665e4ac2208 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -60,7 +60,7 @@ config MTD_PHYSMAP_BANKWIDTH
(i.e., run-time calling physmap_configure()).
config MTD_PHYSMAP_OF
- tristate "Flash device in physical memory map based on OF descirption"
+ tristate "Flash device in physical memory map based on OF description"
depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
help
This provides a 'mapping' driver which allows the NOR Flash and
@@ -358,22 +358,6 @@ config MTD_CFI_FLAGADM
Mapping for the Flaga digital module. If you don't have one, ignore
this setting.
-config MTD_BEECH
- tristate "CFI Flash device mapped on IBM 405LP Beech"
- depends on MTD_CFI && BEECH
- help
- This enables access routines for the flash chips on the IBM
- 405LP Beech board. If you have one of these boards and would like
- to use the flash chips on it, say 'Y'.
-
-config MTD_ARCTIC
- tristate "CFI Flash device mapped on IBM 405LP Arctic"
- depends on MTD_CFI && ARCTIC2
- help
- This enables access routines for the flash chips on the IBM 405LP
- Arctic board. If you have one of these boards and would like to
- use the flash chips on it, say 'Y'.
-
config MTD_WALNUT
tristate "Flash device mapped on IBM 405GP Walnut"
depends on MTD_JEDECPROBE && WALNUT
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index de036c5e6139..3acbb5d01ca4 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -58,8 +58,6 @@ obj-$(CONFIG_MTD_NETtel) += nettel.o
obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
obj-$(CONFIG_MTD_EBONY) += ebony.o
obj-$(CONFIG_MTD_OCOTEA) += ocotea.o
-obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
-obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
obj-$(CONFIG_MTD_WALNUT) += walnut.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
deleted file mode 100644
index 2cc902436275..000000000000
--- a/drivers/mtd/maps/arctic-mtd.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
- * IBM 405LP Arctic boards.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- * modified for Arctic by,
- * David Gibson
- * IBM OzLabs, Canberra, Australia
- * <arctic@gibson.dropbear.id.au>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-/*
- * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
- * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
- * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
- * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
- */
-
-#define FFS1_SIZE 0x01000000 /* 16MiB */
-#define KERNEL_SIZE 0x00500000 /* 5.12MiB */
-#define FFS2_SIZE 0x00a60000 /* 10.624MiB */
-#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */
-
-
-#define NAME "Arctic Linux Flash"
-#define PADDR SUBZERO_BOOTFLASH_PADDR
-#define BUSWIDTH 2
-#define SIZE SUBZERO_BOOTFLASH_SIZE
-#define PARTITIONS 4
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-{
- /* do nothing for now */
-}
-
-static struct map_info arctic_mtd_map = {
- .name = NAME,
- .size = SIZE,
- .bankwidth = BUSWIDTH,
- .phys = PADDR,
-};
-
-static struct mtd_info *arctic_mtd;
-
-static struct mtd_partition arctic_partitions[PARTITIONS] = {
- { .name = "Filesystem",
- .size = FFS1_SIZE,
- .offset = 0,},
- { .name = "Kernel",
- .size = KERNEL_SIZE,
- .offset = FFS1_SIZE,},
- { .name = "Filesystem",
- .size = FFS2_SIZE,
- .offset = FFS1_SIZE + KERNEL_SIZE,},
- { .name = "Firmware",
- .size = FIRMWARE_SIZE,
- .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-};
-
-static int __init
-init_arctic_mtd(void)
-{
- int err;
-
- printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
- arctic_mtd_map.virt = ioremap(PADDR, SIZE);
-
- if (!arctic_mtd_map.virt) {
- printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
- return -EIO;
- }
- simple_map_init(&arctic_mtd_map);
-
- printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
- arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-
- if (!arctic_mtd) {
- iounmap(arctic_mtd_map.virt);
- return -ENXIO;
- }
-
- arctic_mtd->owner = THIS_MODULE;
-
- err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
- if (err) {
- printk("%s: add_mtd_partitions failed\n", NAME);
- iounmap(arctic_mtd_map.virt);
- }
-
- return err;
-}
-
-static void __exit
-cleanup_arctic_mtd(void)
-{
- if (arctic_mtd) {
- del_mtd_partitions(arctic_mtd);
- map_destroy(arctic_mtd);
- iounmap((void *) arctic_mtd_map.virt);
- }
-}
-
-module_init(init_arctic_mtd);
-module_exit(cleanup_arctic_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
deleted file mode 100644
index d76d5981b863..000000000000
--- a/drivers/mtd/maps/beech-mtd.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
- * IBM 405LP Beech boards.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-#define NAME "Beech Linux Flash"
-#define PADDR BEECH_BIGFLASH_PADDR
-#define SIZE BEECH_BIGFLASH_SIZE
-#define BUSWIDTH 1
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-
-static struct map_info beech_mtd_map = {
- .name = NAME,
- .size = SIZE,
- .bankwidth = BUSWIDTH,
- .phys = PADDR
-};
-
-static struct mtd_info *beech_mtd;
-
-static struct mtd_partition beech_partitions[2] = {
- {
- .name = "Linux Kernel",
- .size = BEECH_KERNEL_SIZE,
- .offset = BEECH_KERNEL_OFFSET
- }, {
- .name = "Free Area",
- .size = BEECH_FREE_AREA_SIZE,
- .offset = BEECH_FREE_AREA_OFFSET
- }
-};
-
-static int __init
-init_beech_mtd(void)
-{
- int err;
-
- printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
- beech_mtd_map.virt = ioremap(PADDR, SIZE);
-
- if (!beech_mtd_map.virt) {
- printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
- return -EIO;
- }
-
- simple_map_init(&beech_mtd_map);
-
- printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
- beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-
- if (!beech_mtd) {
- iounmap(beech_mtd_map.virt);
- return -ENXIO;
- }
-
- beech_mtd->owner = THIS_MODULE;
-
- err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
- if (err) {
- printk("%s: add_mtd_partitions failed\n", NAME);
- iounmap(beech_mtd_map.virt);
- }
-
- return err;
-}
-
-static void __exit
-cleanup_beech_mtd(void)
-{
- if (beech_mtd) {
- del_mtd_partitions(beech_mtd);
- map_destroy(beech_mtd);
- iounmap((void *) beech_mtd_map.virt);
- }
-}
-
-module_init(init_beech_mtd);
-module_exit(cleanup_beech_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 9f53c655af3a..7b96cd02f82b 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -358,7 +358,7 @@ int __init nettel_init(void)
/* Turn other PAR off so the first probe doesn't find it */
*intel1par = 0;
- /* Probe for the the size of the first Intel flash */
+ /* Probe for the size of the first Intel flash */
nettel_intel_map.size = maxsize;
nettel_intel_map.phys = intel0addr;
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 72107dc06d67..bbb42c35b69b 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -186,7 +186,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
else {
if (strcmp(of_probe, "ROM"))
dev_dbg(&dev->dev, "map_probe: don't know probe type "
- "'%s', mapping as rom\n");
+ "'%s', mapping as rom\n", of_probe);
info->mtd = do_map_probe("mtd_rom", &info->map);
}
if (info->mtd == NULL) {
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 1af989023c66..9c6236852942 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -347,7 +347,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
- slave->mtd.bank_size = master->bank_size;
slave->mtd.owner = master->owner;
slave->mtd.read = part_read;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index d05873b8c155..f1d60b6f048e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -232,11 +232,13 @@ config MTD_NAND_BASLER_EXCITE
will be named "excite_nandflash.ko".
config MTD_NAND_CAFE
- tristate "NAND support for OLPC CAFÉ chip"
- depends on PCI
- help
- Use NAND flash attached to the CAFÉ chip designed for the $100
- laptop.
+ tristate "NAND support for OLPC CAFÉ chip"
+ depends on PCI
+ select REED_SOLOMON
+ select REED_SOLOMON_DEC16
+ help
+ Use NAND flash attached to the CAFÉ chip designed for the $100
+ laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
@@ -270,4 +272,13 @@ config MTD_NAND_NANDSIM
The simulator may simulate various NAND flash chips for the
MTD nand layer.
+config MTD_NAND_PLATFORM
+ tristate "Support for generic platform NAND driver"
+ depends on MTD_NAND
+ help
+ This implements a generic NAND driver for on-SOC platform
+ devices. You will need to provide platform-specific functions
+ via platform_data.
+
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 6872031a3fb2..edba1db14bfa 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -26,6 +26,6 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
+obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
nand-objs := nand_base.o nand_bbt.o
-cafe_nand-objs := cafe.o cafe_ecc.o
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 14b80cc90a7b..512e999177f7 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -82,6 +82,10 @@ static void at91_nand_disable(struct at91_nand_host *host)
at91_set_gpio_value(host->board->enable_pin, 1);
}
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
/*
* Probe for the NAND device.
*/
@@ -151,6 +155,12 @@ static int __init at91_nand_probe(struct platform_device *pdev)
#ifdef CONFIG_MTD_PARTITIONS
if (host->board->partition_info)
partitions = host->board->partition_info(mtd->size, &num_partitions);
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ else {
+ mtd->name = "at91_nand";
+ num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+ }
+#endif
if ((!partitions) || (num_partitions == 0)) {
printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
deleted file mode 100644
index ea5c8491d2c5..000000000000
--- a/drivers/mtd/nand/cafe_ecc.c
+++ /dev/null
@@ -1,1381 +0,0 @@
-/* Error correction for CAFÉ NAND controller
- *
- * © 2006 Marvell, Inc.
- * Author: Tom Chiou
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-
-static unsigned short gf4096_mul(unsigned short, unsigned short);
-static unsigned short gf64_mul(unsigned short, unsigned short);
-static unsigned short gf4096_inv(unsigned short);
-static unsigned short err_pos(unsigned short);
-static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short *);
-static void zero_4x5_col3(unsigned short[4][5]);
-static void zero_4x5_col2(unsigned short[4][5]);
-static void zero_4x5_col1(unsigned short[4][5]);
-static void swap_4x5_rows(unsigned short[4][5], int, int, int);
-static void swap_2x3_rows(unsigned short m[2][3]);
-static void solve_4x5(unsigned short m[4][5], unsigned short *, int *);
-static void sort_coefs(int *, unsigned short *, int);
-static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short *);
-static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short,
- unsigned short *);
-static void zero_3x4_col2(unsigned short[3][4]);
-static void zero_3x4_col1(unsigned short[3][4]);
-static void swap_3x4_rows(unsigned short[3][4], int, int, int);
-static void solve_3x4(unsigned short[3][4], unsigned short *, int *);
-static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short,
- unsigned short *);
-
-static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short *);
-static void find_2x2_soln(unsigned short, unsigned short, unsigned short,
- unsigned short, unsigned short, unsigned short,
- unsigned short *);
-static void solve_2x3(unsigned short[2][3], unsigned short *);
-static int chk_no_err_only(unsigned short *, unsigned short *);
-static int chk_1_err_only(unsigned short *, unsigned short *);
-static int chk_2_err_only(unsigned short *, unsigned short *);
-static int chk_3_err_only(unsigned short *, unsigned short *);
-static int chk_4_err_only(unsigned short *, unsigned short *);
-
-static unsigned short gf64_mul(unsigned short a, unsigned short b)
-{
- unsigned short tmp1, tmp2, tmp3, tmp4, tmp5;
- unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c;
-
- tmp1 = ((a) ^ (a >> 5));
- tmp2 = ((a >> 4) ^ (a >> 5));
- tmp3 = ((a >> 3) ^ (a >> 4));
- tmp4 = ((a >> 2) ^ (a >> 3));
- tmp5 = ((a >> 1) ^ (a >> 2));
-
- c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^
- ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1;
-
- c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^
- (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1;
-
- c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^
- (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1;
-
- c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^
- (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1;
-
- c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^
- ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1;
-
- c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^
- ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1;
-
- c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5);
-
- return c;
-}
-
-static unsigned short gf4096_mul(unsigned short a, unsigned short b)
-{
- unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c;
-
- ah = (a >> 6) & 0x3f;
- al = a & 0x3f;
- bh = (b >> 6) & 0x3f;
- bl = b & 0x3f;
- alxah = al ^ ah;
- blxbh = bl ^ bh;
-
- ablh = gf64_mul(alxah, blxbh);
- albl = gf64_mul(al, bl);
- ahbh = gf64_mul(ah, bh);
-
- ahbhB = ((ahbh & 0x1) << 5) |
- ((ahbh & 0x20) >> 1) |
- ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1);
-
- c = ((ablh ^ albl) << 6) | (ahbhB ^ albl);
- return c;
-}
-
-static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats)
-{
- find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats);
-}
-
-static void find_3bit_err_coefs(unsigned short s0, unsigned short s1,
- unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs)
-{
- unsigned short m[3][4];
- int row_order[3];
-
- row_order[0] = 0;
- row_order[1] = 1;
- row_order[2] = 2;
- m[0][0] = s2;
- m[0][1] = s1;
- m[0][2] = s0;
- m[0][3] = s3;
- m[1][0] = s3;
- m[1][1] = s2;
- m[1][2] = s1;
- m[1][3] = s4;
- m[2][0] = s4;
- m[2][1] = s3;
- m[2][2] = s2;
- m[2][3] = s5;
-
- if (m[0][2] != 0x0) {
- zero_3x4_col2(m);
- } else if (m[1][2] != 0x0) {
- swap_3x4_rows(m, 0, 1, 4);
- zero_3x4_col2(m);
- } else if (m[2][2] != 0x0) {
- swap_3x4_rows(m, 0, 2, 4);
- zero_3x4_col2(m);
- } else {
- printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n");
- }
-
- if (m[1][1] != 0x0) {
- zero_3x4_col1(m);
- } else if (m[2][1] != 0x0) {
- swap_3x4_rows(m, 1, 2, 4);
- zero_3x4_col1(m);
- } else {
- printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n");
- }
-
- /* solve coefs */
- solve_3x4(m, coefs, row_order);
-}
-
-static void zero_3x4_col2(unsigned short m[3][4])
-{
- unsigned short minv1, minv2;
-
- minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2]));
- minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2]));
- m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
- m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
- m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1);
- m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
- m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
- m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2);
-}
-
-static void zero_3x4_col1(unsigned short m[3][4])
-{
- unsigned short minv;
- minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1]));
- m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv);
- m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv);
-}
-
-static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width)
-{
- unsigned short tmp0;
- int cnt;
- for (cnt = 0; cnt < col_width; cnt++) {
- tmp0 = m[i][cnt];
- m[i][cnt] = m[j][cnt];
- m[j][cnt] = tmp0;
- }
-}
-
-static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order)
-{
- unsigned short tmp[3];
- tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0]));
- tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1]));
- tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2]));
- sort_coefs(row_order, tmp, 3);
- coefs[0] = tmp[0];
- coefs[1] = tmp[1];
- coefs[2] = tmp[2];
-}
-
-static void find_3bit_err_pats(unsigned short s0, unsigned short s1,
- unsigned short s2, unsigned short r0,
- unsigned short r1, unsigned short r2,
- unsigned short *pats)
-{
- find_2x2_soln(r0 ^ r2, r1 ^ r2,
- gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2),
- gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats);
- pats[2] = s0 ^ pats[0] ^ pats[1];
-}
-
-static void find_4bit_err_coefs(unsigned short s0, unsigned short s1,
- unsigned short s2, unsigned short s3,
- unsigned short s4, unsigned short s5,
- unsigned short s6, unsigned short s7,
- unsigned short *coefs)
-{
- unsigned short m[4][5];
- int row_order[4];
-
- row_order[0] = 0;
- row_order[1] = 1;
- row_order[2] = 2;
- row_order[3] = 3;
-
- m[0][0] = s3;
- m[0][1] = s2;
- m[0][2] = s1;
- m[0][3] = s0;
- m[0][4] = s4;
- m[1][0] = s4;
- m[1][1] = s3;
- m[1][2] = s2;
- m[1][3] = s1;
- m[1][4] = s5;
- m[2][0] = s5;
- m[2][1] = s4;
- m[2][2] = s3;
- m[2][3] = s2;
- m[2][4] = s6;
- m[3][0] = s6;
- m[3][1] = s5;
- m[3][2] = s4;
- m[3][3] = s3;
- m[3][4] = s7;
-
- if (m[0][3] != 0x0) {
- zero_4x5_col3(m);
- } else if (m[1][3] != 0x0) {
- swap_4x5_rows(m, 0, 1, 5);
- zero_4x5_col3(m);
- } else if (m[2][3] != 0x0) {
- swap_4x5_rows(m, 0, 2, 5);
- zero_4x5_col3(m);
- } else if (m[3][3] != 0x0) {
- swap_4x5_rows(m, 0, 3, 5);
- zero_4x5_col3(m);
- } else {
- printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n");
- }
-
- if (m[1][2] != 0x0) {
- zero_4x5_col2(m);
- } else if (m[2][2] != 0x0) {
- swap_4x5_rows(m, 1, 2, 5);
- zero_4x5_col2(m);
- } else if (m[3][2] != 0x0) {
- swap_4x5_rows(m, 1, 3, 5);
- zero_4x5_col2(m);
- } else {
- printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n");
- }
-
- if (m[2][1] != 0x0) {
- zero_4x5_col1(m);
- } else if (m[3][1] != 0x0) {
- swap_4x5_rows(m, 2, 3, 5);
- zero_4x5_col1(m);
- } else {
- printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n");
- }
-
- solve_4x5(m, coefs, row_order);
-}
-
-static void zero_4x5_col3(unsigned short m[4][5])
-{
- unsigned short minv1, minv2, minv3;
-
- minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3]));
- minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3]));
- minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3]));
-
- m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
- m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
- m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1);
- m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1);
- m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
- m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
- m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2);
- m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2);
- m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3);
- m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3);
- m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3);
- m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3);
-}
-
-static void zero_4x5_col2(unsigned short m[4][5])
-{
- unsigned short minv2, minv3;
-
- minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2]));
- minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2]));
-
- m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2);
- m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2);
- m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2);
- m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3);
- m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3);
- m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3);
-}
-
-static void zero_4x5_col1(unsigned short m[4][5])
-{
- unsigned short minv;
-
- minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1]));
-
- m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv);
- m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv);
-}
-
-static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width)
-{
- unsigned short tmp0;
- int cnt;
-
- for (cnt = 0; cnt < col_width; cnt++) {
- tmp0 = m[i][cnt];
- m[i][cnt] = m[j][cnt];
- m[j][cnt] = tmp0;
- }
-}
-
-static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order)
-{
- unsigned short tmp[4];
-
- tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0]));
- tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1]));
- tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2]));
- tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^
- gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3]));
- sort_coefs(row_order, tmp, 4);
- coefs[0] = tmp[0];
- coefs[1] = tmp[1];
- coefs[2] = tmp[2];
- coefs[3] = tmp[3];
-}
-
-static void sort_coefs(int *order, unsigned short *soln, int len)
-{
- int cnt, start_cnt, least_ord, least_cnt;
- unsigned short tmp0;
- for (start_cnt = 0; start_cnt < len; start_cnt++) {
- for (cnt = start_cnt; cnt < len; cnt++) {
- if (cnt == start_cnt) {
- least_ord = order[cnt];
- least_cnt = start_cnt;
- } else {
- if (least_ord > order[cnt]) {
- least_ord = order[cnt];
- least_cnt = cnt;
- }
- }
- }
- if (least_cnt != start_cnt) {
- tmp0 = order[least_cnt];
- order[least_cnt] = order[start_cnt];
- order[start_cnt] = tmp0;
- tmp0 = soln[least_cnt];
- soln[least_cnt] = soln[start_cnt];
- soln[start_cnt] = tmp0;
- }
- }
-}
-
-static void find_4bit_err_pats(unsigned short s0, unsigned short s1,
- unsigned short s2, unsigned short s3,
- unsigned short z1, unsigned short z2,
- unsigned short z3, unsigned short z4,
- unsigned short *pats)
-{
- unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1,
- z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3;
- unsigned short tmp0, tmp1, tmp2, tmp3;
-
- z4_z1 = z4 ^ z1;
- z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3);
- z4_z2 = z4 ^ z2;
- s0z4_s1 = gf4096_mul(s0, z4) ^ s1;
- z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1);
- z4_z3 = z4 ^ z3;
- z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2);
- s1z4_s2 = gf4096_mul(s1, z4) ^ s2;
- z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3);
- z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1);
- z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2);
- s2z4_s3 = gf4096_mul(s2, z4) ^ s3;
-
- //find err pat 0,1
- find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^
- gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2,
- z3z4_z3z3) ^
- gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1,
- z3z3z4_z3z3z3) ^
- gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3),
- gf4096_mul(z2z4_z2z2,
- z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2,
- z3z4_z3z3),
- gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2,
- z4_z3),
- gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats);
- tmp0 = pats[0];
- tmp1 = pats[1];
- tmp2 = pats[0] ^ pats[1] ^ s0;
- tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1;
-
- //find err pat 2,3
- find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats);
- pats[2] = pats[0];
- pats[3] = pats[1];
- pats[0] = tmp0;
- pats[1] = tmp1;
-}
-
-static void find_2x2_soln(unsigned short c00, unsigned short c01,
- unsigned short c10, unsigned short c11,
- unsigned short lval0, unsigned short lval1,
- unsigned short *soln)
-{
- unsigned short m[2][3];
- m[0][0] = c00;
- m[0][1] = c01;
- m[0][2] = lval0;
- m[1][0] = c10;
- m[1][1] = c11;
- m[1][2] = lval1;
-
- if (m[0][1] != 0x0) {
- /* */
- } else if (m[1][1] != 0x0) {
- swap_2x3_rows(m);
- } else {
- printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n");
- }
-
- solve_2x3(m, soln);
-}
-
-static void swap_2x3_rows(unsigned short m[2][3])
-{
- unsigned short tmp0;
- int cnt;
-
- for (cnt = 0; cnt < 3; cnt++) {
- tmp0 = m[0][cnt];
- m[0][cnt] = m[1][cnt];
- m[1][cnt] = tmp0;
- }
-}
-
-static void solve_2x3(unsigned short m[2][3], unsigned short *coefs)
-{
- unsigned short minv;
-
- minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1]));
- m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv);
- m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv);
- coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0]));
- coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1]));
-}
-
-static unsigned char gf64_inv[64] = {
- 0, 1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25,
- 61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45, 6,
- 63, 2, 27, 21, 56, 9, 50, 19, 13, 47, 48, 5, 7, 30, 12, 41,
- 42, 4, 38, 18, 10, 29, 17, 60, 36, 8, 59, 58, 55, 16, 3, 32
-};
-
-static unsigned short gf4096_inv(unsigned short din)
-{
- unsigned short alahxal, ah2B, deno, inv, bl, bh;
- unsigned short ah, al, ahxal;
- unsigned short dout;
-
- ah = (din >> 6) & 0x3f;
- al = din & 0x3f;
- ahxal = ah ^ al;
- ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) |
- ((ah >> 1) & 0x10) |
- ((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) |
- ((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1);
- alahxal = gf64_mul(ahxal, al);
- deno = alahxal ^ ah2B;
- inv = gf64_inv[deno];
- bl = gf64_mul(inv, ahxal);
- bh = gf64_mul(inv, ah);
- dout = ((bh & 0x3f) << 6) | (bl & 0x3f);
- return (((bh & 0x3f) << 6) | (bl & 0x3f));
-}
-
-static unsigned short err_pos_lut[4096] = {
- 0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff,
- 0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff,
- 0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff,
- 0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff,
- 0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7,
- 0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff,
- 0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff,
- 0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f,
- 0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8,
- 0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe,
- 0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff,
- 0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1,
- 0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff,
- 0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff,
- 0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff,
- 0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8,
- 0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e,
- 0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff,
- 0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff,
- 0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff,
- 0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535,
- 0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d,
- 0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff,
- 0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5,
- 0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff,
- 0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294,
- 0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff,
- 0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4,
- 0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f,
- 0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b,
- 0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff,
- 0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff,
- 0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff,
- 0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158,
- 0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a,
- 0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff,
- 0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff,
- 0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017,
- 0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a,
- 0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351,
- 0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff,
- 0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff,
- 0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074,
- 0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da,
- 0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433,
- 0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285,
- 0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff,
- 0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d,
- 0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff,
- 0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff,
- 0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331,
- 0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff,
- 0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6,
- 0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3,
- 0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff,
- 0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf,
- 0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc,
- 0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381,
- 0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff,
- 0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f,
- 0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff,
- 0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488,
- 0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442,
- 0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6,
- 0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1,
- 0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae,
- 0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff,
- 0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff,
- 0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2,
- 0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec,
- 0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134,
- 0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b,
- 0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff,
- 0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff,
- 0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff,
- 0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5,
- 0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff,
- 0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff,
- 0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff,
- 0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff,
- 0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2,
- 0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff,
- 0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff,
- 0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff,
- 0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff,
- 0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff,
- 0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff,
- 0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff,
- 0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8,
- 0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb,
- 0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff,
- 0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff,
- 0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd,
- 0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff,
- 0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8,
- 0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9,
- 0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f,
- 0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7,
- 0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff,
- 0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d,
- 0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178,
- 0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff,
- 0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba,
- 0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff,
- 0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e,
- 0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff,
- 0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6,
- 0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff,
- 0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff,
- 0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc,
- 0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6,
- 0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5,
- 0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff,
- 0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc,
- 0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff,
- 0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3,
- 0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff,
- 0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6,
- 0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff,
- 0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a,
- 0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff,
- 0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff,
- 0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff,
- 0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff,
- 0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7,
- 0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff,
- 0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff,
- 0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af,
- 0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff,
- 0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2,
- 0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff,
- 0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff,
- 0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff,
- 0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339,
- 0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff,
- 0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff,
- 0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402,
- 0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff,
- 0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368,
- 0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b,
- 0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f,
- 0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff,
- 0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1,
- 0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff,
- 0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff,
- 0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb,
- 0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc,
- 0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097,
- 0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431,
- 0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1,
- 0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff,
- 0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6,
- 0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd,
- 0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff,
- 0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb,
- 0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff,
- 0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd,
- 0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff,
- 0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff,
- 0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519,
- 0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff,
- 0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084,
- 0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0,
- 0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c,
- 0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f,
- 0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a,
- 0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211,
- 0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff,
- 0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff,
- 0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff,
- 0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff,
- 0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff,
- 0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff,
- 0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180,
- 0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0,
- 0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004,
- 0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302,
- 0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff,
- 0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff,
- 0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272,
- 0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff,
- 0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344,
- 0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff,
- 0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e,
- 0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d,
- 0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff,
- 0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330,
- 0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042,
- 0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364,
- 0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff,
- 0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff,
- 0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f,
- 0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb,
- 0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e,
- 0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c,
- 0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194,
- 0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff,
- 0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff,
- 0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff,
- 0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff,
- 0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6,
- 0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff,
- 0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290,
- 0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff,
- 0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9,
- 0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d,
- 0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff,
- 0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9,
- 0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167,
- 0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020,
- 0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347,
- 0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff,
- 0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff,
- 0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff,
- 0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff,
- 0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff,
- 0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039,
- 0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096,
- 0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff,
- 0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8,
- 0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff,
- 0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd,
- 0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e,
- 0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f,
- 0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff,
- 0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7,
- 0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb,
- 0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff,
- 0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078,
- 0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300,
- 0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200,
- 0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f,
- 0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff,
- 0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216,
- 0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d,
- 0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0,
- 0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff,
- 0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff,
- 0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff,
- 0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff,
- 0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff,
- 0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff,
- 0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086,
- 0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff,
- 0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444,
- 0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff,
- 0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110,
- 0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099,
- 0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff,
- 0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da,
- 0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff,
- 0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff,
- 0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff,
- 0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff,
- 0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff,
- 0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283,
- 0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff,
- 0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff,
- 0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff,
- 0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff,
- 0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff,
- 0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195,
- 0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff,
- 0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff,
- 0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff,
- 0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff,
- 0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff,
- 0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245,
- 0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff,
- 0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6,
- 0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
- 0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1,
- 0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da,
- 0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff,
- 0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff,
- 0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5,
- 0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223,
- 0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002
-};
-
-static unsigned short err_pos(unsigned short din)
-{
- BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
- return err_pos_lut[din];
-}
-static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
- if ((chk_syndrome_list[0] | chk_syndrome_list[1] |
- chk_syndrome_list[2] | chk_syndrome_list[3] |
- chk_syndrome_list[4] | chk_syndrome_list[5] |
- chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) {
- return -EINVAL;
- } else {
- err_info[0] = 0x0;
- return 0;
- }
-}
-static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
- unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
- tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0]));
- tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1]));
- tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2]));
- tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3]));
- tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4]));
- tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5]));
- tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6]));
- if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) {
- err_info[0] = 0x1; // encode 1-symbol error as 0x1
- err_info[1] = err_pos(tmp0);
- err_info[1] = (unsigned short)(0x55e - err_info[1]);
- err_info[5] = chk_syndrome_list[0];
- return 0;
- } else
- return -EINVAL;
-}
-static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
- unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- unsigned short coefs[4];
- unsigned short err_pats[4];
- int found_num_root = 0;
- unsigned short bit2_root0, bit2_root1;
- unsigned short bit2_root0_inv, bit2_root1_inv;
- unsigned short err_loc_eqn, test_root;
- unsigned short bit2_loc0, bit2_loc1;
- unsigned short bit2_pat0, bit2_pat1;
-
- find_2x2_soln(chk_syndrome_list[1],
- chk_syndrome_list[0],
- chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs);
- for (test_root = 0x1; test_root < 0xfff; test_root++) {
- err_loc_eqn =
- gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
- if (err_loc_eqn == 0x0) {
- if (found_num_root == 0) {
- bit2_root0 = test_root;
- found_num_root = 1;
- } else if (found_num_root == 1) {
- bit2_root1 = test_root;
- found_num_root = 2;
- break;
- }
- }
- }
- if (found_num_root != 2)
- return -EINVAL;
- else {
- bit2_root0_inv = gf4096_inv(bit2_root0);
- bit2_root1_inv = gf4096_inv(bit2_root1);
- find_2bit_err_pats(chk_syndrome_list[0],
- chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats);
- bit2_pat0 = err_pats[0];
- bit2_pat1 = err_pats[1];
- //for(x+1)
- tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv)); //rinv0^4
- tmp1 = gf4096_mul(bit2_root0_inv, tmp0); //rinv0^5
- tmp2 = gf4096_mul(bit2_root0_inv, tmp1); //rinv0^6
- tmp3 = gf4096_mul(bit2_root0_inv, tmp2); //rinv0^7
- tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv)); //rinv1^4
- tmp5 = gf4096_mul(bit2_root1_inv, tmp4); //rinv1^5
- tmp6 = gf4096_mul(bit2_root1_inv, tmp5); //rinv1^6
- tmp7 = gf4096_mul(bit2_root1_inv, tmp6); //rinv1^7
- //check if only 2-bit error
- if ((chk_syndrome_list[4] ==
- (gf4096_mul(bit2_pat0, tmp0) ^
- gf4096_mul(bit2_pat1,
- tmp4))) & (chk_syndrome_list[5] ==
- (gf4096_mul(bit2_pat0, tmp1) ^
- gf4096_mul(bit2_pat1,
- tmp5))) &
- (chk_syndrome_list[6] ==
- (gf4096_mul(bit2_pat0, tmp2) ^
- gf4096_mul(bit2_pat1,
- tmp6))) & (chk_syndrome_list[7] ==
- (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) {
- if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) {
- return -EINVAL;
- } else {
- bit2_loc0 = 0x55e - err_pos(bit2_root0_inv);
- bit2_loc1 = 0x55e - err_pos(bit2_root1_inv);
- err_info[0] = 0x2; // encode 2-symbol error as 0x2
- err_info[1] = bit2_loc0;
- err_info[2] = bit2_loc1;
- err_info[5] = bit2_pat0;
- err_info[6] = bit2_pat1;
- return 0;
- }
- } else
- return -EINVAL;
- }
-}
-static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
- unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
- unsigned short coefs[4];
- unsigned short err_pats[4];
- int found_num_root = 0;
- unsigned short bit3_root0, bit3_root1, bit3_root2;
- unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv;
- unsigned short err_loc_eqn, test_root;
-
- find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1],
- chk_syndrome_list[2], chk_syndrome_list[3],
- chk_syndrome_list[4], chk_syndrome_list[5], coefs);
-
- for (test_root = 0x1; test_root < 0xfff; test_root++) {
- err_loc_eqn = gf4096_mul(coefs[2],
- gf4096_mul(gf4096_mul(test_root, test_root),
- test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root))
- ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-
- if (err_loc_eqn == 0x0) {
- if (found_num_root == 0) {
- bit3_root0 = test_root;
- found_num_root = 1;
- } else if (found_num_root == 1) {
- bit3_root1 = test_root;
- found_num_root = 2;
- } else if (found_num_root == 2) {
- bit3_root2 = test_root;
- found_num_root = 3;
- break;
- }
- }
- }
- if (found_num_root != 3)
- return -EINVAL;
- else {
- bit3_root0_inv = gf4096_inv(bit3_root0);
- bit3_root1_inv = gf4096_inv(bit3_root1);
- bit3_root2_inv = gf4096_inv(bit3_root2);
-
- find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1],
- chk_syndrome_list[2], bit3_root0_inv,
- bit3_root1_inv, bit3_root2_inv, err_pats);
-
- //check if only 3-bit error
- tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv);
- tmp0 = gf4096_mul(tmp0, tmp0);
- tmp0 = gf4096_mul(tmp0, bit3_root0_inv);
- tmp0 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^6
- tmp1 = gf4096_mul(tmp0, bit3_root0_inv); //rinv0^7
- tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv);
- tmp2 = gf4096_mul(tmp2, tmp2);
- tmp2 = gf4096_mul(tmp2, bit3_root1_inv);
- tmp2 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^6
- tmp3 = gf4096_mul(tmp2, bit3_root1_inv); //rinv1^7
- tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv);
- tmp4 = gf4096_mul(tmp4, tmp4);
- tmp4 = gf4096_mul(tmp4, bit3_root2_inv);
- tmp4 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^6
- tmp5 = gf4096_mul(tmp4, bit3_root2_inv); //rinv2^7
-
- //check if only 3 errors
- if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^
- gf4096_mul(err_pats[1], tmp2) ^
- gf4096_mul(err_pats[2], tmp4))) &
- (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^
- gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) {
- if ((err_pos(bit3_root0_inv) == 0xfff) |
- (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) {
- return -EINVAL;
- } else {
- err_info[0] = 0x3;
- err_info[1] = (0x55e - err_pos(bit3_root0_inv));
- err_info[2] = (0x55e - err_pos(bit3_root1_inv));
- err_info[3] = (0x55e - err_pos(bit3_root2_inv));
- err_info[5] = err_pats[0];
- err_info[6] = err_pats[1];
- err_info[7] = err_pats[2];
- return 0;
- }
- } else
- return -EINVAL;
- }
-}
-static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
- unsigned short coefs[4];
- unsigned short err_pats[4];
- int found_num_root = 0;
- unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3;
- unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv;
- unsigned short err_loc_eqn, test_root;
-
- find_4bit_err_coefs(chk_syndrome_list[0],
- chk_syndrome_list[1],
- chk_syndrome_list[2],
- chk_syndrome_list[3],
- chk_syndrome_list[4],
- chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs);
-
- for (test_root = 0x1; test_root < 0xfff; test_root++) {
- err_loc_eqn =
- gf4096_mul(coefs[3],
- gf4096_mul(gf4096_mul
- (gf4096_mul(test_root, test_root),
- test_root),
- test_root)) ^ gf4096_mul(coefs[2],
- gf4096_mul
- (gf4096_mul(test_root, test_root), test_root))
- ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root)
- ^ 0x1;
- if (err_loc_eqn == 0x0) {
- if (found_num_root == 0) {
- bit4_root0 = test_root;
- found_num_root = 1;
- } else if (found_num_root == 1) {
- bit4_root1 = test_root;
- found_num_root = 2;
- } else if (found_num_root == 2) {
- bit4_root2 = test_root;
- found_num_root = 3;
- } else {
- found_num_root = 4;
- bit4_root3 = test_root;
- break;
- }
- }
- }
- if (found_num_root != 4) {
- return -EINVAL;
- } else {
- bit4_root0_inv = gf4096_inv(bit4_root0);
- bit4_root1_inv = gf4096_inv(bit4_root1);
- bit4_root2_inv = gf4096_inv(bit4_root2);
- bit4_root3_inv = gf4096_inv(bit4_root3);
- find_4bit_err_pats(chk_syndrome_list[0],
- chk_syndrome_list[1],
- chk_syndrome_list[2],
- chk_syndrome_list[3],
- bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats);
- err_info[0] = 0x4;
- err_info[1] = (0x55e - err_pos(bit4_root0_inv));
- err_info[2] = (0x55e - err_pos(bit4_root1_inv));
- err_info[3] = (0x55e - err_pos(bit4_root2_inv));
- err_info[4] = (0x55e - err_pos(bit4_root3_inv));
- err_info[5] = err_pats[0];
- err_info[6] = err_pats[1];
- err_info[7] = err_pats[2];
- err_info[8] = err_pats[3];
- return 0;
- }
-}
-
-void correct_12bit_symbol(unsigned char *buf, unsigned short sym,
- unsigned short val)
-{
- if (unlikely(sym > 1366)) {
- printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym);
- } else if (sym == 0) {
- buf[0] ^= val;
- } else if (sym & 1) {
- buf[1+(3*(sym-1))/2] ^= (val >> 4);
- buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4);
- } else {
- buf[2+(3*(sym-2))/2] ^= (val >> 8);
- buf[3+(3*(sym-2))/2] ^= (val & 0xff);
- }
-}
-
-static int debugecc = 0;
-module_param(debugecc, int, 0644);
-
-int cafe_correct_ecc(unsigned char *buf,
- unsigned short *chk_syndrome_list)
-{
- unsigned short err_info[9];
- int i;
-
- if (debugecc) {
- printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n",
- chk_syndrome_list[0], chk_syndrome_list[1],
- chk_syndrome_list[2], chk_syndrome_list[3],
- chk_syndrome_list[4], chk_syndrome_list[5],
- chk_syndrome_list[6], chk_syndrome_list[7]);
- for (i=0; i < 2048; i+=16) {
- printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- i,
- buf[i], buf[i+1], buf[i+2], buf[i+3],
- buf[i+4], buf[i+5], buf[i+6], buf[i+7],
- buf[i+8], buf[i+9], buf[i+10], buf[i+11],
- buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
- }
- for ( ; i < 2112; i+=16) {
- printk(KERN_WARNING "O %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- i - 2048,
- buf[i], buf[i+1], buf[i+2], buf[i+3],
- buf[i+4], buf[i+5], buf[i+6], buf[i+7],
- buf[i+8], buf[i+9], buf[i+10], buf[i+11],
- buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
- }
- }
-
-
-
- if (chk_no_err_only(chk_syndrome_list, err_info) &&
- chk_1_err_only(chk_syndrome_list, err_info) &&
- chk_2_err_only(chk_syndrome_list, err_info) &&
- chk_3_err_only(chk_syndrome_list, err_info) &&
- chk_4_err_only(chk_syndrome_list, err_info)) {
- return -EIO;
- }
-
- for (i=0; i < err_info[0]; i++) {
- if (debugecc)
- printk(KERN_WARNING "Correct symbol %d with 0x%03x\n",
- err_info[1+i], err_info[5+i]);
-
- correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]);
- }
-
- return err_info[0];
-}
-
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe_nand.c
index c328a7514510..cff969d05d4a 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -11,6 +11,7 @@
#undef DEBUG
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
+#include <linux/rslib.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -46,13 +47,14 @@
#define CAFE_GLOBAL_IRQ_MASK 0x300c
#define CAFE_NAND_RESET 0x3034
-int cafe_correct_ecc(unsigned char *buf,
- unsigned short *chk_syndrome_list);
+/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+#define CTRL1_CHIPSELECT (1<<19)
struct cafe_priv {
struct nand_chip nand;
struct pci_dev *pdev;
void __iomem *mmio;
+ struct rs_control *rs;
uint32_t ctl1;
uint32_t ctl2;
int datalen;
@@ -195,8 +197,8 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
cafe->data_pos = cafe->datalen = 0;
- /* Set command valid bit */
- ctl1 = 0x80000000 | command;
+ /* Set command valid bit, mask in the chip select bit */
+ ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
/* Set RD or WR bits as appropriate */
if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
@@ -309,8 +311,16 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
{
- //struct cafe_priv *cafe = mtd->priv;
- // cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+ struct cafe_priv *cafe = mtd->priv;
+
+ cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+
+ /* Mask the appropriate bit into the stored value of ctl1
+ which will be used by cafe_nand_cmdfunc() */
+ if (chipnr)
+ cafe->ctl1 |= CTRL1_CHIPSELECT;
+ else
+ cafe->ctl1 &= ~CTRL1_CHIPSELECT;
}
static int cafe_nand_interrupt(int irq, void *id)
@@ -374,28 +384,66 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
- unsigned short syn[8];
- int i;
+ unsigned short syn[8], pat[4];
+ int pos[4];
+ u8 *oob = chip->oob_poi;
+ int i, n;
for (i=0; i<8; i+=2) {
uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
- syn[i] = tmp & 0xfff;
- syn[i+1] = (tmp >> 16) & 0xfff;
+ syn[i] = cafe->rs->index_of[tmp & 0xfff];
+ syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+ }
+
+ n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+ pat);
+
+ for (i = 0; i < n; i++) {
+ int p = pos[i];
+
+ /* The 12-bit symbols are mapped to bytes here */
+
+ if (p > 1374) {
+ /* out of range */
+ n = -1374;
+ } else if (p == 0) {
+ /* high four bits do not correspond to data */
+ if (pat[i] > 0xff)
+ n = -2048;
+ else
+ buf[0] ^= pat[i];
+ } else if (p == 1365) {
+ buf[2047] ^= pat[i] >> 4;
+ oob[0] ^= pat[i] << 4;
+ } else if (p > 1365) {
+ if ((p & 1) == 1) {
+ oob[3*p/2 - 2048] ^= pat[i] >> 4;
+ oob[3*p/2 - 2047] ^= pat[i] << 4;
+ } else {
+ oob[3*p/2 - 2049] ^= pat[i] >> 8;
+ oob[3*p/2 - 2048] ^= pat[i];
+ }
+ } else if ((p & 1) == 1) {
+ buf[3*p/2] ^= pat[i] >> 4;
+ buf[3*p/2 + 1] ^= pat[i] << 4;
+ } else {
+ buf[3*p/2 - 1] ^= pat[i] >> 8;
+ buf[3*p/2] ^= pat[i];
+ }
}
- if ((i = cafe_correct_ecc(buf, syn)) < 0) {
+ if (n < 0) {
dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
cafe_readl(cafe, NAND_ADDR2) * 2048);
- for (i=0; i< 0x5c; i+=4)
+ for (i = 0; i < 0x5c; i += 4)
printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
mtd->ecc_stats.failed++;
} else {
- dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
- mtd->ecc_stats.corrected += i;
+ dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+ mtd->ecc_stats.corrected += n;
}
}
-
return 0;
}
@@ -416,7 +464,7 @@ static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
- | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 14,
.len = 4,
.veroffs = 18,
@@ -426,7 +474,7 @@ static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
- | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 14,
.len = 4,
.veroffs = 18,
@@ -442,7 +490,7 @@ static struct nand_ecclayout cafe_oobinfo_512 = {
static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
- | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 14,
.len = 1,
.veroffs = 15,
@@ -452,7 +500,7 @@ static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
- | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+ | NAND_BBT_2BIT | NAND_BBT_VERSION,
.offs = 14,
.len = 1,
.veroffs = 15,
@@ -525,6 +573,48 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
return 0;
}
+/* F_2[X]/(X**6+X+1) */
+static unsigned short __devinit gf64_mul(u8 a, u8 b)
+{
+ u8 c;
+ unsigned int i;
+
+ c = 0;
+ for (i = 0; i < 6; i++) {
+ if (a & 1)
+ c ^= b;
+ a >>= 1;
+ b <<= 1;
+ if ((b & 0x40) != 0)
+ b ^= 0x43;
+ }
+
+ return c;
+}
+
+/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X] */
+static u16 __devinit gf4096_mul(u16 a, u16 b)
+{
+ u8 ah, al, bh, bl, ch, cl;
+
+ ah = a >> 6;
+ al = a & 0x3f;
+ bh = b >> 6;
+ bl = b & 0x3f;
+
+ ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+ cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+
+ return (ch << 6) ^ cl;
+}
+
+static int __devinit cafe_mul(int x)
+{
+ if (x == 0)
+ return 1;
+ return gf4096_mul(x, 0xe01);
+}
+
static int __devinit cafe_nand_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -564,6 +654,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
}
cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
+ cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+ if (!cafe->rs) {
+ err = -ENOMEM;
+ goto out_ior;
+ }
+
cafe->nand.cmdfunc = cafe_nand_cmdfunc;
cafe->nand.dev_ready = cafe_device_ready;
cafe->nand.read_byte = cafe_read_byte;
@@ -646,7 +742,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
/* Scan to find existence of the device */
- if (nand_scan_ident(mtd, 1)) {
+ if (nand_scan_ident(mtd, 2)) {
err = -ENXIO;
goto out_irq;
}
@@ -713,6 +809,7 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
free_irq(pdev->irq, mtd);
nand_release(mtd);
+ free_rs(cafe->rs);
pci_iounmap(pdev, cafe->mmio);
dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
kfree(mtd);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 04de315e4937..7e68203fe1ba 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -303,28 +303,27 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
struct nand_chip *chip = mtd->priv;
u16 bad;
+ page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
if (getchip) {
- page = (int)(ofs >> chip->page_shift);
chipnr = (int)(ofs >> chip->chip_shift);
nand_get_device(chip, mtd, FL_READING);
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
- } else
- page = (int)(ofs >> chip->page_shift);
+ }
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
- page & chip->pagemask);
+ page);
bad = cpu_to_le16(chip->read_word(mtd));
if (chip->badblockpos & 0x1)
bad >>= 8;
if ((bad & 0xFF) != 0xff)
res = 1;
} else {
- chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
- page & chip->pagemask);
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
if (chip->read_byte(mtd) != 0xff)
res = 1;
}
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
new file mode 100644
index 000000000000..cd725fc5e813
--- /dev/null
+++ b/drivers/mtd/nand/plat_nand.c
@@ -0,0 +1,150 @@
+/*
+ * Generic NAND driver
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.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/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+struct plat_nand_data {
+ struct nand_chip chip;
+ struct mtd_info mtd;
+ void __iomem *io_base;
+#ifdef CONFIG_MTD_PARTITIONS
+ int nr_parts;
+ struct mtd_partition *parts;
+#endif
+};
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init plat_nand_probe(struct platform_device *pdev)
+{
+ struct platform_nand_data *pdata = pdev->dev.platform_data;
+ struct plat_nand_data *data;
+ int res = 0;
+
+ /* Allocate memory for the device structure (and zero it) */
+ data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate device structure.\n");
+ return -ENOMEM;
+ }
+
+ data->io_base = ioremap(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start + 1);
+ if (data->io_base == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ kfree(data);
+ return -EIO;
+ }
+
+ data->chip.priv = &data;
+ data->mtd.priv = &data->chip;
+ data->mtd.owner = THIS_MODULE;
+
+ data->chip.IO_ADDR_R = data->io_base;
+ data->chip.IO_ADDR_W = data->io_base;
+ data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+ data->chip.dev_ready = pdata->ctrl.dev_ready;
+ data->chip.select_chip = pdata->ctrl.select_chip;
+ data->chip.chip_delay = pdata->chip.chip_delay;
+ data->chip.options |= pdata->chip.options;
+
+ data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+ data->chip.ecc.layout = pdata->chip.ecclayout;
+ data->chip.ecc.mode = NAND_ECC_SOFT;
+
+ platform_set_drvdata(pdev, data);
+
+ /* Scan to find existance of the device */
+ if (nand_scan(&data->mtd, 1)) {
+ res = -ENXIO;
+ goto out;
+ }
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->chip.part_probe_types) {
+ res = parse_mtd_partitions(&data->mtd,
+ pdata->chip.part_probe_types,
+ &data->parts, 0);
+ if (res > 0) {
+ add_mtd_partitions(&data->mtd, data->parts, res);
+ return 0;
+ }
+ }
+ if (pdata->chip.partitions) {
+ data->parts = pdata->chip.partitions;
+ res = add_mtd_partitions(&data->mtd, data->parts,
+ pdata->chip.nr_partitions);
+ } else
+#endif
+ res = add_mtd_device(&data->mtd);
+
+ if (!res)
+ return res;
+
+ nand_release(&data->mtd);
+out:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(data->io_base);
+ kfree(data);
+ return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit plat_nand_remove(struct platform_device *pdev)
+{
+ struct plat_nand_data *data = platform_get_drvdata(pdev);
+ struct platform_nand_data *pdata = pdev->dev.platform_data;
+
+ nand_release(&data->mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+ if (data->parts && data->parts != pdata->chip.partitions)
+ kfree(data->parts);
+#endif
+ iounmap(data->io_base);
+ kfree(data);
+
+ return 0;
+}
+
+static struct platform_driver plat_nand_driver = {
+ .probe = plat_nand_probe,
+ .remove = plat_nand_remove,
+ .driver = {
+ .name = "gen_nand",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init plat_nand_init(void)
+{
+ return platform_driver_register(&plat_nand_driver);
+}
+
+static void __exit plat_nand_exit(void)
+{
+ platform_driver_unregister(&plat_nand_driver);
+}
+
+module_init(plat_nand_init);
+module_exit(plat_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Simple generic NAND driver");
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 000794c6caf5..0537fac8de74 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -2192,7 +2192,7 @@ static int onenand_check_maf(int manuf)
* @param mtd MTD device structure
*
* OneNAND detection method:
- * Compare the the values from command with ones from register
+ * Compare the values from command with ones from register
*/
static int onenand_probe(struct mtd_info *mtd)
{
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 9588da3a30e7..127f60841b10 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -95,8 +95,7 @@ static int max_interrupt_work = 10;
#include <asm/io.h>
#include <asm/irq.h>
-static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
-static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
+static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
#if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA))
#define EL3_SUSPEND
@@ -360,7 +359,7 @@ static int __init el3_common_init(struct net_device *dev)
printk(", IRQ %d.\n", dev->irq);
if (el3_debug > 0)
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
return 0;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80924f76dee8..f26ca331615e 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -103,7 +103,7 @@ static int vortex_debug = 1;
static char version[] __devinitdata =
-DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
+DRV_NAME ": Donald Becker and others.\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 18aba838c1ff..82d78ff8399b 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -31,10 +31,8 @@
*/
-static const char versionA[] =
+static const char version[] =
"atp.c:v1.09=ac 2002/10/01 Donald Becker <becker@scyld.com>\n";
-static const char versionB[] =
-" http://www.scyld.com/network/atp.html\n";
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -324,7 +322,7 @@ static int __init atp_probe1(long ioaddr)
#ifndef MODULE
if (net_debug)
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
#endif
printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
@@ -926,7 +924,7 @@ static void set_rx_mode_8012(struct net_device *dev)
static int __init atp_init_module(void) {
if (debug) /* Emit version even if no cards detected. */
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
return atp_init();
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 724bce51f936..223517dcbcfd 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3461,7 +3461,7 @@ void bond_unregister_arp(struct bonding *bond)
/*---------------------------- Hashing Policies -----------------------------*/
/*
- * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * Hash for the output device based upon layer 3 and layer 4 data. If
* the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
* altogether not IP, mimic bond_xmit_hash_policy_l2()
*/
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 3a03a74c0609..637ae8f68791 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1214,7 +1214,7 @@ e1000_remove(struct pci_dev *pdev)
int i;
#endif
- flush_scheduled_work();
+ cancel_work_sync(&adapter->reset_task);
e1000_release_manageability(adapter);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 39654e1e2bed..47680237f783 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1126,7 +1126,7 @@ static void eepro_tx_timeout (struct net_device *dev)
printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
/* This is not a duplicate. One message for the console,
- one for the the log file */
+ one for the log file */
printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
eepro_complete_selreset(ioaddr);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 6c267c38df97..9800341956a2 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -28,7 +28,7 @@
*/
static const char * const version =
-"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://www.scyld.com/network/eepro100.html\n"
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n"
"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
/* A few user-configurable values that apply to all boards.
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4e3f14c9c717..5e517946f46a 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -93,8 +93,6 @@ static int rx_copybreak;
static char version[] __devinitdata =
DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
static char version2[] __devinitdata =
-" http://www.scyld.com/network/epic100.html\n";
-static char version3[] __devinitdata =
" (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -323,8 +321,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
#ifndef MODULE
static int printed_version;
if (!printed_version++)
- printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
- version, version2, version3);
+ printk (KERN_INFO "%s" KERN_INFO "%s",
+ version, version2);
#endif
card_idx++;
@@ -1596,8 +1594,8 @@ static int __init epic_init (void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
- printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
- version, version2, version3);
+ printk (KERN_INFO "%s" KERN_INFO "%s",
+ version, version2);
#endif
return pci_register_driver(&epic_driver);
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 6e90619b3b41..36d2c7d4f4d0 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -140,7 +140,7 @@ config BAYCOM_SER_HDX
modems that connect to a serial interface. The driver supports the
ser12 design in half-duplex mode. This is the old driver. It is
still provided in case your serial interface chip does not work with
- the full-duplex driver. This driver is depreciated. To configure
+ the full-duplex driver. This driver is deprecated. To configure
the driver, use the sethdlc utility available in the standard ax25
utilities package. For information on the modems, see
<http://www.baycom.de/> and
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 2ab173d9a0e4..1e67720f1066 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -113,7 +113,7 @@
/* RxOver overflow in Recv FIFO */
/* SipRcv received serial gap (or other condition you set) */
/* Interrupts are enabled by writing a one to the IER register */
-/* Interrupts are cleared by writting a one to the ISR register */
+/* Interrupts are cleared by writing a one to the ISR register */
/* */
/* 6. The remaining registers: 0x6 and 0x3 appear to be */
/* reserved parts of 16 or 32 bit registersthe remainder */
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index f15aebde7b90..52c99d01d568 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -315,7 +315,7 @@ ixgb_wait_eeprom_command(struct ixgb_hw *hw)
* hw - Struct containing variables accessed by shared code
*
* Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * If the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
* valid.
*
* Returns:
diff --git a/drivers/net/meth.h b/drivers/net/meth.h
index 84960dae2a22..ea3b8fc86d1e 100644
--- a/drivers/net/meth.h
+++ b/drivers/net/meth.h
@@ -126,7 +126,7 @@ typedef struct rx_packet {
/* Note: when loopback is set this bit becomes collision control. Setting this bit will */
/* cause a collision to be reported. */
- /* Bits 5 and 6 are used to determine the the Destination address filter mode */
+ /* Bits 5 and 6 are used to determine the Destination address filter mode */
#define METH_ACCEPT_MY 0 /* 00: Accept PHY address only */
#define METH_ACCEPT_MCAST 0x20 /* 01: Accept physical, broadcast, and multicast filter matches only */
#define METH_ACCEPT_AMCAST 0x40 /* 10: Accept physical, broadcast, and all multicast packets */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 223e0e6264ba..4cf0d3fcb519 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -131,7 +131,6 @@ static const char version[] __devinitdata =
KERN_INFO DRV_NAME " dp8381x driver, version "
DRV_VERSION ", " DRV_RELDATE "\n"
KERN_INFO " originally by Donald Becker <becker@scyld.com>\n"
- KERN_INFO " http://www.scyld.com/network/natsemi.html\n"
KERN_INFO " 2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 589785d1e762..995c0a5d4066 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -63,8 +63,7 @@ static int options[MAX_UNITS];
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n"
-KERN_INFO " http://www.scyld.com/network/ne2k-pci.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
#if defined(__powerpc__)
#define inl_le(addr) le32_to_cpu(inl(addr))
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index eed433d6056a..f71dab347667 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -662,10 +662,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
phy_error(phydev);
/*
- * Finish any pending work; we might have been scheduled
- * to be called from keventd ourselves, though.
+ * Finish any pending work; we might have been scheduled to be called
+ * from keventd ourselves, but cancel_work_sync() handles that.
*/
- run_scheduled_work(&phydev->phy_queue);
+ cancel_work_sync(&phydev->phy_queue);
free_irq(phydev->irq, phydev);
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index f51ba31970aa..e1f912d04043 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -110,8 +110,7 @@ static char *media[MAX_UNITS];
/* These identify the driver base version and may not be removed. */
static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"
-KERN_INFO " http://www.scyld.com/network/sundance.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e5e901ecd808..923b9c725cc3 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3716,10 +3716,8 @@ static void tg3_reset_task(struct work_struct *work)
unsigned int restart_timer;
tg3_full_lock(tp, 0);
- tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
if (!netif_running(tp->dev)) {
- tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
tg3_full_unlock(tp);
return;
}
@@ -3750,8 +3748,6 @@ static void tg3_reset_task(struct work_struct *work)
mod_timer(&tp->timer, jiffies + 1);
out:
- tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
-
tg3_full_unlock(tp);
}
@@ -7390,12 +7386,7 @@ static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- /* Calling flush_scheduled_work() may deadlock because
- * linkwatch_event() may be on the workqueue and it will try to get
- * the rtnl_lock which we are holding.
- */
- while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
- msleep(1);
+ cancel_work_sync(&tp->reset_task);
netif_stop_queue(dev);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 4d334cf5a243..bd9f4f428e5b 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2228,7 +2228,7 @@ struct tg3 {
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
-#define TG3_FLAG_IN_RESET_TASK 0x04000000
+
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_SUPPORT_MSI 0x20000000
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 9b08afbd1f65..ea896777bcaf 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -269,7 +269,7 @@ done:
This would turn on IM for devices that is not contributing
to backlog congestion with unnecessary latency.
- We monitor the the device RX-ring and have:
+ We monitor the device RX-ring and have:
HW Interrupt Mitigation either ON or OFF.
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index fa440706fb4a..38f3b99716b8 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1021,7 +1021,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_ring[entry].length |= DescEndRing;
/* Now acquire the irq spinlock.
- * The difficult race is the the ordering between
+ * The difficult race is the ordering between
* increasing np->cur_tx and setting DescOwned:
* - if np->cur_tx is increased first the interrupt
* handler could consider the packet as transmitted
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 985a1810ca59..2470b1ee33c0 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -1043,7 +1043,7 @@ static int enable_promisc(struct xircom_private *card)
/*
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
Must be called in locked state with interrupts disabled
*/
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index f2dd7763cd0b..f72573594121 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -639,7 +639,7 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
- /* "I feel a presence... another warrior is on the the mesa."
+ /* "I feel a presence... another warrior is on the mesa."
*/
wmb();
iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 38fac3bbcd82..7d5b8c2cc614 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -149,7 +149,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
/* Vitally important. If we don't do this it seems we get an
* interrupt somewhere during the power cycle, since
* hw_unavailable is already set it doesn't get ACKed, we get
- * into an interrupt loop and the the PMU decides to turn us
+ * into an interrupt loop and the PMU decides to turn us
* off. */
disable_irq(dev->irq);
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 841b3c136ad9..283be4a70524 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -3054,7 +3054,7 @@ static const iw_handler prism54_handler[] = {
(iw_handler) prism54_set_wap, /* SIOCSIWAP */
(iw_handler) prism54_get_wap, /* SIOCGIWAP */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */
+ (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */
(iw_handler) prism54_set_scan, /* SIOCSIWSCAN */
(iw_handler) prism54_get_scan, /* SIOCGIWSCAN */
(iw_handler) prism54_set_essid, /* SIOCSIWESSID */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index a037b11dac9d..084795355b74 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -115,7 +115,7 @@ isl_upload_firmware(islpci_private *priv)
ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
- /* set the cards base address for writting the data */
+ /* set the card's base address for writing the data */
isl38xx_w32_flush(device_base, reg,
ISL38XX_DIR_MEM_BASE_REG);
wmb(); /* be paranoid */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 67b867f837ca..5740d4d4267c 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -176,7 +176,7 @@ psa_write(struct net_device * dev,
volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
(psaoff(0, psa_comp_number) << 1);
- /* Authorize writting to PSA */
+ /* Authorize writing to PSA */
hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
while(n-- > 0)
@@ -1676,7 +1676,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */
fee_write(base, 0x60,
dac, 2);
- /* We now should verify here that the EEprom writting was ok */
+ /* We now should verify here that the EEprom writing was ok */
/* ReRead the first area */
fee_read(base, 0x00,
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 4d1c4905c749..4b9de0093a7b 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -120,7 +120,7 @@
* the Wavelan itself (NCR -> AT&T -> Lucent).
*
* All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * writing a Wavelan ISA driver for the MACH microkernel. Girish
* Welling <welling@paul.rutgers.edu> had also worked on it.
* Keith Moore modify this for the Pcmcia hardware.
*
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 3f4a7cf9efea..f2a90a7fa2d6 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -109,7 +109,6 @@ static int gx_fix;
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO " http://www.scyld.com/network/yellowfin.html\n"
KERN_INFO " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 3bb7739d26a5..8e58ea3d95c0 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -119,7 +119,7 @@ static inline int pci_create_newid_file(struct pci_driver *drv)
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*
- * Depreciated, don't use this as it will not catch any dynamic ids
+ * Deprecated, don't use this as it will not catch any dynamic ids
* that a driver might want to check for.
*/
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 5e439836db2d..76422eded36e 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -98,7 +98,7 @@ config RTC_INTF_DEV_UIE_EMUL
bool "RTC UIE emulation on dev interface"
depends on RTC_INTF_DEV
help
- Provides an emulation for RTC_UIE if the underlaying rtc chip
+ Provides an emulation for RTC_UIE if the underlying rtc chip
driver does not expose RTC_UIE ioctls. Those requests generate
once-per-second update interrupts, used for synchronization.
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 6abf4811958c..e0f91dfce0f5 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
writeb(tmp, rtc->regbase + RCR1);
- rtc_update_irq(&rtc->rtc_dev, 1, events);
+ rtc_update_irq(rtc->rtc_dev, 1, events);
spin_unlock(&rtc->lock);
@@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
rtc->rearm_aie = 1;
- rtc_update_irq(&rtc->rtc_dev, 1, events);
+ rtc_update_irq(rtc->rtc_dev, 1, events);
}
spin_unlock(&rtc->lock);
@@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
spin_lock(&rtc->lock);
- rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
spin_unlock(&rtc->lock);
@@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec--;
#endif
- dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index bbd5b8b66f42..d6b06ab81188 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -23,7 +23,7 @@
/*
* The room for the SCCB (only for writing) is not equal to a pages size
- * (as it is specified as the maximum size in the the SCLP documentation)
+ * (as it is specified as the maximum size in the SCLP documentation)
* because of the additional data structure described above.
*/
#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 29d176036e5c..0b96d49dd636 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -2860,7 +2860,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
if (!atomic_read(&queue->set_pci_flags_count)){
/*
* there's no outstanding PCI any more, so we
- * have to request a PCI to be sure the the PCI
+ * have to request a PCI to be sure that the PCI
* will wake at some time in the future then we
* can flush packed buffers that might still be
* hanging around, which can happen if no
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index cb08ca3cc0f9..bdf5782b8a7a 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -222,7 +222,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
* Since we have been using this adapter, it is save to assume
* that it is not failed but recoverable. The card seems to
* report link-up events by self-initiated queue shutdown.
- * That is why we need to clear the the link-down flag
+ * That is why we need to clear the link-down flag
* which is set again in case we have missed by a mile.
*/
zfcp_erp_adapter_reopen(
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 74b999d77bbf..4fab0c23814c 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -156,7 +156,7 @@ static unsigned short get_pins(unsigned minor)
#define BPP_ICR 0x18
#define BPP_SIZE 0x1A
-/* BPP_CSR. Bits of type RW1 are cleared with writting '1'. */
+/* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */
#define P_DEV_ID_MASK 0xf0000000 /* R */
#define P_DEV_ID_ZEBRA 0x40000000
#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 8d72bbae96ad..0bada0028aa0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -966,7 +966,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
| AHD_BUSFREEREV_BUG;
ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
- /* If the user requested the the SLOWCRC bit to be set. */
+ /* If the user requested that the SLOWCRC bit to be set. */
if (aic79xx_slowcrc)
ahd->features |= AHD_AIC79XXB_SLOWCRC;
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
index e6b70123940c..e78ce0fa44d2 100644
--- a/drivers/scsi/aic94xx/Makefile
+++ b/drivers/scsi/aic94xx/Makefile
@@ -6,7 +6,7 @@
#
# This file is licensed under GPLv2.
#
-# This file is part of the the aic94xx driver.
+# This file is part of the aic94xx driver.
#
# The aic94xx driver is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index a965ed3548d5..564ea90ed3a0 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -541,7 +541,7 @@ static struct ParameterData __devinitdata cfg_data[] = {
/*
- * Safe settings. If set to zero the the BIOS/default values with
+ * Safe settings. If set to zero the BIOS/default values with
* command line overrides will be used. If set to 1 then safe and
* slow settings will be used.
*/
@@ -617,7 +617,7 @@ static void __devinit fix_settings(void)
/*
* Mapping from the eeprom delay index value (index into this array)
- * to the the number of actual seconds that the delay should be for.
+ * to the number of actual seconds that the delay should be for.
*/
static char __devinitdata eeprom_index_to_delay_map[] =
{ 1, 3, 5, 10, 16, 30, 60, 120 };
@@ -4136,7 +4136,7 @@ static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long
* @io_port: base I/O address
* @addr: offset into SEEPROM
*
- * Returns the the byte read.
+ * Returns the byte read.
**/
static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
{
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 61fbcdcbb009..1f5a07bf2a75 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -173,7 +173,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* @retries: number of times to retry request
* @flags: or into request flags;
*
- * returns the req->errors value which is the the scsi_cmnd result
+ * returns the req->errors value which is the scsi_cmnd result
* field.
**/
int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 66e7bc985797..1d8a2f6bb8eb 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -22,10 +22,7 @@
#include <asm/io.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
-
-#ifdef CONFIG_ARCH_AT91
#include <asm/arch/cpu.h>
-#endif
#include "atmel_spi.h"
@@ -552,10 +549,8 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
goto out_free_buffer;
as->irq = irq;
as->clk = clk;
-#ifdef CONFIG_ARCH_AT91
if (!cpu_is_at91rm9200())
as->new_1 = 1;
-#endif
ret = request_irq(irq, atmel_spi_interrupt, 0,
pdev->dev.bus_id, master);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index b082d95bbbaa..11e9b15ca45a 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -1033,7 +1033,7 @@ static int usbatm_do_heavy_init(void *arg)
static int usbatm_heavy_init(struct usbatm_data *instance)
{
- int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+ int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
if (ret < 0) {
usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index b5332e679c46..88fb56d5db8f 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1307,7 +1307,7 @@ static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp)
}
-/* remove a service from the the device
+/* remove a service from the device
scp->id must be set! */
static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
{
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
index cbb53e065d6c..82db5a8e528e 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/usb/net/usbnet.h
@@ -129,7 +129,7 @@ extern void usbnet_disconnect(struct usb_interface *);
/* Drivers that reuse some of the standard USB CDC infrastructure
- * (notably, using multiple interfaces according to the the CDC
+ * (notably, using multiple interfaces according to the CDC
* union descriptor) get some helper code.
*/
struct cdc_state {
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index ba5d1dc03036..3efe67092f15 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -558,7 +558,7 @@ config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
depends on USB_SERIAL
help
- Say Y here if you have a USB debugging device used to recieve
+ Say Y here if you have a USB debugging device used to receive
debugging data from another machine. The most common of these
devices is the NetChip TurboCONNECT device.
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index b675735bfbee..fbc8c27d5d99 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -9,7 +9,7 @@
* The device works as an standard CDC device, it has 2 interfaces, the first
* one is for firmware access and the second is the serial one.
* The protocol is very simply, there are two posibilities reading or writing.
- * When writting the first urb must have a Header that starts with 0x20 0x29 the
+ * When writing the first urb must have a Header that starts with 0x20 0x29 the
* next two bytes must say how much data will be sended.
* When reading the process is almost equal except that the header starts with
* 0x00 0x20.
@@ -18,7 +18,7 @@
* buffer: The First and Second byte is used for a Header, the Third and Fourth
* tells the device the amount of information the package holds.
* Packages are 60 bytes long Header Stuff.
- * When writting to the device the first two bytes of the header are 0x20 0x29
+ * When writing to the device the first two bytes of the header are 0x20 0x29
* When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
* situation, when too much data arrives to the device because it sends the data
* but with out the header. I will use a simply hack to override this situation,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 18f74ac76565..4807f960150b 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2465,7 +2465,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
((edge_serial->is_epic) &&
(!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
(regNum == MCR))) {
- dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+ dbg("SendCmdWriteUartReg - Not writing to MCR Register");
return 0;
}
@@ -2473,7 +2473,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
((edge_serial->is_epic) &&
(!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
(regNum == LCR))) {
- dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+ dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
return 0;
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1132ba5ff391..9a256d2ff9dc 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1348,6 +1348,20 @@ config FB_VOODOO1
Please read the <file:Documentation/fb/README-sstfb.txt> for supported
options and other important info support.
+config FB_VT8623
+ tristate "VIA VT8623 support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for CastleRock integrated graphics core in the
+ VIA VT8623 [Apollo CLE266] chipset.
+
config FB_CYBLA
tristate "Cyberblade/i1 support"
depends on FB && PCI && X86_32 && !64BIT
@@ -1401,6 +1415,20 @@ config FB_TRIDENT_ACCEL
This will compile the Trident frame buffer device with
acceleration functions.
+config FB_ARK
+ tristate "ARK 2000PV support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for PCI graphics boards with ARK 2000PV chip
+ and ICS 5342 RAMDAC.
+
config FB_PM3
tristate "Permedia3 support"
depends on FB && PCI && BROKEN
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a916c204274f..0b70567458fb 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -54,10 +54,12 @@ obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
+obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_CYBLA) += cyblafb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_LE80578) += vermilion/
obj-$(CONFIG_FB_S3) += s3fb.o
+obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
new file mode 100644
index 000000000000..ba6fede5c466
--- /dev/null
+++ b/drivers/video/arkfb.c
@@ -0,0 +1,1200 @@
+/*
+ * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV
+ * with ICS 5342 dac (it is easy to add support for different dacs).
+ *
+ * Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct arkfb_info {
+ int mclk_freq;
+ int mtrr_reg;
+
+ struct dac_info *dac;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static const struct svga_fb_format arkfb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {24, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 8, 8},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+
+/* CRT timing register sets */
+
+static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
+// const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
+static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
+
+static const struct svga_timing_regs ark_timing_regs = {
+ ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
+ ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
+ ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
+ ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+static int threshold = 4;
+
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "FIFO threshold");
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+ const u8 *font = map->data;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+ int i, c;
+
+ if ((map->width != 8) || (map->height != 16) ||
+ (map->depth != 1) || (map->length != 256)) {
+ printk(KERN_ERR "fb%d: unsupported font parameters: width %d, "
+ "height %d, depth %d, length %d\n", info->node,
+ map->width, map->height, map->depth, map->length);
+ return;
+ }
+
+ fb += 2;
+ for (c = 0; c < map->length; c++) {
+ for (i = 0; i < map->height; i++) {
+ fb_writeb(font[i], &fb[i * 4]);
+ fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
+ }
+ fb += 128;
+
+ if ((c % 8) == 7)
+ fb += 128*8;
+
+ font += map->height;
+ }
+}
+
+static struct fb_tile_ops arkfb_tile_ops = {
+ .fb_settile = arkfb_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+/* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ arkfb_iplan_imageblit(info, image);
+ else
+ arkfb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ arkfb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+enum
+{
+ DAC_PSEUDO8_8,
+ DAC_RGB1555_8,
+ DAC_RGB0565_8,
+ DAC_RGB0888_8,
+ DAC_RGB8888_8,
+ DAC_PSEUDO8_16,
+ DAC_RGB1555_16,
+ DAC_RGB0565_16,
+ DAC_RGB0888_16,
+ DAC_RGB8888_16,
+ DAC_MAX
+};
+
+struct dac_ops {
+ int (*dac_get_mode)(struct dac_info *info);
+ int (*dac_set_mode)(struct dac_info *info, int mode);
+ int (*dac_get_freq)(struct dac_info *info, int channel);
+ int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
+ void (*dac_release)(struct dac_info *info);
+};
+
+typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
+typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
+
+struct dac_info
+{
+ struct dac_ops *dacops;
+ dac_read_regs_t dac_read_regs;
+ dac_write_regs_t dac_write_regs;
+ void *data;
+};
+
+
+static inline u8 dac_read_reg(struct dac_info *info, u8 reg)
+{
+ u8 code[2] = {reg, 0};
+ info->dac_read_regs(info->data, code, 1);
+ return code[1];
+}
+
+static inline void dac_read_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_read_regs(info->data, code, count);
+}
+
+static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val)
+{
+ u8 code[2] = {reg, val};
+ info->dac_write_regs(info->data, code, 1);
+}
+
+static inline void dac_write_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_write_regs(info->data, code, count);
+}
+
+static inline int dac_set_mode(struct dac_info *info, int mode)
+{
+ return info->dacops->dac_set_mode(info, mode);
+}
+
+static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ return info->dacops->dac_set_freq(info, channel, freq);
+}
+
+static inline void dac_release(struct dac_info *info)
+{
+ info->dacops->dac_release(info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ICS5342 DAC */
+
+struct ics5342_info
+{
+ struct dac_info dac;
+ u8 mode;
+};
+
+#define DAC_PAR(info) ((struct ics5342_info *) info)
+
+/* LSB is set to distinguish unused slots */
+static const u8 ics5342_mode_table[DAC_MAX] = {
+ [DAC_PSEUDO8_8] = 0x01, [DAC_RGB1555_8] = 0x21, [DAC_RGB0565_8] = 0x61,
+ [DAC_RGB0888_8] = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31,
+ [DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71
+};
+
+static int ics5342_set_mode(struct dac_info *info, int mode)
+{
+ u8 code;
+
+ if (mode >= DAC_MAX)
+ return -EINVAL;
+
+ code = ics5342_mode_table[mode];
+
+ if (! code)
+ return -EINVAL;
+
+ dac_write_reg(info, 6, code & 0xF0);
+ DAC_PAR(info)->mode = mode;
+
+ return 0;
+}
+
+static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3,
+ 60000, 250000, 14318};
+
+/* pd4 - allow only posdivider 4 (r=2) */
+static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2,
+ 60000, 335000, 14318};
+
+/* 270 MHz should be upper bound for VCO clock according to specs,
+ but that is too restrictive in pd4 case */
+
+static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ u16 m, n, r;
+
+ /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */
+ int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16)
+ ? &ics5342_pll_pd4 : &ics5342_pll,
+ freq, &m, &n, &r, 0);
+
+ if (rv < 0) {
+ return -EINVAL;
+ } else {
+ u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)};
+ dac_write_regs(info, code, 3);
+ return 0;
+ }
+}
+
+static void ics5342_release(struct dac_info *info)
+{
+ ics5342_set_mode(info, DAC_PSEUDO8_8);
+ kfree(info);
+}
+
+static struct dac_ops ics5342_ops = {
+ .dac_set_mode = ics5342_set_mode,
+ .dac_set_freq = ics5342_set_freq,
+ .dac_release = ics5342_release
+};
+
+
+static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data)
+{
+ struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL);
+
+ if (! info)
+ return NULL;
+
+ info->dacops = &ics5342_ops;
+ info->dac_read_regs = drr;
+ info->dac_write_regs = dwr;
+ info->data = data;
+ DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */
+ return info;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
+
+static void ark_dac_read_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+static void ark_dac_write_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+
+static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ struct arkfb_info *par = info->par;
+ u8 regval;
+
+ int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+}
+
+
+/* Open framebuffer */
+
+static int arkfb_open(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0x60;
+ par->state.num_seq = 0x30;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Close framebuffer */
+
+static int arkfb_release(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1) {
+ restore_vga(&(par->state));
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ }
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Validate passed in var */
+
+static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (arkfb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = arkfb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&ark_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode is broken */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Set video mode from par */
+
+static int arkfb_set_par(struct fb_info *info)
+{
+ struct arkfb_info *par = info->par;
+ u32 value, mode, hmul, hdiv, offset_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+ u8 regval;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &arkfb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+
+ /* Blank screen and turn off sync */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(ark_start_address_regs, 0);
+
+ /* ARK specific initialization */
+ svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+ svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+
+ vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
+ vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
+ vga_wseq(NULL, 0x15, 0);
+ vga_wseq(NULL, 0x16, 0);
+
+ /* Set the FIFO threshold register */
+ /* It is fascinating way to store 5-bit value in 8-bit register */
+ regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
+ vga_wseq(NULL, 0x18, regval);
+
+ /* Set the offset register */
+ pr_debug("fb%d: offset register : %d\n", info->node, offset_value);
+ svga_wcrt_multi(ark_offset_regs, offset_value);
+
+ /* fix for hi-res textmode */
+ svga_wcrt_mask(0x40, 0x08, 0x08);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ if (info->var.vmode & FB_VMODE_INTERLACED)
+ svga_wcrt_mask(0x44, 0x04, 0x04);
+ else
+ svga_wcrt_mask(0x44, 0x00, 0x04);
+
+ hmul = 1;
+ hdiv = 1;
+ mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix));
+
+ /* Set mode-specific register values */
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+
+ if (info->var.pixclock > 20000) {
+ pr_debug("fb%d: not using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ } else {
+ pr_debug("fb%d: using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_16);
+ hdiv = 2;
+ }
+ break;
+ case 4:
+ pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB1555_16);
+ break;
+ case 5:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0565_16);
+ break;
+ case 6:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0888_16);
+ hmul = 3;
+ hdiv = 2;
+ break;
+ case 7:
+ pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB8888_16);
+ hmul = 2;
+ break;
+ default:
+ printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+ return -EINVAL;
+ }
+
+ ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
+ svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1,
+ (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+ hmul, info->node);
+
+ /* Set interlaced mode start/end register */
+ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+ value = ((value * hmul / hdiv) / 8) - 5;
+ vga_wcrt(NULL, 0x42, (value + 1) / 2);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+/* Set a colour register */
+
+static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ if ((fb->var.bits_per_pixel == 4) &&
+ (fb->var.nonstd == 0)) {
+ outb(0xF0, VGA_PEL_MSK);
+ outb(regno*16, VGA_PEL_IW);
+ } else {
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ }
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set the display blanking state */
+
+static int arkfb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: sync down\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+ break;
+ }
+ return 0;
+}
+
+
+/* Pan the display */
+
+static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ offset = offset >> 2;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(ark_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops arkfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = arkfb_open,
+ .fb_release = arkfb_release,
+ .fb_check_var = arkfb_check_var,
+ .fb_set_par = arkfb_set_par,
+ .fb_setcolreg = arkfb_setcolreg,
+ .fb_blank = arkfb_blank,
+ .fb_pan_display = arkfb_pan_display,
+ .fb_fillrect = arkfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = arkfb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* PCI probe */
+static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct arkfb_info *par;
+ int rc;
+ u8 regval;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &arkfb_ops;
+
+ /* Prepare PCI device */
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "arkfb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
+ if (! par->dac) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+ goto err_dac;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap;
+ }
+
+ /* FIXME get memsize */
+ regval = vga_rseq(NULL, 0x10);
+ info->screen_size = (1 << (regval >> 6)) << 20;
+ info->fix.smem_len = info->screen_size;
+
+ strcpy(info->fix.id, "ARK 2000PV");
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*) (par->pseudo_palette);
+
+ /* Prepare startup mode */
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, info->screen_base);
+err_iomap:
+ dac_release(par->dac);
+err_dac:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit ark_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ dac_release(par->dac);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int ark_pci_resume (struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ arkfb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+ return 0;
+}
+#else
+#define ark_pci_suspend NULL
+#define ark_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id ark_devices[] __devinitdata = {
+ {PCI_DEVICE(0xEDD8, 0xA099)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, ark_devices);
+
+static struct pci_driver arkfb_pci_driver = {
+ .name = "arkfb",
+ .id_table = ark_devices,
+ .probe = ark_pci_probe,
+ .remove = __devexit_p(ark_pci_remove),
+ .suspend = ark_pci_suspend,
+ .resume = ark_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit arkfb_cleanup(void)
+{
+ pr_debug("arkfb: cleaning up\n");
+ pci_unregister_driver(&arkfb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init arkfb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("arkfb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("arkfb: initializing\n");
+ return pci_register_driver(&arkfb_pci_driver);
+}
+
+module_init(arkfb_init);
+module_exit(arkfb_cleanup);
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index f577bd80e020..03cfb7ac5733 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/softcursor.c
+ * linux/drivers/video/console/softcursor.c
*
* Generic software cursor for frame buffer devices
*
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 08d4e11d9121..38c2e2558f5e 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1236,6 +1236,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
#elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+ vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+ & ~_PAGE_CACHABLE)
+ | (_PAGE_BUFFER | _PAGE_DIRTY));
#elif defined(__ia64__)
if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 7e760197cf29..1a7d7789d877 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1717,7 +1717,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
* @info: pointer to device specific info structure
*
* DESCRIPTION:
- * Sets the the user monitor's horizontal and vertical
+ * Sets the user monitor's horizontal and vertical
* frequency limits
*/
static void __devinit i810_init_monspecs(struct fb_info *info)
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index a5690a5f29d5..9445cdb759b1 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -72,7 +72,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index a5c825d99466..c57aaadf410c 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -70,7 +70,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index cb2aa402ddfd..c8559a756b75 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -93,7 +93,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 18886b629cb1..5948e54b9ef9 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -78,7 +78,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index f297c7b14a41..c627955aa124 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -149,8 +149,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
pll = NV_RD32(par->PMC, 0x4024);
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
- if (((par->Chipset & 0xfff0) == 0x0290) ||
- ((par->Chipset & 0xfff0) == 0x0390)) {
+ if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
MB = 1;
NB = 1;
} else {
@@ -963,6 +962,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290))
regions = 15;
for(i = 0; i < regions; i++) {
@@ -1275,6 +1275,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
0x00100000);
break;
case 0x0090:
+ case 0x02E0:
case 0x0290:
NV_WR32(par->PRAMDAC, 0x0608,
NV_RD32(par->PRAMDAC, 0x0608) |
@@ -1352,6 +1353,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290)) {
for (i = 0; i < 60; i++) {
NV_WR32(par->PGRAPH,
@@ -1403,6 +1405,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if ((par->Chipset & 0xfff0) == 0x0090 ||
(par->Chipset & 0xfff0) == 0x01D0 ||
+ (par->Chipset & 0xfff0) == 0x02E0 ||
(par->Chipset & 0xfff0) == 0x0290) {
NV_WR32(par->PGRAPH, 0x0DF0,
NV_RD32(par->PFB, 0x0200));
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 7c36b5fe582e..f85edf084da3 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -1243,6 +1243,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
case 0x0140: /* GeForce 6600 */
case 0x0160: /* GeForce 6200 */
case 0x01D0: /* GeForce 7200, 7300, 7400 */
+ case 0x02E0: /* GeForce 7300 GT */
case 0x0090: /* GeForce 7800 */
case 0x0210: /* GeForce 6800 */
case 0x0220: /* GeForce 6200 */
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 756fafb41d78..d11735895a01 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -796,23 +796,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
return 0;
}
-/* Get capabilities of accelerator based on the mode */
-
-static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
- struct fb_var_screeninfo *var)
-{
- if (var->bits_per_pixel == 0) {
- /* can only support 256 8x16 bitmap */
- caps->x = 1 << (8 - 1);
- caps->y = 1 << (16 - 1);
- caps->len = 256;
- } else {
- caps->x = ~(u32)0;
- caps->y = ~(u32)0;
- caps->len = ~(u32)0;
- }
-}
-
/* ------------------------------------------------------------------------- */
/* Frame buffer operations */
@@ -829,7 +812,7 @@ static struct fb_ops s3fb_ops = {
.fb_fillrect = s3fb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = s3fb_imageblit,
- .fb_get_caps = s3fb_get_caps,
+ .fb_get_caps = svga_get_caps,
};
/* ------------------------------------------------------------------------- */
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 842b5cd054c6..836a612af977 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -14,7 +14,7 @@
* of it.
*
* First the roles of struct fb_info and struct display have changed. Struct
- * display will go away. The way the the new framebuffer console code will
+ * display will go away. The way the new framebuffer console code will
* work is that it will act to translate data about the tty/console in
* struct vc_data to data in a device independent way in struct fb_info. Then
* various functions in struct fb_ops will be called to store the device
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 079cdc911e48..25df928d37d8 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -347,6 +347,23 @@ int svga_get_tilemax(struct fb_info *info)
return 256;
}
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+ struct fb_var_screeninfo *var)
+{
+ if (var->bits_per_pixel == 0) {
+ /* can only support 256 8x16 bitmap */
+ caps->x = 1 << (8 - 1);
+ caps->y = 1 << (16 - 1);
+ caps->len = 256;
+ } else {
+ caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+ caps->y = ~(u32)0;
+ caps->len = ~(u32)0;
+ }
+}
+EXPORT_SYMBOL(svga_get_caps);
/* ------------------------------------------------------------------------- */
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
new file mode 100644
index 000000000000..5e9755e464a1
--- /dev/null
+++ b/drivers/video/vt8623fb.c
@@ -0,0 +1,927 @@
+/*
+ * linux/drivers/video/vt8623fb.c - fbdev driver for
+ * integrated graphic core in VIA VT8623 [CLE266] chipset
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb, some parts are from David Boucher's viafb
+ * (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct vt8623fb_info {
+ char __iomem *mmio_base;
+ int mtrr_reg;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format vt8623fb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+/* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
+ 60000, 300000, 14318};
+
+/* CRT timing register sets */
+
+struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+struct svga_timing_regs vt8623_timing_regs = {
+ vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
+ vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
+ vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
+ vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
+
+module_param(mode, charp, 0644);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_tile_ops vt8623fb_tile_ops = {
+ .fb_settile = svga_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ vt8623fb_iplan_imageblit(info, image);
+ else
+ vt8623fb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ vt8623fb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ u16 m, n, r;
+ u8 regval;
+ int rv;
+
+ rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+ /* Set clock registers */
+ vga_wseq(NULL, 0x46, (n | (r << 6)));
+ vga_wseq(NULL, 0x47, m);
+
+ udelay(1000);
+
+ /* PLL reset */
+ svga_wseq_mask(0x40, 0x02, 0x02);
+ svga_wseq_mask(0x40, 0x00, 0x02);
+}
+
+
+static int vt8623fb_open(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0xA2;
+ par->state.num_seq = 0x50;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_release(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1)
+ restore_vga(&(par->state));
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (vt8623fb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = vt8623fb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ /* Text mode is limited to 256 kB of memory */
+ if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
+ {
+ printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10);
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode not supported */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static int vt8623fb_set_par(struct fb_info *info)
+{
+ u32 mode, offset_value, fetch_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ fetch_value = ((info->var.xres * bpp) / 128) + 4;
+
+ if (bpp == 4)
+ fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */
+
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &vt8623fb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ fetch_value = (info->var.xres / 8) + 8;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wseq_mask(0x10, 0x01, 0x01);
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+ svga_wcrt_mask(0x47, 0x00, 0x01);
+
+ /* Device, screen and sync off */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(vt8623_start_address_regs, 0);
+
+ svga_wcrt_multi(vt8623_offset_regs, offset_value);
+ svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
+ svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
+ svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+ vga_wseq(NULL, 0x17, 0x1F); // FIFO depth
+ vga_wseq(NULL, 0x18, 0x4E);
+ svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+
+ vga_wcrt(NULL, 0x32, 0x00);
+ vga_wcrt(NULL, 0x34, 0x00);
+ vga_wcrt(NULL, 0x6A, 0x80);
+ vga_wcrt(NULL, 0x6A, 0xC0);
+
+ vga_wgfx(NULL, 0x20, 0x00);
+ vga_wgfx(NULL, 0x21, 0x00);
+ vga_wgfx(NULL, 0x22, 0x00);
+
+ /* Set SR15 according to number of bits per pixel */
+ mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x60, 0x70);
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+ svga_wseq_mask(0x15, 0x20, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+ svga_wseq_mask(0x15, 0x22, 0xFE);
+ break;
+ case 4:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xB6, 0xFE);
+ break;
+ case 5:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xAE, 0xFE);
+ break;
+ default:
+ printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
+ return (-EINVAL);
+ }
+
+ vt8623_set_pixclock(info, info->var.pixclock);
+ svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
+ 1, info->node);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+
+static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ /* ((transp & 0xFF00) << 16) */
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x10, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x20, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_POWERDOWN:
+ pr_debug("fb%d: DPMS off (no sync)\n", info->node);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+ offset = offset >> 3;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(vt8623_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops vt8623fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = vt8623fb_open,
+ .fb_release = vt8623fb_release,
+ .fb_check_var = vt8623fb_check_var,
+ .fb_set_par = vt8623fb_set_par,
+ .fb_setcolreg = vt8623fb_setcolreg,
+ .fb_blank = vt8623fb_blank,
+ .fb_pan_display = vt8623fb_pan_display,
+ .fb_fillrect = vt8623fb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = vt8623fb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* PCI probe */
+
+static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct vt8623fb_info *par;
+ unsigned int memsize1, memsize2;
+ int rc;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &vt8623fb_ops;
+
+ /* Prepare PCI device */
+
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "vt8623fb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+ info->fix.mmio_start = pci_resource_start(dev, 1);
+ info->fix.mmio_len = pci_resource_len(dev, 1);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap_1;
+ }
+
+ par->mmio_base = pci_iomap(dev, 1, 0);
+ if (! par->mmio_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for MMIO failed\n");
+ goto err_iomap_2;
+ }
+
+ /* Find how many physical memory there is on card */
+ memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
+ memsize2 = vga_rseq(NULL, 0x39) << 2;
+
+ if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
+ info->screen_size = memsize1 << 20;
+ else {
+ dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+ info->screen_size = 16 << 20;
+ }
+
+ info->fix.smem_len = info->screen_size;
+ strcpy(info->fix.id, "VIA VT8623");
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*)par->pseudo_palette;
+
+ /* Prepare startup mode */
+
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, par->mmio_base);
+err_iomap_2:
+ pci_iounmap(dev, info->screen_base);
+err_iomap_1:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_iounmap(dev, par->mmio_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int vt8623_pci_resume(struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ vt8623fb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+
+ return 0;
+}
+#else
+#define vt8623_pci_suspend NULL
+#define vt8623_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id vt8623_devices[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, vt8623_devices);
+
+static struct pci_driver vt8623fb_pci_driver = {
+ .name = "vt8623fb",
+ .id_table = vt8623_devices,
+ .probe = vt8623_pci_probe,
+ .remove = __devexit_p(vt8623_pci_remove),
+ .suspend = vt8623_pci_suspend,
+ .resume = vt8623_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit vt8623fb_cleanup(void)
+{
+ pr_debug("vt8623fb: cleaning up\n");
+ pci_unregister_driver(&vt8623fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+int __init vt8623fb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("vt8623fb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("vt8623fb: initializing\n");
+ return pci_register_driver(&vt8623fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(vt8623fb_init);
+module_exit(vt8623fb_cleanup);
OpenPOWER on IntegriCloud