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 ); @@ -1687,6 +1692,39 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) { return 0; } +/** + * 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 * @@ -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