Skip to content

Commit

Permalink
pata_cm64x: fix boot crash on parisc
Browse files Browse the repository at this point in the history
commit 9281b16 upstream.

The old IDE cmd64x checks the status of the CNTRL register to see if
the ports are enabled before probing them.  pata_cmd64x doesn't do
this, which causes a HPMC on parisc when it tries to poke at the
secondary port because apparently the BAR isn't wired up (and a
non-responding piece of memory causes a HPMC).

Fix this by porting the CNTRL register port detection logic from IDE
cmd64x.  In addition, following converns from Alan Cox, add a check to
see if a mobility electronics bridge is the immediate parent and forgo
the check if it is (prevents problems on hotplug controllers).

Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
James Bottomley authored and Greg Kroah-Hartman committed Jun 23, 2011
1 parent 5ad3787 commit d1ce810
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
42 changes: 38 additions & 4 deletions drivers/ata/pata_cmd64x.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
enum {
CFR = 0x50,
CFR_INTR_CH0 = 0x04,
CNTRL = 0x51,
CNTRL_CH0 = 0x04,
CNTRL_CH1 = 0x08,
CMDTIM = 0x52,
ARTTIM0 = 0x53,
DRWTIM0 = 0x54,
Expand Down Expand Up @@ -328,9 +331,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &cmd648_port_ops
}
};
const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
u8 mrdmode;
const struct ata_port_info *ppi[] = {
&cmd_info[id->driver_data],
&cmd_info[id->driver_data],
NULL
};
u8 mrdmode, reg;
int rc;
struct pci_dev *bridge = pdev->bus->self;
/* mobility split bridges don't report enabled ports correctly */
int port_ok = !(bridge && bridge->vendor ==
PCI_VENDOR_ID_MOBILITY_ELECTRONICS);
/* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */
int cntrl_ch0_ok = (id->driver_data != 0);

rc = pcim_enable_device(pdev);
if (rc)
Expand All @@ -341,11 +354,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)

if (pdev->device == PCI_DEVICE_ID_CMD_646) {
/* Does UDMA work ? */
if (pdev->revision > 4)
if (pdev->revision > 4) {
ppi[0] = &cmd_info[2];
ppi[1] = &cmd_info[2];
}
/* Early rev with other problems ? */
else if (pdev->revision == 1)
else if (pdev->revision == 1) {
ppi[0] = &cmd_info[3];
ppi[1] = &cmd_info[3];
}
/* revs 1,2 have no CNTRL_CH0 */
if (pdev->revision < 3)
cntrl_ch0_ok = 0;
}

pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
Expand All @@ -354,6 +374,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
mrdmode |= 0x02; /* Memory read line enable */
pci_write_config_byte(pdev, MRDMODE, mrdmode);

/* check for enabled ports */
pci_read_config_byte(pdev, CNTRL, &reg);
if (!port_ok)
dev_printk(KERN_NOTICE, &pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n");
if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) {
dev_printk(KERN_NOTICE, &pdev->dev, "Primary port is disabled\n");
ppi[0] = &ata_dummy_port_info;

}
if (port_ok && !(reg & CNTRL_CH1)) {
dev_printk(KERN_NOTICE, &pdev->dev, "Secondary port is disabled\n");
ppi[1] = &ata_dummy_port_info;
}

/* Force PIO 0 here.. */

/* PPC specific fixup copied from old driver */
Expand Down
2 changes: 2 additions & 0 deletions include/linux/pci_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,8 @@
#define PCI_DEVICE_ID_MATROX_G550 0x2527
#define PCI_DEVICE_ID_MATROX_VIA 0x4536

#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2

#define PCI_VENDOR_ID_CT 0x102c
#define PCI_DEVICE_ID_CT_69000 0x00c0
#define PCI_DEVICE_ID_CT_65545 0x00d8
Expand Down

0 comments on commit d1ce810

Please sign in to comment.