diff options
author | James Bottomley <James.Bottomley@suse.de> | 2011-04-24 15:30:14 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2011-05-14 14:59:15 -0400 |
commit | 9281b16caac1276817b77033c5b8a1f5ca30102c (patch) | |
tree | 73c554e4ab9e9dcfe1b610f2f65e0ae1713341b5 | |
parent | 5f6f12ccf3aa42cfc0c5bde9228df0c843dd63f7 (diff) |
pata_cm64x: fix boot crash on parisc
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>
-rw-r--r-- | drivers/ata/pata_cmd64x.c | 42 | ||||
-rw-r--r-- | include/linux/pci_ids.h | 2 |
2 files changed, 40 insertions, 4 deletions
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 905ff76d3cbb..7bafc16cf5e0 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c | |||
@@ -41,6 +41,9 @@ | |||
41 | enum { | 41 | enum { |
42 | CFR = 0x50, | 42 | CFR = 0x50, |
43 | CFR_INTR_CH0 = 0x04, | 43 | CFR_INTR_CH0 = 0x04, |
44 | CNTRL = 0x51, | ||
45 | CNTRL_CH0 = 0x04, | ||
46 | CNTRL_CH1 = 0x08, | ||
44 | CMDTIM = 0x52, | 47 | CMDTIM = 0x52, |
45 | ARTTIM0 = 0x53, | 48 | ARTTIM0 = 0x53, |
46 | DRWTIM0 = 0x54, | 49 | DRWTIM0 = 0x54, |
@@ -328,9 +331,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
328 | .port_ops = &cmd648_port_ops | 331 | .port_ops = &cmd648_port_ops |
329 | } | 332 | } |
330 | }; | 333 | }; |
331 | const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL }; | 334 | const struct ata_port_info *ppi[] = { |
332 | u8 mrdmode; | 335 | &cmd_info[id->driver_data], |
336 | &cmd_info[id->driver_data], | ||
337 | NULL | ||
338 | }; | ||
339 | u8 mrdmode, reg; | ||
333 | int rc; | 340 | int rc; |
341 | struct pci_dev *bridge = pdev->bus->self; | ||
342 | /* mobility split bridges don't report enabled ports correctly */ | ||
343 | int port_ok = !(bridge && bridge->vendor == | ||
344 | PCI_VENDOR_ID_MOBILITY_ELECTRONICS); | ||
345 | /* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */ | ||
346 | int cntrl_ch0_ok = (id->driver_data != 0); | ||
334 | 347 | ||
335 | rc = pcim_enable_device(pdev); | 348 | rc = pcim_enable_device(pdev); |
336 | if (rc) | 349 | if (rc) |
@@ -341,11 +354,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
341 | 354 | ||
342 | if (pdev->device == PCI_DEVICE_ID_CMD_646) { | 355 | if (pdev->device == PCI_DEVICE_ID_CMD_646) { |
343 | /* Does UDMA work ? */ | 356 | /* Does UDMA work ? */ |
344 | if (pdev->revision > 4) | 357 | if (pdev->revision > 4) { |
345 | ppi[0] = &cmd_info[2]; | 358 | ppi[0] = &cmd_info[2]; |
359 | ppi[1] = &cmd_info[2]; | ||
360 | } | ||
346 | /* Early rev with other problems ? */ | 361 | /* Early rev with other problems ? */ |
347 | else if (pdev->revision == 1) | 362 | else if (pdev->revision == 1) { |
348 | ppi[0] = &cmd_info[3]; | 363 | ppi[0] = &cmd_info[3]; |
364 | ppi[1] = &cmd_info[3]; | ||
365 | } | ||
366 | /* revs 1,2 have no CNTRL_CH0 */ | ||
367 | if (pdev->revision < 3) | ||
368 | cntrl_ch0_ok = 0; | ||
349 | } | 369 | } |
350 | 370 | ||
351 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); | 371 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); |
@@ -354,6 +374,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
354 | mrdmode |= 0x02; /* Memory read line enable */ | 374 | mrdmode |= 0x02; /* Memory read line enable */ |
355 | pci_write_config_byte(pdev, MRDMODE, mrdmode); | 375 | pci_write_config_byte(pdev, MRDMODE, mrdmode); |
356 | 376 | ||
377 | /* check for enabled ports */ | ||
378 | pci_read_config_byte(pdev, CNTRL, ®); | ||
379 | if (!port_ok) | ||
380 | dev_printk(KERN_NOTICE, &pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n"); | ||
381 | if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) { | ||
382 | dev_printk(KERN_NOTICE, &pdev->dev, "Primary port is disabled\n"); | ||
383 | ppi[0] = &ata_dummy_port_info; | ||
384 | |||
385 | } | ||
386 | if (port_ok && !(reg & CNTRL_CH1)) { | ||
387 | dev_printk(KERN_NOTICE, &pdev->dev, "Secondary port is disabled\n"); | ||
388 | ppi[1] = &ata_dummy_port_info; | ||
389 | } | ||
390 | |||
357 | /* Force PIO 0 here.. */ | 391 | /* Force PIO 0 here.. */ |
358 | 392 | ||
359 | /* PPC specific fixup copied from old driver */ | 393 | /* PPC specific fixup copied from old driver */ |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 8abe8d78c4bf..8652a4fa3fe2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -608,6 +608,8 @@ | |||
608 | #define PCI_DEVICE_ID_MATROX_G550 0x2527 | 608 | #define PCI_DEVICE_ID_MATROX_G550 0x2527 |
609 | #define PCI_DEVICE_ID_MATROX_VIA 0x4536 | 609 | #define PCI_DEVICE_ID_MATROX_VIA 0x4536 |
610 | 610 | ||
611 | #define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 | ||
612 | |||
611 | #define PCI_VENDOR_ID_CT 0x102c | 613 | #define PCI_VENDOR_ID_CT 0x102c |
612 | #define PCI_DEVICE_ID_CT_69000 0x00c0 | 614 | #define PCI_DEVICE_ID_CT_69000 0x00c0 |
613 | #define PCI_DEVICE_ID_CT_65545 0x00d8 | 615 | #define PCI_DEVICE_ID_CT_65545 0x00d8 |