Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[phantom] Update interrupt support to match current firmware
The interrupt control mechanism on Phantom cards has changed
substantially since the driver was initially written.  This updates
the code to match the mechanism used in production firmware.

This is sufficient to allow DOS wget to function successfully using
the 3Com UNDI/NDIS, Intel UNDI/NDIS, and UNDIPD.COM UNDI/PD stacks.

Signed-off-by: Michael Brown <mcb30@etherboot.org>
  • Loading branch information
Michael Brown committed Mar 22, 2010
1 parent 5e829de commit b3533dd
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 23 deletions.
88 changes: 69 additions & 19 deletions src/drivers/net/phantom/phantom.c
Expand Up @@ -45,7 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/

/** Maximum number of ports */
#define PHN_MAX_NUM_PORTS 4
#define PHN_MAX_NUM_PORTS 8

/** Maximum time to wait for command PEG to initialise
*
Expand Down Expand Up @@ -154,6 +154,10 @@ struct phantom_nic {
unsigned long rds_producer_crb;
/** RX status descriptor consumer CRB offset */
unsigned long sds_consumer_crb;
/** RX interrupt mask CRB offset */
unsigned long sds_irq_mask_crb;
/** RX interrupts enabled */
unsigned int sds_irq_enabled;

/** RX producer index */
unsigned int rds_producer_idx;
Expand Down Expand Up @@ -192,6 +196,30 @@ struct phantom_nic {
struct settings settings;
};

/** Interrupt mask registers */
static const unsigned long phantom_irq_mask_reg[PHN_MAX_NUM_PORTS] = {
UNM_PCIE_IRQ_MASK_F0,
UNM_PCIE_IRQ_MASK_F1,
UNM_PCIE_IRQ_MASK_F2,
UNM_PCIE_IRQ_MASK_F3,
UNM_PCIE_IRQ_MASK_F4,
UNM_PCIE_IRQ_MASK_F5,
UNM_PCIE_IRQ_MASK_F6,
UNM_PCIE_IRQ_MASK_F7,
};

/** Interrupt status registers */
static const unsigned long phantom_irq_status_reg[PHN_MAX_NUM_PORTS] = {
UNM_PCIE_IRQ_STATUS_F0,
UNM_PCIE_IRQ_STATUS_F1,
UNM_PCIE_IRQ_STATUS_F2,
UNM_PCIE_IRQ_STATUS_F3,
UNM_PCIE_IRQ_STATUS_F4,
UNM_PCIE_IRQ_STATUS_F5,
UNM_PCIE_IRQ_STATUS_F6,
UNM_PCIE_IRQ_STATUS_F7,
};

/***************************************************************************
*
* CRB register access
Expand Down Expand Up @@ -664,10 +692,13 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
le16_to_cpu ( buf->cardrsp.rx_ctx.context_id );
phantom->rds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ));
le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ) );
phantom->sds_consumer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ));
le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ) );
phantom->sds_irq_mask_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.sds.interrupt_crb ) );

DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys "
"%02x virt %02x)\n", phantom, phantom->rx_context_id,
Expand All @@ -678,6 +709,8 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
phantom, phantom->rds_producer_crb );
DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n",
phantom, phantom->sds_consumer_crb );
DBGC ( phantom, "Phantom %p SDS interrupt mask CRB is %08lx\n",
phantom, phantom->sds_irq_mask_crb );

out:
free_dma ( buf, sizeof ( *buf ) );
Expand Down Expand Up @@ -1263,6 +1296,8 @@ static int phantom_transmit ( struct net_device *netdev,
static void phantom_poll ( struct net_device *netdev ) {
struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int irq_vector;
unsigned int irq_state;
unsigned int cds_consumer_idx;
unsigned int raw_new_cds_consumer_idx;
unsigned int new_cds_consumer_idx;
Expand All @@ -1272,6 +1307,32 @@ static void phantom_poll ( struct net_device *netdev ) {
unsigned int sds_handle;
unsigned int sds_opcode;

/* Occasionally poll the link state */
if ( phantom->link_poll_timer-- == 0 ) {
phantom_poll_link_state ( netdev );
/* Reset the link poll timer */
phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
}

/* Check for interrupts */
if ( phantom->sds_irq_enabled ) {

/* Do nothing unless an interrupt is asserted */
irq_vector = phantom_readl ( phantom, UNM_PCIE_IRQ_VECTOR );
if ( ! ( irq_vector & UNM_PCIE_IRQ_VECTOR_BIT( phantom->port )))
return;

/* Do nothing unless interrupt state machine has stabilised */
irq_state = phantom_readl ( phantom, UNM_PCIE_IRQ_STATE );
if ( ! UNM_PCIE_IRQ_STATE_TRIGGERED ( irq_state ) )
return;

/* Acknowledge interrupt */
phantom_writel ( phantom, UNM_PCIE_IRQ_STATUS_MAGIC,
phantom_irq_status_reg[phantom->port] );
phantom_readl ( phantom, UNM_PCIE_IRQ_VECTOR );
}

/* Check for TX completions */
cds_consumer_idx = phantom->cds_consumer_idx;
raw_new_cds_consumer_idx = phantom->desc->cmd_cons;
Expand Down Expand Up @@ -1361,13 +1422,6 @@ static void phantom_poll ( struct net_device *netdev ) {

/* Refill the RX descriptor ring */
phantom_refill_rx_ring ( netdev );

/* Occasionally poll the link state */
if ( phantom->link_poll_timer-- == 0 ) {
phantom_poll_link_state ( netdev );
/* Reset the link poll timer */
phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
}
}

/**
Expand All @@ -1378,16 +1432,12 @@ static void phantom_poll ( struct net_device *netdev ) {
*/
static void phantom_irq ( struct net_device *netdev, int enable ) {
struct phantom_nic *phantom = netdev_priv ( netdev );
static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = {
UNM_NIC_REG_SW_INT_MASK_0,
UNM_NIC_REG_SW_INT_MASK_1,
UNM_NIC_REG_SW_INT_MASK_2,
UNM_NIC_REG_SW_INT_MASK_3
};

phantom_writel ( phantom,
( enable ? 1 : 0 ),
sw_int_mask_reg[phantom->port] );
phantom_writel ( phantom, ( enable ? 1 : 0 ),
phantom->sds_irq_mask_crb );
phantom_writel ( phantom, UNM_PCIE_IRQ_MASK_MAGIC,
phantom_irq_mask_reg[phantom->port] );
phantom->sds_irq_enabled = enable;
}

/** Phantom net device operations */
Expand Down
26 changes: 22 additions & 4 deletions src/drivers/net/phantom/phantom.h
Expand Up @@ -89,6 +89,28 @@ enum unm_reg_blocks {
#define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE )
#define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 )
#define UNM_PCIE_SEM2_UNLOCK ( UNM_CRB_PCIE + 0x1c014 )
#define UNM_PCIE_IRQ_VECTOR ( UNM_CRB_PCIE + 0x10100 )
#define UNM_PCIE_IRQ_VECTOR_BIT(n) ( 1 << ( (n) + 7 ) )
#define UNM_PCIE_IRQ_STATE ( UNM_CRB_PCIE + 0x1206c )
#define UNM_PCIE_IRQ_STATE_TRIGGERED(state) (( (state) & 0x300 ) == 0x200 )
#define UNM_PCIE_IRQ_MASK_F0 ( UNM_CRB_PCIE + 0x10128 )
#define UNM_PCIE_IRQ_MASK_F1 ( UNM_CRB_PCIE + 0x10170 )
#define UNM_PCIE_IRQ_MASK_F2 ( UNM_CRB_PCIE + 0x10174 )
#define UNM_PCIE_IRQ_MASK_F3 ( UNM_CRB_PCIE + 0x10178 )
#define UNM_PCIE_IRQ_MASK_F4 ( UNM_CRB_PCIE + 0x10370 )
#define UNM_PCIE_IRQ_MASK_F5 ( UNM_CRB_PCIE + 0x10374 )
#define UNM_PCIE_IRQ_MASK_F6 ( UNM_CRB_PCIE + 0x10378 )
#define UNM_PCIE_IRQ_MASK_F7 ( UNM_CRB_PCIE + 0x1037c )
#define UNM_PCIE_IRQ_MASK_MAGIC 0x0000fbffUL
#define UNM_PCIE_IRQ_STATUS_F0 ( UNM_CRB_PCIE + 0x10118 )
#define UNM_PCIE_IRQ_STATUS_F1 ( UNM_CRB_PCIE + 0x10160 )
#define UNM_PCIE_IRQ_STATUS_F2 ( UNM_CRB_PCIE + 0x10164 )
#define UNM_PCIE_IRQ_STATUS_F3 ( UNM_CRB_PCIE + 0x10168 )
#define UNM_PCIE_IRQ_STATUS_F4 ( UNM_CRB_PCIE + 0x10360 )
#define UNM_PCIE_IRQ_STATUS_F5 ( UNM_CRB_PCIE + 0x10364 )
#define UNM_PCIE_IRQ_STATUS_F6 ( UNM_CRB_PCIE + 0x10368 )
#define UNM_PCIE_IRQ_STATUS_F7 ( UNM_CRB_PCIE + 0x1036c )
#define UNM_PCIE_IRQ_STATUS_MAGIC 0xffffffffUL

#define UNM_CRB_CAM UNM_CRB_BASE ( UNM_CRB_BLK_CAM )

Expand Down Expand Up @@ -137,10 +159,6 @@ enum unm_reg_blocks {
#define UNM_NIC_REG_XG_STATE_P3_LINK_DOWN 0x02
#define UNM_NIC_REG_RCVPEG_STATE ( UNM_NIC_REG + 0x0013c )
#define UNM_NIC_REG_RCVPEG_STATE_INITIALIZED 0xff01
#define UNM_NIC_REG_SW_INT_MASK_0 ( UNM_NIC_REG + 0x001d8 )
#define UNM_NIC_REG_SW_INT_MASK_1 ( UNM_NIC_REG + 0x001e0 )
#define UNM_NIC_REG_SW_INT_MASK_2 ( UNM_NIC_REG + 0x001e4 )
#define UNM_NIC_REG_SW_INT_MASK_3 ( UNM_NIC_REG + 0x001e8 )

#define UNM_CRB_ROMUSB UNM_CRB_BASE ( UNM_CRB_BLK_ROMUSB )

Expand Down

0 comments on commit b3533dd

Please sign in to comment.