forked from Minki/linux
07f1dc8cc8
Unloading the falconide module results in a crash:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
Oops: 00000000
Modules linked in: falconide(-)
PC: [<002930b2>] ide_host_remove+0x2e/0x1d2
SR: 2000 SP: 00b49e28 a2: 009b0f90
d0: 00000000 d1: 009b0f90 d2: 00000000 d3: 00b48000
d4: 003cef32 d5: 00299188 a0: 0086d000 a1: 0086d000
Process rmmod (pid: 322, task=009b0f90)
Frame format=7 eff addr=00000000 ssw=0505 faddr=00000000
wb 1 stat/addr/data: 0000 00000000 00000000
wb 2 stat/addr/data: 0000 00000000 00000000
wb 3 stat/addr/data: 0000 00000000 00018da9
push data: 00000000 00000000 00000000 00000000
Stack from 00b49e90:
004c456a 0027f176 0027cb0a 0027cb9e 00000000 0086d00a 2187d3f0 0027f0e0
00b49ebc 2187d1f6 00000000 00b49ec8 002811e8 0086d000 00b49ef0 0028024c
0086d00a 002800d6 00279a1a 00000001 00000001 0086d00a 2187d3f0 00279a58
00b49f1c 002802e0 0086d00a 2187d3f0 004c456a 0086d00a ef96af74 00000000
2187d3f0 002805d2 800de064 00b49f44 0027f088 2187d3f0 00ac1cf4 2187d3f0
004c43be 2187d3f0 00000000 2187d3f0 800b66a8 00b49f5c 00280776 2187d3f0
Call Trace: [<0027f176>] __device_driver_unlock+0x0/0x48
[<0027cb0a>] device_links_busy+0x0/0x94
[<0027cb9e>] device_links_unbind_consumers+0x0/0x130
[<0027f0e0>] __device_driver_lock+0x0/0x5a
[<2187d1f6>] falconide_remove+0x12/0x18 [falconide]
[<002811e8>] platform_drv_remove+0x1c/0x28
[<0028024c>] device_release_driver_internal+0x176/0x17c
[<002800d6>] device_release_driver_internal+0x0/0x17c
[<00279a1a>] get_device+0x0/0x22
[<00279a58>] put_device+0x0/0x18
[<002802e0>] driver_detach+0x56/0x82
[<002805d2>] driver_remove_file+0x0/0x24
[<0027f088>] bus_remove_driver+0x4c/0xa4
[<00280776>] driver_unregister+0x28/0x5a
[<00281a00>] platform_driver_unregister+0x12/0x18
[<2187d2a0>] ide_falcon_driver_exit+0x10/0x16 [falconide]
[<000764f0>] sys_delete_module+0x110/0x1f2
[<000e83ea>] sys_rename+0x1a/0x1e
[<00002e0c>] syscall+0x8/0xc
[<00188004>] ext4_multi_mount_protect+0x35a/0x3ce
Code: 0029 9188 4bf9 0027 aa1c 283c 003c ef32 <265c> 4a8b 6700 00b8 2043 2028 000c 0280 00ff ff00 6600 0176 40c0 7202 b2b9 004c
Disabling lock debugging due to kernel taint
This happens because the driver_data pointer is uninitialized.
Add the missing platform_set_drvdata() call. For clarity, use the
matching platform_get_drvdata() as well.
Cc: Michael Schmitz <schmitzmic@gmail.com>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Fixes: 5ed0794cde
("m68k/atari: Convert Falcon IDE drivers to platform drivers")
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Reviewed-by: Michael Schmitz <schmitzmic@gmail.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
198 lines
4.4 KiB
C
198 lines
4.4 KiB
C
/*
|
|
* Atari Falcon IDE Driver
|
|
*
|
|
* Created 12 Jul 1997 by Geert Uytterhoeven
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/ide.h>
|
|
#include <linux/init.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/setup.h>
|
|
#include <asm/atarihw.h>
|
|
#include <asm/atariints.h>
|
|
#include <asm/atari_stdma.h>
|
|
#include <asm/ide.h>
|
|
|
|
#define DRV_NAME "falconide"
|
|
|
|
/*
|
|
* Offsets from base address
|
|
*/
|
|
|
|
#define ATA_HD_CONTROL 0x39
|
|
|
|
/*
|
|
* falconide_intr_lock is used to obtain access to the IDE interrupt,
|
|
* which is shared between several drivers.
|
|
*/
|
|
|
|
static int falconide_intr_lock;
|
|
|
|
static void falconide_release_lock(void)
|
|
{
|
|
if (falconide_intr_lock == 0) {
|
|
printk(KERN_ERR "%s: bug\n", __func__);
|
|
return;
|
|
}
|
|
falconide_intr_lock = 0;
|
|
stdma_release();
|
|
}
|
|
|
|
static void falconide_get_lock(irq_handler_t handler, void *data)
|
|
{
|
|
if (falconide_intr_lock == 0) {
|
|
stdma_lock(handler, data);
|
|
falconide_intr_lock = 1;
|
|
}
|
|
}
|
|
|
|
static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
|
|
void *buf, unsigned int len)
|
|
{
|
|
unsigned long data_addr = drive->hwif->io_ports.data_addr;
|
|
|
|
if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
|
|
__ide_mm_insw(data_addr, buf, (len + 1) / 2);
|
|
return;
|
|
}
|
|
|
|
raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
|
|
}
|
|
|
|
static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
|
|
void *buf, unsigned int len)
|
|
{
|
|
unsigned long data_addr = drive->hwif->io_ports.data_addr;
|
|
|
|
if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
|
|
__ide_mm_outsw(data_addr, buf, (len + 1) / 2);
|
|
return;
|
|
}
|
|
|
|
raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
|
|
}
|
|
|
|
/* Atari has a byte-swapped IDE interface */
|
|
static const struct ide_tp_ops falconide_tp_ops = {
|
|
.exec_command = ide_exec_command,
|
|
.read_status = ide_read_status,
|
|
.read_altstatus = ide_read_altstatus,
|
|
.write_devctl = ide_write_devctl,
|
|
|
|
.dev_select = ide_dev_select,
|
|
.tf_load = ide_tf_load,
|
|
.tf_read = ide_tf_read,
|
|
|
|
.input_data = falconide_input_data,
|
|
.output_data = falconide_output_data,
|
|
};
|
|
|
|
static const struct ide_port_info falconide_port_info = {
|
|
.get_lock = falconide_get_lock,
|
|
.release_lock = falconide_release_lock,
|
|
.tp_ops = &falconide_tp_ops,
|
|
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
|
|
IDE_HFLAG_NO_DMA,
|
|
.irq_flags = IRQF_SHARED,
|
|
.chipset = ide_generic,
|
|
};
|
|
|
|
static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
|
|
{
|
|
int i;
|
|
|
|
memset(hw, 0, sizeof(*hw));
|
|
|
|
hw->io_ports.data_addr = base;
|
|
|
|
for (i = 1; i < 8; i++)
|
|
hw->io_ports_array[i] = base + 1 + i * 4;
|
|
|
|
hw->io_ports.ctl_addr = base + ATA_HD_CONTROL;
|
|
|
|
hw->irq = IRQ_MFP_IDE;
|
|
}
|
|
|
|
/*
|
|
* Probe for a Falcon IDE interface
|
|
*/
|
|
|
|
static int __init falconide_init(struct platform_device *pdev)
|
|
{
|
|
struct resource *res;
|
|
struct ide_host *host;
|
|
struct ide_hw hw, *hws[] = { &hw };
|
|
unsigned long base;
|
|
int rc;
|
|
|
|
dev_info(&pdev->dev, "Atari Falcon IDE controller\n");
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!res)
|
|
return -ENODEV;
|
|
|
|
if (!devm_request_mem_region(&pdev->dev, res->start,
|
|
resource_size(res), DRV_NAME)) {
|
|
dev_err(&pdev->dev, "resources busy\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
base = (unsigned long)res->start;
|
|
|
|
falconide_setup_ports(&hw, base);
|
|
|
|
host = ide_host_alloc(&falconide_port_info, hws, 1);
|
|
if (host == NULL) {
|
|
rc = -ENOMEM;
|
|
goto err;
|
|
}
|
|
|
|
falconide_get_lock(NULL, NULL);
|
|
rc = ide_host_register(host, &falconide_port_info, hws);
|
|
falconide_release_lock();
|
|
|
|
if (rc)
|
|
goto err_free;
|
|
|
|
platform_set_drvdata(pdev, host);
|
|
return 0;
|
|
err_free:
|
|
ide_host_free(host);
|
|
err:
|
|
release_mem_region(res->start, resource_size(res));
|
|
return rc;
|
|
}
|
|
|
|
static int falconide_remove(struct platform_device *pdev)
|
|
{
|
|
struct ide_host *host = platform_get_drvdata(pdev);
|
|
|
|
ide_host_remove(host);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver ide_falcon_driver = {
|
|
.remove = falconide_remove,
|
|
.driver = {
|
|
.name = "atari-falcon-ide",
|
|
},
|
|
};
|
|
|
|
module_platform_driver_probe(ide_falcon_driver, falconide_init);
|
|
|
|
MODULE_AUTHOR("Geert Uytterhoeven");
|
|
MODULE_DESCRIPTION("low-level driver for Atari Falcon IDE");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("platform:atari-falcon-ide");
|