Imported Upstream version 16.07-rc1
[deb_dpdk.git] / drivers / net / cxgbe / cxgbe_ethdev.c
index bb134e5..6c130ed 100644 (file)
@@ -656,7 +656,6 @@ static void cxgbe_dev_stats_get(struct rte_eth_dev *eth_dev,
        /* RX Stats */
        eth_stats->ipackets = ps.rx_frames;
        eth_stats->ibytes   = ps.rx_octets;
-       eth_stats->imcasts  = ps.rx_mcast_frames;
        eth_stats->imissed  = ps.rx_ovflow0 + ps.rx_ovflow1 +
                              ps.rx_ovflow2 + ps.rx_ovflow3 +
                              ps.rx_trunc0 + ps.rx_trunc1 +
@@ -782,6 +781,168 @@ cxgbe_dev_supported_ptypes_get(struct rte_eth_dev *eth_dev)
        return NULL;
 }
 
+static int cxgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+       RTE_SET_USED(dev);
+       return EEPROMSIZE;
+}
+
+/**
+ * eeprom_ptov - translate a physical EEPROM address to virtual
+ * @phys_addr: the physical EEPROM address
+ * @fn: the PCI function number
+ * @sz: size of function-specific area
+ *
+ * Translate a physical EEPROM address to virtual.  The first 1K is
+ * accessed through virtual addresses starting at 31K, the rest is
+ * accessed through virtual addresses starting at 0.
+ *
+ * The mapping is as follows:
+ * [0..1K) -> [31K..32K)
+ * [1K..1K+A) -> [31K-A..31K)
+ * [1K+A..ES) -> [0..ES-A-1K)
+ *
+ * where A = @fn * @sz, and ES = EEPROM size.
+ */
+static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz)
+{
+       fn *= sz;
+       if (phys_addr < 1024)
+               return phys_addr + (31 << 10);
+       if (phys_addr < 1024 + fn)
+               return fn + phys_addr - 1024;
+       if (phys_addr < EEPROMSIZE)
+               return phys_addr - 1024 - fn;
+       if (phys_addr < EEPROMVSIZE)
+               return phys_addr - 1024;
+       return -EINVAL;
+}
+
+/* The next two routines implement eeprom read/write from physical addresses.
+ */
+static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v)
+{
+       int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
+
+       if (vaddr >= 0)
+               vaddr = t4_seeprom_read(adap, vaddr, v);
+       return vaddr < 0 ? vaddr : 0;
+}
+
+static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v)
+{
+       int vaddr = eeprom_ptov(phys_addr, adap->pf, EEPROMPFSIZE);
+
+       if (vaddr >= 0)
+               vaddr = t4_seeprom_write(adap, vaddr, v);
+       return vaddr < 0 ? vaddr : 0;
+}
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+static int cxgbe_get_eeprom(struct rte_eth_dev *dev,
+                           struct rte_dev_eeprom_info *e)
+{
+       struct port_info *pi = (struct port_info *)(dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+       u32 i, err = 0;
+       u8 *buf = rte_zmalloc(NULL, EEPROMSIZE, 0);
+
+       if (!buf)
+               return -ENOMEM;
+
+       e->magic = EEPROM_MAGIC;
+       for (i = e->offset & ~3; !err && i < e->offset + e->length; i += 4)
+               err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]);
+
+       if (!err)
+               rte_memcpy(e->data, buf + e->offset, e->length);
+       rte_free(buf);
+       return err;
+}
+
+static int cxgbe_set_eeprom(struct rte_eth_dev *dev,
+                           struct rte_dev_eeprom_info *eeprom)
+{
+       struct port_info *pi = (struct port_info *)(dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+       u8 *buf;
+       int err = 0;
+       u32 aligned_offset, aligned_len, *p;
+
+       if (eeprom->magic != EEPROM_MAGIC)
+               return -EINVAL;
+
+       aligned_offset = eeprom->offset & ~3;
+       aligned_len = (eeprom->length + (eeprom->offset & 3) + 3) & ~3;
+
+       if (adapter->pf > 0) {
+               u32 start = 1024 + adapter->pf * EEPROMPFSIZE;
+
+               if (aligned_offset < start ||
+                   aligned_offset + aligned_len > start + EEPROMPFSIZE)
+                       return -EPERM;
+       }
+
+       if (aligned_offset != eeprom->offset || aligned_len != eeprom->length) {
+               /* RMW possibly needed for first or last words.
+                */
+               buf = rte_zmalloc(NULL, aligned_len, 0);
+               if (!buf)
+                       return -ENOMEM;
+               err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf);
+               if (!err && aligned_len > 4)
+                       err = eeprom_rd_phys(adapter,
+                                            aligned_offset + aligned_len - 4,
+                                            (u32 *)&buf[aligned_len - 4]);
+               if (err)
+                       goto out;
+               rte_memcpy(buf + (eeprom->offset & 3), eeprom->data,
+                          eeprom->length);
+       } else {
+               buf = eeprom->data;
+       }
+
+       err = t4_seeprom_wp(adapter, false);
+       if (err)
+               goto out;
+
+       for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
+               err = eeprom_wr_phys(adapter, aligned_offset, *p);
+               aligned_offset += 4;
+       }
+
+       if (!err)
+               err = t4_seeprom_wp(adapter, true);
+out:
+       if (buf != eeprom->data)
+               rte_free(buf);
+       return err;
+}
+
+static int cxgbe_get_regs_len(struct rte_eth_dev *eth_dev)
+{
+       struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+
+       return t4_get_regs_len(adapter) / sizeof(uint32_t);
+}
+
+static int cxgbe_get_regs(struct rte_eth_dev *eth_dev,
+                         struct rte_dev_reg_info *regs)
+{
+       struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+
+       regs->length = cxgbe_get_regs_len(eth_dev);
+       regs->version = CHELSIO_CHIP_VERSION(adapter->params.chip) |
+                       (CHELSIO_CHIP_RELEASE(adapter->params.chip) << 10) |
+                       (1 << 16);
+       t4_get_regs(adapter, regs->data, (regs->length * sizeof(uint32_t)));
+
+       return 0;
+}
+
 static const struct eth_dev_ops cxgbe_eth_dev_ops = {
        .dev_start              = cxgbe_dev_start,
        .dev_stop               = cxgbe_dev_stop,
@@ -807,6 +968,11 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
        .stats_reset            = cxgbe_dev_stats_reset,
        .flow_ctrl_get          = cxgbe_flow_ctrl_get,
        .flow_ctrl_set          = cxgbe_flow_ctrl_set,
+       .get_eeprom_length      = cxgbe_get_eeprom_length,
+       .get_eeprom             = cxgbe_get_eeprom,
+       .set_eeprom             = cxgbe_set_eeprom,
+       .get_reg_length         = cxgbe_get_regs_len,
+       .get_reg                = cxgbe_get_regs,
 };
 
 /*