powerpc/macio: Rework hotplug media bay support

The hotplug mediabay has tendrils deep into drivers/ide code
which makes a libata port reather difficult. In addition it's
ugly and could be done better.

This reworks the interface between the mediabay and the rest
of the world so that:

   - Any macio_driver can now have a mediabay_event callback
which will be called when that driver sits on a mediabay and
it's been either plugged or unplugged. The device type is
passed as an argument. We can now move all the IDE cruft
into the IDE driver itself

   - A check_media_bay() function can be used to take a peek
at the type of device currently in the bay if any, a cleaner
variant of the previous function with the same name.

   - A pair of lock/unlock functions are exposed to allow the
IDE driver to block the hotplug callbacks during the initial
setup and probing of the bay in order to avoid nasty race
conditions.

   - The mediabay code no longer needs to spin on the status
register of the IDE interface when it detects an IDE device,
this is done just fine by the IDE code itself

Overall, less code, simpler, and allows for another driver
than our old drivers/ide based one.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 128b4a0e
...@@ -134,6 +134,9 @@ struct macio_driver ...@@ -134,6 +134,9 @@ struct macio_driver
int (*resume)(struct macio_dev* dev); int (*resume)(struct macio_dev* dev);
int (*shutdown)(struct macio_dev* dev); int (*shutdown)(struct macio_dev* dev);
#ifdef CONFIG_PMAC_MEDIABAY
void (*mediabay_event)(struct macio_dev* dev, int mb_state);
#endif
struct device_driver driver; struct device_driver driver;
}; };
#define to_macio_driver(drv) container_of(drv,struct macio_driver, driver) #define to_macio_driver(drv) container_of(drv,struct macio_driver, driver)
......
...@@ -17,26 +17,31 @@ ...@@ -17,26 +17,31 @@
#define MB_POWER 6 /* media bay contains a Power device (???) */ #define MB_POWER 6 /* media bay contains a Power device (???) */
#define MB_NO 7 /* media bay contains nothing */ #define MB_NO 7 /* media bay contains nothing */
/* Number of bays in the machine or 0 */ struct macio_dev;
extern int media_bay_count;
#ifdef CONFIG_BLK_DEV_IDE_PMAC #ifdef CONFIG_PMAC_MEDIABAY
#include <linux/ide.h>
int check_media_bay_by_base(unsigned long base, int what); /* Check the content type of the bay, returns MB_NO if the bay is still
/* called by IDE PMAC host driver to register IDE controller for media bay */ * transitionning
int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base, */
int irq, ide_hwif_t *hwif); extern int check_media_bay(struct macio_dev *bay);
int check_media_bay(struct device_node *which_bay, int what); /* The ATA driver uses the calls below to temporarily hold on the
* media bay callbacks while initializing the interface
*/
extern void lock_media_bay(struct macio_dev *bay);
extern void unlock_media_bay(struct macio_dev *bay);
#else #else
static inline int check_media_bay(struct device_node *which_bay, int what) static inline int check_media_bay(struct macio_dev *bay)
{ {
return -ENODEV; return MB_NO;
} }
static inline void lock_media_bay(struct macio_dev *bay) { }
static inline void unlock_media_bay(struct macio_dev *bay) { }
#endif #endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -200,7 +200,7 @@ struct floppy_state { ...@@ -200,7 +200,7 @@ struct floppy_state {
int ejected; int ejected;
wait_queue_head_t wait; wait_queue_head_t wait;
int wanted; int wanted;
struct device_node* media_bay; /* NULL when not in bay */ struct macio_dev *mdev;
char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
}; };
...@@ -303,14 +303,13 @@ static int swim3_readbit(struct floppy_state *fs, int bit) ...@@ -303,14 +303,13 @@ static int swim3_readbit(struct floppy_state *fs, int bit)
static void do_fd_request(struct request_queue * q) static void do_fd_request(struct request_queue * q)
{ {
int i; int i;
for(i=0;i<floppy_count;i++)
{ for(i=0; i<floppy_count; i++) {
#ifdef CONFIG_PMAC_MEDIABAY struct floppy_state *fs = &floppy_states[i];
if (floppy_states[i].media_bay && if (fs->mdev->media_bay &&
check_media_bay(floppy_states[i].media_bay, MB_FD)) check_media_bay(fs->mdev->media_bay) != MB_FD)
continue; continue;
#endif /* CONFIG_PMAC_MEDIABAY */ start_request(fs);
start_request(&floppy_states[i]);
} }
} }
...@@ -849,10 +848,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -849,10 +848,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)) if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
#ifdef CONFIG_PMAC_MEDIABAY if (fs->mdev->media_bay &&
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) check_media_bay(fs->mdev->media_bay) != MB_FD)
return -ENXIO; return -ENXIO;
#endif
switch (cmd) { switch (cmd) {
case FDEJECT: case FDEJECT:
...@@ -876,10 +874,9 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) ...@@ -876,10 +874,9 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
int n, err = 0; int n, err = 0;
if (fs->ref_count == 0) { if (fs->ref_count == 0) {
#ifdef CONFIG_PMAC_MEDIABAY if (fs->mdev->media_bay &&
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) check_media_bay(fs->mdev->media_bay) != MB_FD)
return -ENXIO; return -ENXIO;
#endif
out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
out_8(&sw->control_bic, 0xff); out_8(&sw->control_bic, 0xff);
out_8(&sw->mode, 0x95); out_8(&sw->mode, 0x95);
...@@ -963,10 +960,9 @@ static int floppy_revalidate(struct gendisk *disk) ...@@ -963,10 +960,9 @@ static int floppy_revalidate(struct gendisk *disk)
struct swim3 __iomem *sw; struct swim3 __iomem *sw;
int ret, n; int ret, n;
#ifdef CONFIG_PMAC_MEDIABAY if (fs->mdev->media_bay &&
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) check_media_bay(fs->mdev->media_bay) != MB_FD)
return -ENXIO; return -ENXIO;
#endif
sw = fs->swim3; sw = fs->swim3;
grab_drive(fs, revalidating, 0); grab_drive(fs, revalidating, 0);
...@@ -1009,7 +1005,6 @@ static const struct block_device_operations floppy_fops = { ...@@ -1009,7 +1005,6 @@ static const struct block_device_operations floppy_fops = {
static int swim3_add_device(struct macio_dev *mdev, int index) static int swim3_add_device(struct macio_dev *mdev, int index)
{ {
struct device_node *swim = mdev->ofdev.node; struct device_node *swim = mdev->ofdev.node;
struct device_node *mediabay;
struct floppy_state *fs = &floppy_states[index]; struct floppy_state *fs = &floppy_states[index];
int rc = -EBUSY; int rc = -EBUSY;
...@@ -1036,9 +1031,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index) ...@@ -1036,9 +1031,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
} }
dev_set_drvdata(&mdev->ofdev.dev, fs); dev_set_drvdata(&mdev->ofdev.dev, fs);
mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? if (mdev->media_bay == NULL)
swim->parent : NULL;
if (mediabay == NULL)
pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
memset(fs, 0, sizeof(*fs)); memset(fs, 0, sizeof(*fs));
...@@ -1068,7 +1061,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index) ...@@ -1068,7 +1061,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
fs->secpercyl = 36; fs->secpercyl = 36;
fs->secpertrack = 18; fs->secpertrack = 18;
fs->total_secs = 2880; fs->total_secs = 2880;
fs->media_bay = mediabay; fs->mdev = mdev;
init_waitqueue_head(&fs->wait); init_waitqueue_head(&fs->wait);
fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space); fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
...@@ -1093,7 +1086,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index) ...@@ -1093,7 +1086,7 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
init_timer(&fs->timeout); init_timer(&fs->timeout);
printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count, printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
mediabay ? "in media bay" : ""); mdev->media_bay ? "in media bay" : "");
return 0; return 0;
......
...@@ -43,10 +43,7 @@ ...@@ -43,10 +43,7 @@
#include <asm/pmac_feature.h> #include <asm/pmac_feature.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/irq.h> #include <asm/irq.h>
#ifndef CONFIG_PPC64
#include <asm/mediabay.h> #include <asm/mediabay.h>
#endif
#define DRV_NAME "ide-pmac" #define DRV_NAME "ide-pmac"
...@@ -59,13 +56,14 @@ typedef struct pmac_ide_hwif { ...@@ -59,13 +56,14 @@ typedef struct pmac_ide_hwif {
int irq; int irq;
int kind; int kind;
int aapl_bus_id; int aapl_bus_id;
unsigned mediabay : 1;
unsigned broken_dma : 1; unsigned broken_dma : 1;
unsigned broken_dma_warn : 1; unsigned broken_dma_warn : 1;
struct device_node* node; struct device_node* node;
struct macio_dev *mdev; struct macio_dev *mdev;
u32 timings[4]; u32 timings[4];
volatile u32 __iomem * *kauai_fcr; volatile u32 __iomem * *kauai_fcr;
ide_hwif_t *hwif;
/* Those fields are duplicating what is in hwif. We currently /* Those fields are duplicating what is in hwif. We currently
* can't use the hwif ones because of some assumptions that are * can't use the hwif ones because of some assumptions that are
* beeing done by the generic code about the kind of dma controller * beeing done by the generic code about the kind of dma controller
...@@ -854,6 +852,11 @@ sanitize_timings(pmac_ide_hwif_t *pmif) ...@@ -854,6 +852,11 @@ sanitize_timings(pmac_ide_hwif_t *pmif)
pmif->timings[2] = pmif->timings[3] = value2; pmif->timings[2] = pmif->timings[3] = value2;
} }
static int on_media_bay(pmac_ide_hwif_t *pmif)
{
return pmif->mdev && pmif->mdev->media_bay != NULL;
}
/* Suspend call back, should be called after the child devices /* Suspend call back, should be called after the child devices
* have actually been suspended * have actually been suspended
*/ */
...@@ -866,7 +869,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif) ...@@ -866,7 +869,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
disable_irq(pmif->irq); disable_irq(pmif->irq);
/* The media bay will handle itself just fine */ /* The media bay will handle itself just fine */
if (pmif->mediabay) if (on_media_bay(pmif))
return 0; return 0;
/* Kauai has bus control FCRs directly here */ /* Kauai has bus control FCRs directly here */
...@@ -889,7 +892,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif) ...@@ -889,7 +892,7 @@ static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif) static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif)
{ {
/* Hard reset & re-enable controller (do we really need to reset ? -BenH) */ /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */
if (!pmif->mediabay) { if (!on_media_bay(pmif)) {
ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
msleep(10); msleep(10);
...@@ -950,13 +953,11 @@ static void pmac_ide_init_dev(ide_drive_t *drive) ...@@ -950,13 +953,11 @@ static void pmac_ide_init_dev(ide_drive_t *drive)
pmac_ide_hwif_t *pmif = pmac_ide_hwif_t *pmif =
(pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent); (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
if (pmif->mediabay) { if (on_media_bay(pmif)) {
#ifdef CONFIG_PMAC_MEDIABAY if (check_media_bay(pmif->mdev->media_bay) == MB_CD) {
if (check_media_bay_by_base(pmif->regbase, MB_CD) == 0) {
drive->dev_flags &= ~IDE_DFLAG_NOPROBE; drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
return; return;
} }
#endif
drive->dev_flags |= IDE_DFLAG_NOPROBE; drive->dev_flags |= IDE_DFLAG_NOPROBE;
} }
} }
...@@ -1072,26 +1073,23 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ...@@ -1072,26 +1073,23 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
writel(KAUAI_FCR_UATA_MAGIC | writel(KAUAI_FCR_UATA_MAGIC |
KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_RESET_N |
KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr); KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
pmif->mediabay = 0;
/* Make sure we have sane timings */ /* Make sure we have sane timings */
sanitize_timings(pmif); sanitize_timings(pmif);
/* If we are on a media bay, wait for it to settle and lock it */
if (pmif->mdev)
lock_media_bay(pmif->mdev->media_bay);
host = ide_host_alloc(&d, hws, 1); host = ide_host_alloc(&d, hws, 1);
if (host == NULL) if (host == NULL) {
return -ENOMEM; rc = -ENOMEM;
hwif = host->ports[0]; goto bail;
}
hwif = pmif->hwif = host->ports[0];
#ifndef CONFIG_PPC64 if (on_media_bay(pmif)) {
/* XXX FIXME: Media bay stuff need re-organizing */ /* Fixup bus ID for media bay */
if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
#ifdef CONFIG_PMAC_MEDIABAY
media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq,
hwif);
#endif /* CONFIG_PMAC_MEDIABAY */
pmif->mediabay = 1;
if (!bidp) if (!bidp)
pmif->aapl_bus_id = 1; pmif->aapl_bus_id = 1;
} else if (pmif->kind == controller_ohare) { } else if (pmif->kind == controller_ohare) {
...@@ -1100,9 +1098,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ...@@ -1100,9 +1098,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
* units, I keep the old way * units, I keep the old way
*/ */
ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
} else } else {
#endif
{
/* This is necessary to enable IDE when net-booting */ /* This is necessary to enable IDE when net-booting */
ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
...@@ -1112,17 +1108,21 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ...@@ -1112,17 +1108,21 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
} }
printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), " printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), "
"bus ID %d%s, irq %d\n", model_name[pmif->kind], "bus ID %d%s, irq %d\n", model_name[pmif->kind],
pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hw->irq); on_media_bay(pmif) ? " (mediabay)" : "", hw->irq);
rc = ide_host_register(host, &d, hws); rc = ide_host_register(host, &d, hws);
if (rc) { if (rc)
ide_host_free(host); pmif->hwif = NULL;
return rc;
}
return 0; if (pmif->mdev)
unlock_media_bay(pmif->mdev->media_bay);
bail:
if (rc && host)
ide_host_free(host);
return rc;
} }
static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base) static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
...@@ -1362,6 +1362,25 @@ pmac_ide_pci_resume(struct pci_dev *pdev) ...@@ -1362,6 +1362,25 @@ pmac_ide_pci_resume(struct pci_dev *pdev)
return rc; return rc;
} }
#ifdef CONFIG_PMAC_MEDIABAY
static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state)
{
pmac_ide_hwif_t *pmif =
(pmac_ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
switch(mb_state) {
case MB_CD:
if (!pmif->hwif->present)
ide_port_scan(pmif->hwif);
break;
default:
if (pmif->hwif->present)
ide_port_unregister_devices(pmif->hwif);
}
}
#endif /* CONFIG_PMAC_MEDIABAY */
static struct of_device_id pmac_ide_macio_match[] = static struct of_device_id pmac_ide_macio_match[] =
{ {
{ {
...@@ -1386,6 +1405,9 @@ static struct macio_driver pmac_ide_macio_driver = ...@@ -1386,6 +1405,9 @@ static struct macio_driver pmac_ide_macio_driver =
.probe = pmac_ide_macio_attach, .probe = pmac_ide_macio_attach,
.suspend = pmac_ide_macio_suspend, .suspend = pmac_ide_macio_suspend,
.resume = pmac_ide_macio_resume, .resume = pmac_ide_macio_resume,
#ifdef CONFIG_PMAC_MEDIABAY
.mediabay_event = pmac_ide_macio_mb_event,
#endif
}; };
static const struct pci_device_id pmac_ide_pci_match[] = { static const struct pci_device_id pmac_ide_pci_match[] = {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment