]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/sfc/nic.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / net / sfc / nic.c
index 67cb0c96838caeee1bc0497266ef51dd8e9bb407..da386599ab68d0a42686eaf4c7af2837fa4b04a9 100644 (file)
@@ -362,6 +362,35 @@ static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
                        FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue);
 }
 
+/* Write pointer and first descriptor for TX descriptor ring */
+static inline void efx_push_tx_desc(struct efx_tx_queue *tx_queue,
+                                   const efx_qword_t *txd)
+{
+       unsigned write_ptr;
+       efx_oword_t reg;
+
+       BUILD_BUG_ON(FRF_AZ_TX_DESC_LBN != 0);
+       BUILD_BUG_ON(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0);
+
+       write_ptr = tx_queue->write_count & tx_queue->ptr_mask;
+       EFX_POPULATE_OWORD_2(reg, FRF_AZ_TX_DESC_PUSH_CMD, true,
+                            FRF_AZ_TX_DESC_WPTR, write_ptr);
+       reg.qword[0] = *txd;
+       efx_writeo_page(tx_queue->efx, &reg,
+                       FR_BZ_TX_DESC_UPD_P0, tx_queue->queue);
+}
+
+static inline bool
+efx_may_push_tx_desc(struct efx_tx_queue *tx_queue, unsigned int write_count)
+{
+       unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
+
+       if (empty_read_count == 0)
+               return false;
+
+       tx_queue->empty_read_count = 0;
+       return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0;
+}
 
 /* For each entry inserted into the software descriptor ring, create a
  * descriptor in the hardware TX descriptor ring (in host memory), and
@@ -373,6 +402,7 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
        struct efx_tx_buffer *buffer;
        efx_qword_t *txd;
        unsigned write_ptr;
+       unsigned old_write_count = tx_queue->write_count;
 
        BUG_ON(tx_queue->write_count == tx_queue->insert_count);
 
@@ -391,7 +421,15 @@ void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
        } while (tx_queue->write_count != tx_queue->insert_count);
 
        wmb(); /* Ensure descriptors are written before they are fetched */
-       efx_notify_tx_desc(tx_queue);
+
+       if (efx_may_push_tx_desc(tx_queue, old_write_count)) {
+               txd = efx_tx_desc(tx_queue,
+                                 old_write_count & tx_queue->ptr_mask);
+               efx_push_tx_desc(tx_queue, txd);
+               ++tx_queue->pushes;
+       } else {
+               efx_notify_tx_desc(tx_queue);
+       }
 }
 
 /* Allocate hardware resources for a TX queue */
@@ -894,46 +932,6 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
                          channel->channel, EFX_QWORD_VAL(*event));
 }
 
-/* Global events are basically PHY events */
-static void
-efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
-{
-       struct efx_nic *efx = channel->efx;
-       bool handled = false;
-
-       if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
-           EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
-           EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
-               /* Ignored */
-               handled = true;
-       }
-
-       if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) &&
-           EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
-               efx->xmac_poll_required = true;
-               handled = true;
-       }
-
-       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
-           EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
-           EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
-               netif_err(efx, rx_err, efx->net_dev,
-                         "channel %d seen global RX_RESET event. Resetting.\n",
-                         channel->channel);
-
-               atomic_inc(&efx->rx_reset);
-               efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
-                                  RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
-               handled = true;
-       }
-
-       if (!handled)
-               netif_err(efx, hw, efx->net_dev,
-                         "channel %d unknown global event "
-                         EFX_QWORD_FMT "\n", channel->channel,
-                         EFX_QWORD_VAL(*event));
-}
-
 static void
 efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
 {
@@ -1050,15 +1048,17 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
                case FSE_AZ_EV_CODE_DRV_GEN_EV:
                        efx_handle_generated_event(channel, &event);
                        break;
-               case FSE_AZ_EV_CODE_GLOBAL_EV:
-                       efx_handle_global_event(channel, &event);
-                       break;
                case FSE_AZ_EV_CODE_DRIVER_EV:
                        efx_handle_driver_event(channel, &event);
                        break;
                case FSE_CZ_EV_CODE_MCDI_EV:
                        efx_mcdi_process_event(channel, &event);
                        break;
+               case FSE_AZ_EV_CODE_GLOBAL_EV:
+                       if (efx->type->handle_global_event &&
+                           efx->type->handle_global_event(channel, &event))
+                               break;
+                       /* else fall through */
                default:
                        netif_err(channel->efx, hw, channel->efx->net_dev,
                                  "channel %d unknown event type %d (data "
@@ -1670,7 +1670,7 @@ void efx_nic_init_common(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
-       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 1);
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
        /* Enable SW_EV to inherit in char driver - assume harmless here */
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);