[phantom] Update interrupt support to match current firmware
authorMichael Brown <mcb30@etherboot.org>
Sat, 20 Mar 2010 03:11:03 +0000 (03:11 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 22 Mar 2010 21:59:27 +0000 (21:59 +0000)
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>
src/drivers/net/phantom/phantom.c
src/drivers/net/phantom/phantom.h

index 4c3f22f..41cad18 100644 (file)
@@ -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 */
index 1018a69..a55f32f 100644 (file)
@@ -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 )