aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorKeck, David <david.keck@amd.com>2006-01-16 16:22:36 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 21:00:12 -0500
commit53044f357448693f218cc4f053affe92ed414f9d (patch)
treedabb2a73762270027d72828a055ba1dd243860af /drivers/pci/hotplug
parent3c0c6441883be7676b795939e268b90d6acab360 (diff)
[PATCH] PCI Hotplug: shpchp: AMD POGO errata fix
This patch fixes the AMD POGO errata on the hotplug controller where the platform will lock up or reboot if PERR/SERR generation is enabled and a slot is sent an enable command. This fix disables PERR/SERR generation before a slot is sent the enable command by first saving related registers, turning off SERR/PERR generation, enabling the slot, then restoring the registers. Signed-off-by: David Keck <david.keck@amd.com> Cc: Kristen Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/shpchp.h94
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c12
2 files changed, 105 insertions, 1 deletions
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index ce0e9b6ce833..7d6f521d02ea 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -95,6 +95,7 @@ struct controller {
95 u8 function; 95 u8 function;
96 u8 slot_device_offset; 96 u8 slot_device_offset;
97 u8 add_support; 97 u8 add_support;
98 u32 pcix_misc2_reg; /* for amd pogo errata */
98 enum pci_bus_speed speed; 99 enum pci_bus_speed speed;
99 u32 first_slot; /* First physical slot number */ 100 u32 first_slot; /* First physical slot number */
100 u8 slot_bus; /* Bus where the slots handled by this controller sit */ 101 u8 slot_bus; /* Bus where the slots handled by this controller sit */
@@ -113,6 +114,26 @@ struct hotplug_params {
113 114
114/* Define AMD SHPC ID */ 115/* Define AMD SHPC ID */
115#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 116#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
117#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
118
119/* AMD PCIX bridge registers */
120
121#define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C
122#define PCIX_MISCII_OFFSET 0x48
123#define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80
124
125/* AMD PCIX_MISCII masks and offsets */
126#define PERRNONFATALENABLE_MASK 0x00040000
127#define PERRFATALENABLE_MASK 0x00080000
128#define PERRFLOODENABLE_MASK 0x00100000
129#define SERRNONFATALENABLE_MASK 0x00200000
130#define SERRFATALENABLE_MASK 0x00400000
131
132/* AMD PCIX_MISC_BRIDGE_ERRORS masks and offsets */
133#define PERR_OBSERVED_MASK 0x00000001
134
135/* AMD PCIX_MEM_BASE_LIMIT masks */
136#define RSE_MASK 0x40000000
116 137
117#define INT_BUTTON_IGNORE 0 138#define INT_BUTTON_IGNORE 0
118#define INT_PRESENCE_ON 1 139#define INT_PRESENCE_ON 1
@@ -333,6 +354,79 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl)
333 return retval; 354 return retval;
334} 355}
335 356
357static inline void amd_pogo_errata_save_misc_reg(struct slot *p_slot)
358{
359 u32 pcix_misc2_temp;
360
361 /* save MiscII register */
362 pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp);
363
364 p_slot->ctrl->pcix_misc2_reg = pcix_misc2_temp;
365
366 /* clear SERR/PERR enable bits */
367 pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
368 pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
369 pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
370 pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
371 pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
372 pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
373}
374
375static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot)
376{
377 u32 pcix_misc2_temp;
378 u32 pcix_bridge_errors_reg;
379 u32 pcix_mem_base_reg;
380 u8 perr_set;
381 u8 rse_set;
382
383 /* write-one-to-clear Bridge_Errors[ PERR_OBSERVED ] */
384 pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, &pcix_bridge_errors_reg);
385 perr_set = pcix_bridge_errors_reg & PERR_OBSERVED_MASK;
386 if (perr_set) {
387 dbg ("%s W1C: Bridge_Errors[ PERR_OBSERVED = %08X]\n",__FUNCTION__ , perr_set);
388
389 pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, perr_set);
390 }
391
392 /* write-one-to-clear Memory_Base_Limit[ RSE ] */
393 pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, &pcix_mem_base_reg);
394 rse_set = pcix_mem_base_reg & RSE_MASK;
395 if (rse_set) {
396 dbg ("%s W1C: Memory_Base_Limit[ RSE ]\n",__FUNCTION__ );
397
398 pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, rse_set);
399 }
400 /* restore MiscII register */
401 pci_read_config_dword( p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp );
402
403 if (p_slot->ctrl->pcix_misc2_reg & SERRFATALENABLE_MASK)
404 pcix_misc2_temp |= SERRFATALENABLE_MASK;
405 else
406 pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
407
408 if (p_slot->ctrl->pcix_misc2_reg & SERRNONFATALENABLE_MASK)
409 pcix_misc2_temp |= SERRNONFATALENABLE_MASK;
410 else
411 pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
412
413 if (p_slot->ctrl->pcix_misc2_reg & PERRFLOODENABLE_MASK)
414 pcix_misc2_temp |= PERRFLOODENABLE_MASK;
415 else
416 pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
417
418 if (p_slot->ctrl->pcix_misc2_reg & PERRFATALENABLE_MASK)
419 pcix_misc2_temp |= PERRFATALENABLE_MASK;
420 else
421 pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
422
423 if (p_slot->ctrl->pcix_misc2_reg & PERRNONFATALENABLE_MASK)
424 pcix_misc2_temp |= PERRNONFATALENABLE_MASK;
425 else
426 pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
427 pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
428}
429
336#define SLOT_NAME_SIZE 10 430#define SLOT_NAME_SIZE 10
337 431
338static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) 432static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 25ccb0e47593..643252d9bf3b 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -894,7 +894,17 @@ int shpchp_enable_slot (struct slot *p_slot)
894 dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save); 894 dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
895 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 895 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
896 896
897 rc = board_added(p_slot); 897 if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
898 (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
899 && p_slot->ctrl->num_slots == 1) {
900 /* handle amd pogo errata; this must be done before enable */
901 amd_pogo_errata_save_misc_reg(p_slot);
902 rc = board_added(p_slot);
903 /* handle amd pogo errata; this must be done after enable */
904 amd_pogo_errata_restore_misc_reg(p_slot);
905 } else
906 rc = board_added(p_slot);
907
898 if (rc) { 908 if (rc) {
899 p_slot->hpc_ops->get_adapter_status(p_slot, 909 p_slot->hpc_ops->get_adapter_status(p_slot,
900 &(p_slot->presence_save)); 910 &(p_slot->presence_save));