#include <linux/pci.h>
#include <linux/module.h>
#include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
#include "net_driver.h"
#include "bitfield.h"
#include "efx.h"
* struct falcon_nic_data - Falcon NIC state
* @next_buffer_table: First available buffer table id
* @pci_dev2: The secondary PCI device if present
+ * @i2c_data: Operations and state for I2C bit-bashing algorithm
*/
struct falcon_nic_data {
unsigned next_buffer_table;
struct pci_dev *pci_dev2;
+ struct i2c_algo_bit_data i2c_data;
};
/**************************************************************************
*
**************************************************************************
*/
-static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+static void falcon_setsda(void *data, int state)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
- falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state);
+ falcon_write(efx, ®, GPIO_CTL_REG_KER);
}
-static int falcon_getsda(struct efx_i2c_interface *i2c)
+static void falcon_setscl(void *data, int state)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state);
+ falcon_write(efx, ®, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(void *data)
+{
+ struct efx_nic *efx = (struct efx_nic *)data;
+ efx_oword_t reg;
+
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
return EFX_OWORD_FIELD(reg, GPIO3_IN);
}
-static int falcon_getscl(struct efx_i2c_interface *i2c)
+static int falcon_getscl(void *data)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
- return EFX_DWORD_FIELD(reg, GPIO0_IN);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ return EFX_OWORD_FIELD(reg, GPIO0_IN);
}
-static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
- .setsda = falcon_setsdascl,
- .setscl = falcon_setsdascl,
+static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
+ .setsda = falcon_setsda,
+ .setscl = falcon_setscl,
.getsda = falcon_getsda,
.getscl = falcon_getscl,
- .udelay = 100,
- .mdelay = 10,
+ .udelay = 5,
+ /* Wait up to 50 ms for slave to let us pull SCL high */
+ .timeout = DIV_ROUND_UP(HZ, 20),
};
/**************************************************************************
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,
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, ®, 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 *)®);
else
set_bit_le(tx_queue->queue, (void *)®);
if (EFX_WORKAROUND_11557(efx)) {
efx_oword_t reg;
- int enabled;
+ bool enabled;
falcon_read_table(efx, ®, efx->type->txd_ptr_tbl_base,
tx_queue->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,
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;
if (EFX_WORKAROUND_11557(efx)) {
efx_oword_t reg;
- int enabled;
+ bool enabled;
falcon_read_table(efx, ®, efx->type->rxd_ptr_tbl_base,
rx_queue->queue);
* 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;
}
}
-/* 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);
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;
#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 ?
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
* 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;
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 */
EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
if (unlikely(!rx_ev_mcast_hash_match))
- discard = 1;
+ discard = true;
}
/* Handle received packet */
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)) {
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)
/* 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);
}
}
/* 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);
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;
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);
}
/* 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, ®, 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, ®, 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, ®, EE_SPI_HADR_REG_KER);
+ }
+
+ /* Program data register, if we have data */
+ if (in != NULL) {
+ memcpy(®, in, len);
+ falcon_write(efx, ®, 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, ®, 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, ®, EE_SPI_HDATA_REG_KER);
- memcpy(data, ®, len);
+ if (out != NULL) {
+ falcon_read(efx, ®, EE_SPI_HDATA_REG_KER);
+ memcpy(out, ®, 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
{
efx_oword_t reg;
int link_speed;
- unsigned int tx_fc;
+ bool tx_fc;
if (efx->link_options & GM_LPA_10000)
link_speed = 0x3;
/* 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, ®, RX_CFG_REG_KER);
EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
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;
* 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;
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 */
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 */
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;
}
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;
int rc;
- /* Initialise I2C interface state */
- efx->i2c.efx = efx;
- efx->i2c.op = &falcon_i2c_bit_operations;
- efx->i2c.sda = 1;
- efx->i2c.scl = 1;
-
/* Allocate storage for hardware specific data */
nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
efx->nic_data = nic_data;
(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)
goto fail5;
+ /* Initialise I2C adapter */
+ efx->i2c_adap.owner = THIS_MODULE;
+ nic_data->i2c_data = falcon_i2c_bit_operations;
+ nic_data->i2c_data.data = efx;
+ efx->i2c_adap.algo_data = &nic_data->i2c_data;
+ efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
+ strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name));
+ rc = i2c_bit_add_bus(&efx->i2c_adap);
+ if (rc)
+ goto fail5;
+
return 0;
fail5:
+ falcon_remove_spi_devices(efx);
falcon_free_buffer(efx, &efx->irq_status);
fail4:
fail3:
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 */
void falcon_remove_nic(struct efx_nic *efx)
{
struct falcon_nic_data *nic_data = efx->nic_data;
+ int rc;
+
+ 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);