summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/phantom
diff options
context:
space:
mode:
authorMichael Brown2010-03-20 04:11:03 +0100
committerMichael Brown2010-03-22 22:59:27 +0100
commitb3533dd2bb3de6682ebd6c6b523c49fa6c406e92 (patch)
treece580a57bc0ab60fc9d2add89b6a4e9e73666cf6 /src/drivers/net/phantom
parent[igb] Add igb driver (diff)
downloadipxe-b3533dd2bb3de6682ebd6c6b523c49fa6c406e92.tar.gz
ipxe-b3533dd2bb3de6682ebd6c6b523c49fa6c406e92.tar.xz
ipxe-b3533dd2bb3de6682ebd6c6b523c49fa6c406e92.zip
[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>
Diffstat (limited to 'src/drivers/net/phantom')
-rw-r--r--src/drivers/net/phantom/phantom.c88
-rw-r--r--src/drivers/net/phantom/phantom.h26
2 files changed, 91 insertions, 23 deletions
diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c
index 4c3f22f6..41cad188 100644
--- a/src/drivers/net/phantom/phantom.c
+++ b/src/drivers/net/phantom/phantom.c
@@ -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
*
@@ -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;
@@ -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
@@ -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,
@@ -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 ) );
@@ -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;
@@ -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;
@@ -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;
- }
}
/**
@@ -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 */
diff --git a/src/drivers/net/phantom/phantom.h b/src/drivers/net/phantom/phantom.h
index 1018a690..a55f32fb 100644
--- a/src/drivers/net/phantom/phantom.h
+++ b/src/drivers/net/phantom/phantom.h
@@ -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 )
@@ -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 )