summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-10-24 04:49:11 +0200
committerMichael Brown2008-10-28 19:47:44 +0100
commit664f4cf36577c795c43bd998919b73bdf6a8c2f0 (patch)
treef73fa1dac76dd1a0c86c9791d62bf0c2cc1fe6b9
parent[phantom] Add line count limit to phantom_dmesg() (diff)
downloadipxe-664f4cf36577c795c43bd998919b73bdf6a8c2f0.tar.gz
ipxe-664f4cf36577c795c43bd998919b73bdf6a8c2f0.tar.xz
ipxe-664f4cf36577c795c43bd998919b73bdf6a8c2f0.zip
[phantom] Unhalt/halt all PEGs during driver startup/shutdown
A hardware bug means that reads through the expansion ROM BAR can return corrupted data if the PEGs are running. This breaks platforms that re-read the expansion ROM after invoking gPXE code, such as IBM blade servers. Halt PEGs during driver shutdown, and unhalt PEGs during driver startup if we detect that this is not the first startup since power-on.
-rw-r--r--src/drivers/net/phantom/phantom.c45
-rw-r--r--src/drivers/net/phantom/phantom.h25
2 files changed, 70 insertions, 0 deletions
diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c
index f78e4e0e..2f0274c3 100644
--- a/src/drivers/net/phantom/phantom.c
+++ b/src/drivers/net/phantom/phantom.c
@@ -294,6 +294,11 @@ static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom,
{ UNM_CRB_BLK_CAM, 0x416 },
{ UNM_CRB_BLK_ROMUSB, 0x421 },
{ UNM_CRB_BLK_TEST, 0x295 },
+ { UNM_CRB_BLK_PEG_0, 0x340 },
+ { UNM_CRB_BLK_PEG_1, 0x341 },
+ { UNM_CRB_BLK_PEG_2, 0x342 },
+ { UNM_CRB_BLK_PEG_3, 0x343 },
+ { UNM_CRB_BLK_PEG_4, 0x34b },
};
unsigned int block = UNM_CRB_BLK ( reg );
unsigned long offset = UNM_CRB_OFFSET ( reg );
@@ -1688,6 +1693,39 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) {
}
/**
+ * Halt all PEGs
+ *
+ * @v phantom Phantom NIC
+ */
+static void phantom_halt_pegs ( struct phantom_nic *phantom ) {
+ phantom_writel ( phantom, 1, UNM_PEG_0_HALT );
+ phantom_writel ( phantom, 1, UNM_PEG_1_HALT );
+ phantom_writel ( phantom, 1, UNM_PEG_2_HALT );
+ phantom_writel ( phantom, 1, UNM_PEG_3_HALT );
+ phantom_writel ( phantom, 1, UNM_PEG_4_HALT );
+}
+
+/**
+ * Unhalt all PEGs
+ *
+ * @v phantom Phantom NIC
+ */
+static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) {
+ uint32_t halt_status;
+
+ halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS );
+}
+
+/**
* Initialise the Phantom command PEG
*
* @v phantom Phantom NIC
@@ -1709,6 +1747,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
DBGC ( phantom, "Phantom %p command PEG already initialized\n",
phantom );
+ /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may
+ * have halted the PEGs to prevent internal bus
+ * collisions when the BIOS re-reads the expansion ROM.
+ */
+ phantom_unhalt_pegs ( phantom );
return 0;
}
@@ -1942,6 +1985,7 @@ static int phantom_probe ( struct pci_device *pci,
for ( ; i >= 0 ; i-- )
unregister_netdev ( phantom->netdev[i] );
err_init_rcvpeg:
+ phantom_halt_pegs ( phantom );
err_init_cmdpeg:
free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
phantom->dma_buf = NULL;
@@ -1970,6 +2014,7 @@ static void phantom_remove ( struct pci_device *pci ) {
for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- )
unregister_netdev ( phantom->netdev[i] );
+ phantom_halt_pegs ( phantom );
free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
phantom->dma_buf = NULL;
for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) {
diff --git a/src/drivers/net/phantom/phantom.h b/src/drivers/net/phantom/phantom.h
index c43bac83..ad56ad62 100644
--- a/src/drivers/net/phantom/phantom.h
+++ b/src/drivers/net/phantom/phantom.h
@@ -80,6 +80,11 @@ enum unm_reg_blocks {
UNM_CRB_BLK_CAM = 0x22,
UNM_CRB_BLK_ROMUSB = 0x33,
UNM_CRB_BLK_TEST = 0x02,
+ UNM_CRB_BLK_PEG_0 = 0x11,
+ UNM_CRB_BLK_PEG_1 = 0x12,
+ UNM_CRB_BLK_PEG_2 = 0x13,
+ UNM_CRB_BLK_PEG_3 = 0x14,
+ UNM_CRB_BLK_PEG_4 = 0x0f,
};
#define UNM_CRB_BASE(blk) ( (blk) << 20 )
#define UNM_CRB_BLK(reg) ( (reg) >> 20 )
@@ -160,6 +165,26 @@ enum unm_reg_blocks {
#define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 )
#define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac )
+#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 )
+#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 )
+#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c )
+
+#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 )
+#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 )
+#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c )
+
+#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 )
+#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 )
+#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c )
+
+#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 )
+#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 )
+#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c )
+
+#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 )
+#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 )
+#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c )
+
/******************************************************************************
*
* Flash layout