]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/sfc/falcon.c
sfc: Remove efx_channel::has_interrupt
[linux-2.6-omap-h63xx.git] / drivers / net / sfc / falcon.c
index 9138ee5b7b7bdc628fc782886b4ac0dbf4c951c4..40dd643e930df37392dc186c3cf4a7328e5b9020 100644 (file)
@@ -474,9 +474,9 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue)
                              TX_NON_IP_DROP_DIS_B0, 1);
 
        if (falcon_rev(efx) >= FALCON_REV_B0) {
-               int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
-               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
-               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+               int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
+               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, !csum);
+               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, !csum);
        }
 
        falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
@@ -485,10 +485,11 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue)
        if (falcon_rev(efx) < FALCON_REV_B0) {
                efx_oword_t reg;
 
-               BUG_ON(tx_queue->queue >= 128); /* HW limit */
+               /* Only 128 bits in this register */
+               BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
 
                falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
-               if (efx->net_dev->features & NETIF_F_IP_CSUM)
+               if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
                        clear_bit_le(tx_queue->queue, (void *)&reg);
                else
                        set_bit_le(tx_queue->queue, (void *)&reg);
@@ -538,7 +539,7 @@ static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
 
        if (EFX_WORKAROUND_11557(efx)) {
                efx_oword_t reg;
-               int enabled;
+               bool enabled;
 
                falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
                                  tx_queue->queue);
@@ -643,8 +644,8 @@ int falcon_init_rx(struct efx_rx_queue *rx_queue)
        efx_oword_t rx_desc_ptr;
        struct efx_nic *efx = rx_queue->efx;
        int rc;
-       int is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
-       int iscsi_digest_en = is_b0;
+       bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
+       bool iscsi_digest_en = is_b0;
 
        EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
                rx_queue->queue, rx_queue->rxd.index,
@@ -694,7 +695,8 @@ static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
        read_ptr = channel->eventq_read_ptr;
        for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
                efx_qword_t *event = falcon_event(channel, read_ptr);
-               int ev_code, ev_sub_code, ev_queue, ev_failed;
+               int ev_code, ev_sub_code, ev_queue;
+               bool ev_failed;
                if (!falcon_event_present(event))
                        break;
 
@@ -721,7 +723,7 @@ static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
 
        if (EFX_WORKAROUND_11557(efx)) {
                efx_oword_t reg;
-               int enabled;
+               bool enabled;
 
                falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
                                  rx_queue->queue);
@@ -813,8 +815,8 @@ void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
  * Falcon batches TX completion events; the message we receive is of
  * the form "complete all TX events up to this index".
  */
-static inline void falcon_handle_tx_event(struct efx_channel *channel,
-                                         efx_qword_t *event)
+static void falcon_handle_tx_event(struct efx_channel *channel,
+                                  efx_qword_t *event)
 {
        unsigned int tx_ev_desc_ptr;
        unsigned int tx_ev_q_label;
@@ -847,39 +849,19 @@ static inline void falcon_handle_tx_event(struct efx_channel *channel,
        }
 }
 
-/* Check received packet's destination MAC address. */
-static int check_dest_mac(struct efx_rx_queue *rx_queue,
-                         const efx_qword_t *event)
-{
-       struct efx_rx_buffer *rx_buf;
-       struct efx_nic *efx = rx_queue->efx;
-       int rx_ev_desc_ptr;
-       struct ethhdr *eh;
-
-       if (efx->promiscuous)
-               return 1;
-
-       rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
-       rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
-       eh = (struct ethhdr *)rx_buf->data;
-       if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
-               return 0;
-       return 1;
-}
-
 /* Detect errors included in the rx_evt_pkt_ok bit. */
 static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
                                    const efx_qword_t *event,
-                                   unsigned *rx_ev_pkt_ok,
-                                   int *discard, int byte_count)
+                                   bool *rx_ev_pkt_ok,
+                                   bool *discard)
 {
        struct efx_nic *efx = rx_queue->efx;
-       unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
-       unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
-       unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
-       unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
-       unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
-       int snap, non_ip;
+       bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+       bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+       bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+       bool rx_ev_other_err, rx_ev_pause_frm;
+       bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+       unsigned rx_ev_pkt_type;
 
        rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
        rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
@@ -903,41 +885,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
                           rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
                           rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
 
-       snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
-               (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
-       non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
-
-       /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
-        * length field of an LLC frame, which sets TOBE_DISC. We could set
-        * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
-        * protect the RX block).
-        *
-        * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
-        * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
-        *                       LLC can't encapsulate IP, so by definition
-        *                       these packets are NON_IP.
-        *
-        * Unicast mismatch will also cause TOBE_DISC, so the driver needs
-        * to check this.
-        */
-       if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
-               /* If all the other flags are zero then we can state the
-                * entire packet is ok, which will flag to the kernel not
-                * to recalculate checksums.
-                */
-               if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
-                       *rx_ev_pkt_ok = 1;
-
-               rx_ev_tobe_disc = 0;
-
-               /* TOBE_DISC is set for unicast mismatch.  But given that
-                * we can't trust TOBE_DISC here, we must validate the dest
-                * MAC address ourselves.
-                */
-               if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
-                       rx_ev_tobe_disc = 1;
-       }
-
        /* Count errors that are not in MAC stats. */
        if (rx_ev_frm_trunc)
                ++rx_queue->channel->n_rx_frm_trunc;
@@ -961,7 +908,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
 #ifdef EFX_ENABLE_DEBUG
        if (rx_ev_other_err) {
                EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
-                           EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
+                           EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n",
                            rx_queue->queue, EFX_QWORD_VAL(*event),
                            rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
                            rx_ev_ip_hdr_chksum_err ?
@@ -972,8 +919,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
                            rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
                            rx_ev_drib_nib ? " [DRIB_NIB]" : "",
                            rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
-                           rx_ev_pause_frm ? " [PAUSE]" : "",
-                           snap ? " [SNAP/LLC]" : "");
+                           rx_ev_pause_frm ? " [PAUSE]" : "");
        }
 #endif
 
@@ -1006,13 +952,13 @@ static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
  * Also "is multicast" and "matches multicast filter" flags can be used to
  * discard non-matching multicast packets.
  */
-static inline int falcon_handle_rx_event(struct efx_channel *channel,
-                                        const efx_qword_t *event)
+static int falcon_handle_rx_event(struct efx_channel *channel,
+                                 const efx_qword_t *event)
 {
        unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
-       unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
+       unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt;
        unsigned expected_ptr;
-       int discard = 0, checksummed;
+       bool rx_ev_pkt_ok, discard = false, checksummed;
        struct efx_rx_queue *rx_queue;
        struct efx_nic *efx = channel->efx;
 
@@ -1040,8 +986,8 @@ static inline int falcon_handle_rx_event(struct efx_channel *channel,
                checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
        } else {
                falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
-                                       &discard, rx_ev_byte_cnt);
-               checksummed = 0;
+                                       &discard);
+               checksummed = false;
        }
 
        /* Detect multicast packets that didn't match the filter */
@@ -1051,7 +997,7 @@ static inline int falcon_handle_rx_event(struct efx_channel *channel,
                        EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
 
                if (unlikely(!rx_ev_mcast_hash_match))
-                       discard = 1;
+                       discard = true;
        }
 
        /* Handle received packet */
@@ -1066,23 +1012,23 @@ static void falcon_handle_global_event(struct efx_channel *channel,
                                       efx_qword_t *event)
 {
        struct efx_nic *efx = channel->efx;
-       int is_phy_event = 0, handled = 0;
+       bool is_phy_event = false, handled = false;
 
        /* Check for interrupt on either port.  Some boards have a
         * single PHY wired to the interrupt line for port 1. */
        if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
            EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
            EFX_QWORD_FIELD(*event, XG_PHY_INTR))
-               is_phy_event = 1;
+               is_phy_event = true;
 
        if ((falcon_rev(efx) >= FALCON_REV_B0) &&
            EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
-               is_phy_event = 1;
+               is_phy_event = true;
 
        if (is_phy_event) {
                efx->phy_op->clear_interrupt(efx);
                queue_work(efx->workqueue, &efx->reconfigure_work);
-               handled = 1;
+               handled = true;
        }
 
        if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
@@ -1092,7 +1038,7 @@ static void falcon_handle_global_event(struct efx_channel *channel,
                atomic_inc(&efx->rx_reset);
                efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
                                   RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
-               handled = 1;
+               handled = true;
        }
 
        if (!handled)
@@ -1371,7 +1317,7 @@ void falcon_enable_interrupts(struct efx_nic *efx)
 
        /* Force processing of all the channels to get the EVQ RPTRs up to
           date */
-       efx_for_each_channel_with_interrupt(channel, efx)
+       efx_for_each_channel(channel, efx)
                efx_schedule_channel(channel);
 }
 
@@ -1621,7 +1567,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
        }
 
        /* Hook MSI or MSI-X interrupt */
-       efx_for_each_channel_with_interrupt(channel, efx) {
+       efx_for_each_channel(channel, efx) {
                rc = request_irq(channel->irq, falcon_msi_interrupt,
                                 IRQF_PROBE_SHARED, /* Not shared */
                                 efx->name, channel);
@@ -1634,7 +1580,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
        return 0;
 
  fail2:
-       efx_for_each_channel_with_interrupt(channel, efx)
+       efx_for_each_channel(channel, efx)
                free_irq(channel->irq, channel);
  fail1:
        return rc;
@@ -1646,7 +1592,7 @@ void falcon_fini_interrupt(struct efx_nic *efx)
        efx_oword_t reg;
 
        /* Disable MSI/MSI-X interrupts */
-       efx_for_each_channel_with_interrupt(channel, efx) {
+       efx_for_each_channel(channel, efx) {
                if (channel->irq)
                        free_irq(channel->irq, channel);
        }
@@ -1674,64 +1620,195 @@ void falcon_fini_interrupt(struct efx_nic *efx)
 /* Wait for SPI command completion */
 static int falcon_spi_wait(struct efx_nic *efx)
 {
+       unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10);
        efx_oword_t reg;
-       int cmd_en, timer_active;
-       int count;
+       bool cmd_en, timer_active;
 
-       count = 0;
-       do {
+       for (;;) {
                falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
                cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
                timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
                if (!cmd_en && !timer_active)
                        return 0;
-               udelay(10);
-       } while (++count < 10000); /* wait upto 100msec */
-       EFX_ERR(efx, "timed out waiting for SPI\n");
-       return -ETIMEDOUT;
+               if (time_after_eq(jiffies, timeout)) {
+                       EFX_ERR(efx, "timed out waiting for SPI\n");
+                       return -ETIMEDOUT;
+               }
+               cpu_relax();
+       }
 }
 
-static int
-falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command,
-               unsigned int address, unsigned int addr_len,
-               void *data, unsigned int len)
+static int falcon_spi_cmd(const struct efx_spi_device *spi,
+                         unsigned int command, int address,
+                         const void *in, void *out, unsigned int len)
 {
+       struct efx_nic *efx = spi->efx;
+       bool addressed = (address >= 0);
+       bool reading = (out != NULL);
        efx_oword_t reg;
        int rc;
 
-       BUG_ON(len > FALCON_SPI_MAX_LEN);
+       /* Input validation */
+       if (len > FALCON_SPI_MAX_LEN)
+               return -EINVAL;
 
        /* Check SPI not currently being accessed */
        rc = falcon_spi_wait(efx);
        if (rc)
                return rc;
 
-       /* Program address register */
-       EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
-       falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+       /* Program address register, if we have an address */
+       if (addressed) {
+               EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
+               falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
+       }
+
+       /* Program data register, if we have data */
+       if (in != NULL) {
+               memcpy(&reg, in, len);
+               falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
+       }
 
-       /* Issue read command */
+       /* Issue read/write command */
        EFX_POPULATE_OWORD_7(reg,
                             EE_SPI_HCMD_CMD_EN, 1,
-                            EE_SPI_HCMD_SF_SEL, device_id,
+                            EE_SPI_HCMD_SF_SEL, spi->device_id,
                             EE_SPI_HCMD_DABCNT, len,
-                            EE_SPI_HCMD_READ, EE_SPI_READ,
+                            EE_SPI_HCMD_READ, reading,
                             EE_SPI_HCMD_DUBCNT, 0,
-                            EE_SPI_HCMD_ADBCNT, addr_len,
+                            EE_SPI_HCMD_ADBCNT,
+                            (addressed ? spi->addr_len : 0),
                             EE_SPI_HCMD_ENC, command);
        falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
 
-       /* Wait for read to complete */
+       /* Wait for read/write to complete */
        rc = falcon_spi_wait(efx);
        if (rc)
                return rc;
 
        /* Read data */
-       falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
-       memcpy(data, &reg, len);
+       if (out != NULL) {
+               falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
+               memcpy(out, &reg, len);
+       }
+
        return 0;
 }
 
+static unsigned int
+falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
+{
+       return min(FALCON_SPI_MAX_LEN,
+                  (spi->block_size - (start & (spi->block_size - 1))));
+}
+
+static inline u8
+efx_spi_munge_command(const struct efx_spi_device *spi,
+                     const u8 command, const unsigned int address)
+{
+       return command | (((address >> 8) & spi->munge_address) << 3);
+}
+
+
+static int falcon_spi_fast_wait(const struct efx_spi_device *spi)
+{
+       u8 status;
+       int i, rc;
+
+       /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
+       for (i = 0; i < 50; i++) {
+               udelay(20);
+
+               rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL,
+                                   &status, sizeof(status));
+               if (rc)
+                       return rc;
+               if (!(status & SPI_STATUS_NRDY))
+                       return 0;
+       }
+       EFX_ERR(spi->efx,
+               "timed out waiting for device %d last status=0x%02x\n",
+               spi->device_id, status);
+       return -ETIMEDOUT;
+}
+
+int falcon_spi_read(const struct efx_spi_device *spi, loff_t start,
+                   size_t len, size_t *retlen, u8 *buffer)
+{
+       unsigned int command, block_len, pos = 0;
+       int rc = 0;
+
+       while (pos < len) {
+               block_len = min((unsigned int)len - pos,
+                               FALCON_SPI_MAX_LEN);
+
+               command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+               rc = falcon_spi_cmd(spi, command, start + pos, NULL,
+                                   buffer + pos, block_len);
+               if (rc)
+                       break;
+               pos += block_len;
+
+               /* Avoid locking up the system */
+               cond_resched();
+               if (signal_pending(current)) {
+                       rc = -EINTR;
+                       break;
+               }
+       }
+
+       if (retlen)
+               *retlen = pos;
+       return rc;
+}
+
+int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
+                    size_t len, size_t *retlen, const u8 *buffer)
+{
+       u8 verify_buffer[FALCON_SPI_MAX_LEN];
+       unsigned int command, block_len, pos = 0;
+       int rc = 0;
+
+       while (pos < len) {
+               rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0);
+               if (rc)
+                       break;
+
+               block_len = min((unsigned int)len - pos,
+                               falcon_spi_write_limit(spi, start + pos));
+               command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
+               rc = falcon_spi_cmd(spi, command, start + pos,
+                                   buffer + pos, NULL, block_len);
+               if (rc)
+                       break;
+
+               rc = falcon_spi_fast_wait(spi);
+               if (rc)
+                       break;
+
+               command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+               rc = falcon_spi_cmd(spi, command, start + pos,
+                                   NULL, verify_buffer, block_len);
+               if (memcmp(verify_buffer, buffer + pos, block_len)) {
+                       rc = -EIO;
+                       break;
+               }
+
+               pos += block_len;
+
+               /* Avoid locking up the system */
+               cond_resched();
+               if (signal_pending(current)) {
+                       rc = -EINTR;
+                       break;
+               }
+       }
+
+       if (retlen)
+               *retlen = pos;
+       return rc;
+}
+
 /**************************************************************************
  *
  * MAC wrapper
@@ -1812,7 +1889,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 {
        efx_oword_t reg;
        int link_speed;
-       unsigned int tx_fc;
+       bool tx_fc;
 
        if (efx->link_options & GM_LPA_10000)
                link_speed = 0x3;
@@ -1847,7 +1924,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
        /* Transmission of pause frames when RX crosses the threshold is
         * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
         * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
-       tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+       tx_fc = !!(efx->flow_control & EFX_FC_TX);
        falcon_read(efx, &reg, RX_CFG_REG_KER);
        EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
 
@@ -1951,7 +2028,7 @@ static int falcon_gmii_wait(struct efx_nic *efx)
 static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
                              int addr, int value)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
        efx_oword_t reg;
 
@@ -2019,7 +2096,7 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
  * could be read, -1 will be returned. */
 static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
        efx_oword_t reg;
        int value = -1;
@@ -2120,7 +2197,7 @@ int falcon_probe_port(struct efx_nic *efx)
                return rc;
 
        /* Set up GMII structure for PHY */
-       efx->mii.supports_gmii = 1;
+       efx->mii.supports_gmii = true;
        falcon_init_mdio(&efx->mii);
 
        /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
@@ -2305,40 +2382,66 @@ static int falcon_reset_sram(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
+static int falcon_spi_device_init(struct efx_nic *efx,
+                                 struct efx_spi_device **spi_device_ret,
+                                 unsigned int device_id, u32 device_type)
+{
+       struct efx_spi_device *spi_device;
+
+       if (device_type != 0) {
+               spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
+               if (!spi_device)
+                       return -ENOMEM;
+               spi_device->device_id = device_id;
+               spi_device->size =
+                       1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
+               spi_device->addr_len =
+                       SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
+               spi_device->munge_address = (spi_device->size == 1 << 9 &&
+                                            spi_device->addr_len == 1);
+               spi_device->block_size =
+                       1 << SPI_DEV_TYPE_FIELD(device_type,
+                                               SPI_DEV_TYPE_BLOCK_SIZE);
+
+               spi_device->efx = efx;
+       } else {
+               spi_device = NULL;
+       }
+
+       kfree(*spi_device_ret);
+       *spi_device_ret = spi_device;
+       return 0;
+}
+
+
+static void falcon_remove_spi_devices(struct efx_nic *efx)
+{
+       kfree(efx->spi_eeprom);
+       efx->spi_eeprom = NULL;
+       kfree(efx->spi_flash);
+       efx->spi_flash = NULL;
+}
+
 /* Extract non-volatile configuration */
 static int falcon_probe_nvconfig(struct efx_nic *efx)
 {
        struct falcon_nvconfig *nvconfig;
-       efx_oword_t nic_stat;
-       int device_id;
-       unsigned addr_len;
-       size_t offset, len;
+       struct efx_spi_device *spi;
        int magic_num, struct_ver, board_rev;
        int rc;
 
-       /* Find the boot device. */
-       falcon_read(efx, &nic_stat, NIC_STAT_REG);
-       if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
-               device_id = EE_SPI_FLASH;
-               addr_len = 3;
-       } else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
-               device_id = EE_SPI_EEPROM;
-               addr_len = 2;
-       } else {
-               return -ENODEV;
-       }
-
        nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+       if (!nvconfig)
+               return -ENOMEM;
 
        /* Read the whole configuration structure into memory. */
-       for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
-               len = min(sizeof(*nvconfig) - offset,
-                         (size_t) FALCON_SPI_MAX_LEN);
-               rc = falcon_spi_read(efx, device_id, SPI_READ,
-                                    NVCONFIG_BASE + offset, addr_len,
-                                    (char *)nvconfig + offset, len);
-               if (rc)
-                       goto out;
+       spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
+       rc = falcon_spi_read(spi, NVCONFIG_BASE, sizeof(*nvconfig),
+                            NULL, (char *)nvconfig);
+       if (rc) {
+               EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" :
+                       "EEPROM");
+               goto fail1;
        }
 
        /* Read the MAC addresses */
@@ -2356,17 +2459,38 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
                board_rev = 0;
        } else {
                struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
+               struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
 
                efx->phy_type = v2->port0_phy_type;
                efx->mii.phy_id = v2->port0_phy_addr;
                board_rev = le16_to_cpu(v2->board_revision);
+
+               if (struct_ver >= 3) {
+                       __le32 fl = v3->spi_device_type[EE_SPI_FLASH];
+                       __le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
+                       rc = falcon_spi_device_init(efx, &efx->spi_flash,
+                                                   EE_SPI_FLASH,
+                                                   le32_to_cpu(fl));
+                       if (rc)
+                               goto fail2;
+                       rc = falcon_spi_device_init(efx, &efx->spi_eeprom,
+                                                   EE_SPI_EEPROM,
+                                                   le32_to_cpu(ee));
+                       if (rc)
+                               goto fail2;
+               }
        }
 
        EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
 
        efx_set_board_info(efx, board_rev);
 
- out:
+       kfree(nvconfig);
+       return 0;
+
+ fail2:
+       falcon_remove_spi_devices(efx);
+ fail1:
        kfree(nvconfig);
        return rc;
 }
@@ -2417,6 +2541,86 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
        return 0;
 }
 
+/* Probe all SPI devices on the NIC */
+static void falcon_probe_spi_devices(struct efx_nic *efx)
+{
+       efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+       bool has_flash, has_eeprom, boot_is_external;
+
+       falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
+       falcon_read(efx, &nic_stat, NIC_STAT_REG);
+       falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+
+       has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
+       has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
+       boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
+
+       if (has_flash) {
+               /* Default flash SPI device: Atmel AT25F1024
+                * 128 KB, 24-bit address, 32 KB erase block,
+                * 256 B write block
+                */
+               u32 flash_device_type =
+                       (17 << SPI_DEV_TYPE_SIZE_LBN)
+                       | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                       | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
+                       | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
+                       | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+
+               falcon_spi_device_init(efx, &efx->spi_flash,
+                                      EE_SPI_FLASH, flash_device_type);
+
+               if (!boot_is_external) {
+                       /* Disable VPD and set clock dividers to safe
+                        * values for initial programming.
+                        */
+                       EFX_LOG(efx, "Booted from internal ASIC settings;"
+                               " setting SPI config\n");
+                       EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
+                                            /* 125 MHz / 7 ~= 20 MHz */
+                                            EE_SF_CLOCK_DIV, 7,
+                                            /* 125 MHz / 63 ~= 2 MHz */
+                                            EE_EE_CLOCK_DIV, 63);
+                       falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
+               }
+       }
+
+       if (has_eeprom) {
+               u32 eeprom_device_type;
+
+               /* If it has no flash, it must have a large EEPROM
+                * for chip config; otherwise check whether 9-bit
+                * addressing is used for VPD configuration
+                */
+               if (has_flash &&
+                   (!boot_is_external ||
+                    EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) {
+                       /* Default SPI device: Atmel AT25040 or similar
+                        * 512 B, 9-bit address, 8 B write block
+                        */
+                       eeprom_device_type =
+                               (9 << SPI_DEV_TYPE_SIZE_LBN)
+                               | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                               | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+               } else {
+                       /* "Large" SPI device: Atmel AT25640 or similar
+                        * 8 KB, 16-bit address, 32 B write block
+                        */
+                       eeprom_device_type =
+                               (13 << SPI_DEV_TYPE_SIZE_LBN)
+                               | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                               | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
+               }
+
+               falcon_spi_device_init(efx, &efx->spi_eeprom,
+                                      EE_SPI_EEPROM, eeprom_device_type);
+       }
+
+       EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
+               (has_flash ? "present" : "absent"),
+               (has_eeprom ? "present" : "absent"));
+}
+
 int falcon_probe_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data;
@@ -2467,6 +2671,8 @@ int falcon_probe_nic(struct efx_nic *efx)
                (unsigned long long)efx->irq_status.dma_addr,
                efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
 
+       falcon_probe_spi_devices(efx);
+
        /* Read in the non-volatile configuration */
        rc = falcon_probe_nvconfig(efx);
        if (rc)
@@ -2486,6 +2692,7 @@ int falcon_probe_nic(struct efx_nic *efx)
        return 0;
 
  fail5:
+       falcon_remove_spi_devices(efx);
        falcon_free_buffer(efx, &efx->irq_status);
  fail4:
  fail3:
@@ -2641,8 +2848,8 @@ int falcon_init_nic(struct efx_nic *efx)
                  rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
        EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
        /* RX control FIFO thresholds [32 entries] */
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
+       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 20);
+       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 25);
        falcon_write(efx, &temp, RX_CFG_REG_KER);
 
        /* Set destination of both TX and RX Flush events */
@@ -2662,6 +2869,7 @@ void falcon_remove_nic(struct efx_nic *efx)
        rc = i2c_del_adapter(&efx->i2c_adap);
        BUG_ON(rc);
 
+       falcon_remove_spi_devices(efx);
        falcon_free_buffer(efx, &efx->irq_status);
 
        falcon_reset_hw(efx, RESET_TYPE_ALL);