summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidcs <davidcs@FreeBSD.org>2016-04-12 22:31:48 +0000
committerdavidcs <davidcs@FreeBSD.org>2016-04-12 22:31:48 +0000
commit5e2c24a43d150300de7952faf86b881bec60720a (patch)
treecf7ba5a651f2f2533630c090adb1193f105af753
parentb38b6a219df4fa5f8d62cea220e3b503bcd469ea (diff)
downloadFreeBSD-src-5e2c24a43d150300de7952faf86b881bec60720a.zip
FreeBSD-src-5e2c24a43d150300de7952faf86b881bec60720a.tar.gz
Add support for Flash Update
Submitted by:nrapendra.singh@qlogic.com;vaishali.kulkarni@qlogic.com;davidcs@freebsd.org Approved by:davidcs@freebsd.org MFC after:5 days
-rw-r--r--sys/dev/bxe/bxe.c266
-rw-r--r--sys/dev/bxe/bxe.h23
-rw-r--r--sys/dev/bxe/bxe_ioctl.h116
3 files changed, 400 insertions, 5 deletions
diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c
index 2a26ac8..c9e8188 100644
--- a/sys/dev/bxe/bxe.c
+++ b/sys/dev/bxe/bxe.c
@@ -13653,49 +13653,60 @@ bxe_get_tunable_params(struct bxe_softc *sc)
sc->udp_rss);
}
-static void
+static int
bxe_media_detect(struct bxe_softc *sc)
{
+ int port_type;
uint32_t phy_idx = bxe_get_cur_phy_idx(sc);
+
switch (sc->link_params.phy[phy_idx].media_type) {
case ELINK_ETH_PHY_SFPP_10G_FIBER:
case ELINK_ETH_PHY_XFP_FIBER:
BLOGI(sc, "Found 10Gb Fiber media.\n");
sc->media = IFM_10G_SR;
+ port_type = PORT_FIBRE;
break;
case ELINK_ETH_PHY_SFP_1G_FIBER:
BLOGI(sc, "Found 1Gb Fiber media.\n");
sc->media = IFM_1000_SX;
+ port_type = PORT_FIBRE;
break;
case ELINK_ETH_PHY_KR:
case ELINK_ETH_PHY_CX4:
BLOGI(sc, "Found 10GBase-CX4 media.\n");
sc->media = IFM_10G_CX4;
+ port_type = PORT_FIBRE;
break;
case ELINK_ETH_PHY_DA_TWINAX:
BLOGI(sc, "Found 10Gb Twinax media.\n");
sc->media = IFM_10G_TWINAX;
+ port_type = PORT_DA;
break;
case ELINK_ETH_PHY_BASE_T:
if (sc->link_params.speed_cap_mask[0] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
BLOGI(sc, "Found 10GBase-T media.\n");
sc->media = IFM_10G_T;
+ port_type = PORT_TP;
} else {
BLOGI(sc, "Found 1000Base-T media.\n");
sc->media = IFM_1000_T;
+ port_type = PORT_TP;
}
break;
case ELINK_ETH_PHY_NOT_PRESENT:
BLOGI(sc, "Media not present.\n");
sc->media = 0;
+ port_type = PORT_OTHER;
break;
case ELINK_ETH_PHY_UNSPECIFIED:
default:
BLOGI(sc, "Unknown media!\n");
sc->media = 0;
+ port_type = PORT_OTHER;
break;
}
+ return port_type;
}
#define GET_FIELD(value, fname) \
@@ -18714,6 +18725,14 @@ bxe_add_cdev(struct bxe_softc *sc)
if (sc->grc_dump == NULL)
return (-1);
+ sc->eeprom = malloc(BXE_EEPROM_MAX_DATA_LEN, M_DEVBUF, M_NOWAIT);
+
+ if (sc->eeprom == NULL) {
+ BLOGW(sc, "Unable to alloc for eeprom size buffer\n");
+ free(sc->grc_dump, M_DEVBUF); sc->grc_dump = NULL;
+ return (-1);
+ }
+
sc->ioctl_dev = make_dev(&bxe_cdevsw,
sc->ifp->if_dunit,
UID_ROOT,
@@ -18725,6 +18744,8 @@ bxe_add_cdev(struct bxe_softc *sc)
if (sc->ioctl_dev == NULL) {
free(sc->grc_dump, M_DEVBUF);
+ free(sc->eeprom, M_DEVBUF);
+ sc->eeprom = NULL;
return (-1);
}
@@ -18740,12 +18761,152 @@ bxe_del_cdev(struct bxe_softc *sc)
if (sc->ioctl_dev != NULL)
destroy_dev(sc->ioctl_dev);
- if (sc->grc_dump == NULL)
+ if (sc->grc_dump != NULL)
free(sc->grc_dump, M_DEVBUF);
+ if (sc->eeprom != NULL) {
+ free(sc->eeprom, M_DEVBUF);
+ sc->eeprom = NULL;
+ }
+
return;
}
+static bool bxe_is_nvram_accessible(struct bxe_softc *sc)
+{
+
+ if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static int
+bxe_wr_eeprom(struct bxe_softc *sc, void *data, uint32_t offset, uint32_t len)
+{
+ int rval = 0;
+
+ if(!bxe_is_nvram_accessible(sc)) {
+ BLOGW(sc, "Cannot access eeprom when interface is down\n");
+ return (-EAGAIN);
+ }
+ rval = bxe_nvram_write(sc, offset, (uint8_t *)data, len);
+
+
+ return (rval);
+}
+
+static int
+bxe_rd_eeprom(struct bxe_softc *sc, void *data, uint32_t offset, uint32_t len)
+{
+ int rval = 0;
+
+ if(!bxe_is_nvram_accessible(sc)) {
+ BLOGW(sc, "Cannot access eeprom when interface is down\n");
+ return (-EAGAIN);
+ }
+ rval = bxe_nvram_read(sc, offset, (uint8_t *)data, len);
+
+ return (rval);
+}
+
+static int
+bxe_eeprom_rd_wr(struct bxe_softc *sc, bxe_eeprom_t *eeprom)
+{
+ int rval = 0;
+
+ switch (eeprom->eeprom_cmd) {
+
+ case BXE_EEPROM_CMD_SET_EEPROM:
+
+ rval = copyin(eeprom->eeprom_data, sc->eeprom,
+ eeprom->eeprom_data_len);
+
+ if (rval)
+ break;
+
+ rval = bxe_wr_eeprom(sc, sc->eeprom, eeprom->eeprom_offset,
+ eeprom->eeprom_data_len);
+ break;
+
+ case BXE_EEPROM_CMD_GET_EEPROM:
+
+ rval = bxe_rd_eeprom(sc, sc->eeprom, eeprom->eeprom_offset,
+ eeprom->eeprom_data_len);
+
+ if (rval) {
+ break;
+ }
+
+ rval = copyout(sc->eeprom, eeprom->eeprom_data,
+ eeprom->eeprom_data_len);
+ break;
+
+ default:
+ rval = EINVAL;
+ break;
+ }
+
+ if (rval) {
+ BLOGW(sc, "ioctl cmd %d failed rval %d\n", eeprom->eeprom_cmd, rval);
+ }
+
+ return (rval);
+}
+
+static int
+bxe_get_settings(struct bxe_softc *sc, bxe_dev_setting_t *dev_p)
+{
+ uint32_t ext_phy_config;
+ int port = SC_PORT(sc);
+ int cfg_idx = bxe_get_link_cfg_idx(sc);
+
+ dev_p->supported = sc->port.supported[cfg_idx] |
+ (sc->port.supported[cfg_idx ^ 1] &
+ (ELINK_SUPPORTED_TP | ELINK_SUPPORTED_FIBRE));
+ dev_p->advertising = sc->port.advertising[cfg_idx];
+ if(sc->link_params.phy[bxe_get_cur_phy_idx(sc)].media_type ==
+ ELINK_ETH_PHY_SFP_1G_FIBER) {
+ dev_p->supported = ~(ELINK_SUPPORTED_10000baseT_Full);
+ dev_p->advertising &= ~(ADVERTISED_10000baseT_Full);
+ }
+ if ((sc->state == BXE_STATE_OPEN) && sc->link_vars.link_up &&
+ !(sc->flags & BXE_MF_FUNC_DIS)) {
+ dev_p->duplex = sc->link_vars.duplex;
+ if (IS_MF(sc) && !BXE_NOMCP(sc))
+ dev_p->speed = bxe_get_mf_speed(sc);
+ else
+ dev_p->speed = sc->link_vars.line_speed;
+ } else {
+ dev_p->duplex = DUPLEX_UNKNOWN;
+ dev_p->speed = SPEED_UNKNOWN;
+ }
+
+ dev_p->port = bxe_media_detect(sc);
+
+ ext_phy_config = SHMEM_RD(sc,
+ dev_info.port_hw_config[port].external_phy_config);
+ if((ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+ dev_p->phy_address = sc->port.phy_addr;
+ else if(((ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) !=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+ ((ext_phy_config & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) !=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
+ dev_p->phy_address = ELINK_XGXS_EXT_PHY_ADDR(ext_phy_config);
+ else
+ dev_p->phy_address = 0;
+
+ if(sc->link_params.req_line_speed[cfg_idx] == ELINK_SPEED_AUTO_NEG)
+ dev_p->autoneg = AUTONEG_ENABLE;
+ else
+ dev_p->autoneg = AUTONEG_DISABLE;
+
+
+ return 0;
+}
+
static int
bxe_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
struct thread *td)
@@ -18755,6 +18916,14 @@ bxe_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
device_t pci_dev;
bxe_grcdump_t *dump = NULL;
int grc_dump_size;
+ bxe_drvinfo_t *drv_infop = NULL;
+ bxe_dev_setting_t *dev_p;
+ bxe_dev_setting_t dev_set;
+ bxe_get_regs_t *reg_p;
+ bxe_reg_rdw_t *reg_rdw_p;
+ bxe_pcicfg_rdw_t *cfg_rdw_p;
+ bxe_perm_mac_addr_t *mac_addr_p;
+
if ((sc = (struct bxe_softc *)dev->si_drv1) == NULL)
return ENXIO;
@@ -18767,14 +18936,15 @@ bxe_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
case BXE_GRC_DUMP_SIZE:
dump->pci_func = sc->pcie_func;
- dump->grcdump_size = (bxe_get_total_regs_len32(sc) * sizeof(uint32_t)) +
- sizeof(struct dump_header);
+ dump->grcdump_size =
+ (bxe_get_total_regs_len32(sc) * sizeof(uint32_t)) +
+ sizeof(struct dump_header);
break;
case BXE_GRC_DUMP:
grc_dump_size = (bxe_get_total_regs_len32(sc) * sizeof(uint32_t)) +
- sizeof(struct dump_header);
+ sizeof(struct dump_header);
if ((sc->grc_dump == NULL) || (dump->grcdump == NULL) ||
(dump->grcdump_size < grc_dump_size) || (!sc->grcdump_done)) {
@@ -18787,6 +18957,92 @@ bxe_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
break;
+ case BXE_DRV_INFO:
+ drv_infop = (bxe_drvinfo_t *)data;
+ snprintf(drv_infop->drv_name, BXE_DRV_NAME_LENGTH, "%s", "bxe");
+ snprintf(drv_infop->drv_version, BXE_DRV_VERSION_LENGTH, "v:%s",
+ BXE_DRIVER_VERSION);
+ snprintf(drv_infop->mfw_version, BXE_MFW_VERSION_LENGTH, "%s",
+ sc->devinfo.bc_ver_str);
+ snprintf(drv_infop->stormfw_version, BXE_STORMFW_VERSION_LENGTH,
+ "%s", sc->fw_ver_str);
+ drv_infop->eeprom_dump_len = sc->devinfo.flash_size;
+ drv_infop->reg_dump_len =
+ (bxe_get_total_regs_len32(sc) * sizeof(uint32_t))
+ + sizeof(struct dump_header);
+ snprintf(drv_infop->bus_info, BXE_BUS_INFO_LENGTH, "%d:%d:%d",
+ sc->pcie_bus, sc->pcie_device, sc->pcie_func);
+ break;
+ case BXE_DEV_SETTING:
+ dev_p = (bxe_dev_setting_t *)data;
+ bxe_get_settings(sc, &dev_set);
+ dev_p->supported = dev_set.supported;
+ dev_p->advertising = dev_set.advertising;
+ dev_p->speed = dev_set.speed;
+ dev_p->duplex = dev_set.duplex;
+ dev_p->port = dev_set.port;
+ dev_p->phy_address = dev_set.phy_address;
+ dev_p->autoneg = dev_set.autoneg;
+
+ break;
+
+ case BXE_GET_REGS:
+
+ reg_p = (bxe_get_regs_t *)data;
+ grc_dump_size = reg_p->reg_buf_len;
+
+ if (sc->grc_dump == NULL) {
+ rval = EINVAL;
+ break;
+ }
+
+ if(!sc->grcdump_done) {
+ bxe_grc_dump(sc);
+ }
+ if(sc->grcdump_done) {
+ rval = copyout(sc->grc_dump, reg_p->reg_buf, grc_dump_size);
+ sc->grcdump_done = 0;
+ }
+
+ break;
+ case BXE_RDW_REG:
+ reg_rdw_p = (bxe_reg_rdw_t *)data;
+ if((reg_rdw_p->reg_cmd == BXE_READ_REG_CMD) &&
+ (reg_rdw_p->reg_access_type == BXE_REG_ACCESS_DIRECT))
+ reg_rdw_p->reg_val = REG_RD(sc, reg_rdw_p->reg_id);
+
+ if((reg_rdw_p->reg_cmd == BXE_WRITE_REG_CMD) &&
+ (reg_rdw_p->reg_access_type == BXE_REG_ACCESS_DIRECT))
+ REG_WR(sc, reg_rdw_p->reg_id, reg_rdw_p->reg_val);
+
+ break;
+
+ case BXE_RDW_PCICFG:
+ cfg_rdw_p = (bxe_pcicfg_rdw_t *)data;
+ if(cfg_rdw_p->cfg_cmd == BXE_READ_PCICFG) {
+
+ cfg_rdw_p->cfg_val = pci_read_config(sc->dev, cfg_rdw_p->cfg_id,
+ cfg_rdw_p->cfg_width);
+
+ } else if(cfg_rdw_p->cfg_cmd == BXE_WRITE_PCICFG) {
+ pci_write_config(sc->dev, cfg_rdw_p->cfg_id, cfg_rdw_p->cfg_val,
+ cfg_rdw_p->cfg_width);
+ } else {
+ BLOGW(sc, "BXE_RDW_PCICFG ioctl wrong cmd passed\n");
+ }
+ break;
+
+ case BXE_MAC_ADDR:
+ mac_addr_p = (bxe_perm_mac_addr_t *)data;
+ snprintf(mac_addr_p->mac_addr_str, sizeof(sc->mac_addr_str), "%s",
+ sc->mac_addr_str);
+ break;
+
+ case BXE_EEPROM:
+ rval = bxe_eeprom_rd_wr(sc, (bxe_eeprom_t *)data);
+ break;
+
+
default:
break;
}
diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h
index 73f72ce..e2dbae2 100644
--- a/sys/dev/bxe/bxe.h
+++ b/sys/dev/bxe/bxe.h
@@ -1788,6 +1788,7 @@ struct bxe_softc {
struct cdev *ioctl_dev;
void *grc_dump;
int grcdump_done;
+ void *eeprom;
}; /* struct bxe_softc */
/* IOCTL sub-commands for edebug and firmware upgrade */
@@ -2109,6 +2110,28 @@ static const uint32_t dmae_reg_go_c[] = {
#define PCI_PM_D0 1
#define PCI_PM_D3hot 2
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN (0xff)
+#endif
+
+#ifndef SPEED_UNKNOWN
+#define SPEED_UNKNOWN (-1)
+#endif
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+/* Which connector port. */
+#define PORT_TP 0x00
+#define PORT_AUI 0x01
+#define PORT_MII 0x02
+#define PORT_FIBRE 0x03
+#define PORT_BNC 0x04
+#define PORT_DA 0x05
+#define PORT_NONE 0xef
+#define PORT_OTHER 0xff
+
int bxe_test_bit(int nr, volatile unsigned long * addr);
void bxe_set_bit(unsigned int nr, volatile unsigned long * addr);
void bxe_clear_bit(int nr, volatile unsigned long * addr);
diff --git a/sys/dev/bxe/bxe_ioctl.h b/sys/dev/bxe/bxe_ioctl.h
index 2504982..a0f8478 100644
--- a/sys/dev/bxe/bxe_ioctl.h
+++ b/sys/dev/bxe/bxe_ioctl.h
@@ -42,6 +42,86 @@ struct bxe_grcdump {
};
typedef struct bxe_grcdump bxe_grcdump_t;
+#define BXE_DRV_NAME_LENGTH 32
+#define BXE_DRV_VERSION_LENGTH 32
+#define BXE_MFW_VERSION_LENGTH 32
+#define BXE_STORMFW_VERSION_LENGTH 32
+#define BXE_BUS_INFO_LENGTH 32
+
+struct bxe_drvinfo {
+ char drv_name[BXE_DRV_NAME_LENGTH];
+ char drv_version[BXE_DRV_VERSION_LENGTH];
+ char mfw_version[BXE_MFW_VERSION_LENGTH];
+ char stormfw_version[BXE_STORMFW_VERSION_LENGTH];
+ uint32_t eeprom_dump_len; /* in bytes */
+ uint32_t reg_dump_len; /* in bytes */
+ char bus_info[BXE_BUS_INFO_LENGTH];
+};
+typedef struct bxe_drvinfo bxe_drvinfo_t;
+
+struct bxe_dev_setting {
+
+ uint32_t supported; /* Features this interface supports */
+ uint32_t advertising;/* Features this interface advertises */
+ uint32_t speed; /* The forced speed, 10Mb, 100Mb, gigabit */
+ uint32_t duplex; /* Duplex, half or full */
+ uint32_t port; /* Which connector port */
+ uint32_t phy_address;/* port number*/
+ uint32_t autoneg; /* Enable or disable autonegotiation */
+};
+typedef struct bxe_dev_setting bxe_dev_setting_t;
+
+struct bxe_get_regs {
+ void *reg_buf;
+ uint32_t reg_buf_len;
+};
+typedef struct bxe_get_regs bxe_get_regs_t;
+
+#define BXE_EEPROM_MAX_DATA_LEN 524288
+
+struct bxe_eeprom {
+ uint32_t eeprom_cmd;
+#define BXE_EEPROM_CMD_SET_EEPROM 0x01
+#define BXE_EEPROM_CMD_GET_EEPROM 0x02
+
+ void *eeprom_data;
+ uint32_t eeprom_offset;
+ uint32_t eeprom_data_len;
+ uint32_t eeprom_magic;
+};
+typedef struct bxe_eeprom bxe_eeprom_t;
+
+struct bxe_reg_rdw {
+ uint32_t reg_cmd;
+#define BXE_READ_REG_CMD 0x01
+#define BXE_WRITE_REG_CMD 0x02
+
+ uint32_t reg_id;
+ uint32_t reg_val;
+ uint32_t reg_access_type;
+#define BXE_REG_ACCESS_DIRECT 0x01
+#define BXE_REG_ACCESS_INDIRECT 0x02
+};
+
+typedef struct bxe_reg_rdw bxe_reg_rdw_t;
+
+struct bxe_pcicfg_rdw {
+ uint32_t cfg_cmd;
+#define BXE_READ_PCICFG 0x01
+#define BXE_WRITE_PCICFG 0x01
+ uint32_t cfg_id;
+ uint32_t cfg_val;
+ uint32_t cfg_width;
+};
+
+typedef struct bxe_pcicfg_rdw bxe_pcicfg_rdw_t;
+
+struct bxe_perm_mac_addr {
+ char mac_addr_str[32];
+};
+
+typedef struct bxe_perm_mac_addr bxe_perm_mac_addr_t;
+
/*
* Read grcdump size
@@ -53,5 +133,41 @@ typedef struct bxe_grcdump bxe_grcdump_t;
*/
#define BXE_GRC_DUMP _IOWR('e', 2, bxe_grcdump_t)
+/*
+ * Read driver info
+ */
+#define BXE_DRV_INFO _IOR('e', 3, bxe_drvinfo_t)
+
+/*
+ * Read Device Setting
+ */
+#define BXE_DEV_SETTING _IOR('e', 4, bxe_dev_setting_t)
+
+/*
+ * Get Registers
+ */
+#define BXE_GET_REGS _IOR('e', 5, bxe_get_regs_t)
+
+/*
+ * Get/Set EEPROM
+ */
+#define BXE_EEPROM _IOWR('e', 6, bxe_eeprom_t)
+
+/*
+ * read/write a register
+ */
+#define BXE_RDW_REG _IOWR('e', 7, bxe_reg_rdw_t)
+
+/*
+ * read/write PCIcfg
+ */
+#define BXE_RDW_PCICFG _IOWR('e', 8, bxe_reg_rdw_t)
+
+/*
+ * get permanent mac address
+ */
+
+#define BXE_MAC_ADDR _IOWR('e', 9, bxe_perm_mac_addr_t)
+
#endif /* #ifndef _QLNX_IOCTL_H_ */
OpenPOWER on IntegriCloud