summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2009-05-20 16:31:51 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2009-05-20 16:31:51 +0000
commit7f3e76169ebb97f6e4e00db3115fb336d61e95d8 (patch)
tree841f7753f2b116a9d6a0f277e7d84a46e07d176a
parent82274dabef232f01b6c5f0c13255d02765795abf (diff)
add code to read from OTPROM (1000 and 6000 series only).
-rw-r--r--sys/dev/pci/if_iwn.c67
-rw-r--r--sys/dev/pci/if_iwnreg.h16
-rw-r--r--sys/dev/pci/if_iwnvar.h5
3 files changed, 77 insertions, 11 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c
index 296ca0dd63a..b878f846ac5 100644
--- a/sys/dev/pci/if_iwn.c
+++ b/sys/dev/pci/if_iwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwn.c,v 1.53 2009/05/12 19:10:57 damien Exp $ */
+/* $OpenBSD: if_iwn.c,v 1.54 2009/05/20 16:31:50 damien Exp $ */
/*-
* Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr>
@@ -102,6 +102,7 @@ void iwn_radiotap_attach(struct iwn_softc *);
void iwn_power(int, void *);
int iwn_nic_lock(struct iwn_softc *);
int iwn_eeprom_lock(struct iwn_softc *);
+int iwn_init_otprom(struct iwn_softc *);
int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int);
int iwn_dma_contig_alloc(bus_dma_tag_t, struct iwn_dma_info *,
void **, bus_size_t, bus_size_t);
@@ -783,6 +784,33 @@ iwn_eeprom_unlock(struct iwn_softc *sc)
IWN_CLRBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED);
}
+/*
+ * Initialize access by host to One Time Programmable ROM.
+ * NB: This kind of ROM can be found on 1000 or 6000 Series only.
+ */
+int
+iwn_init_otprom(struct iwn_softc *sc)
+{
+ int error;
+
+ if ((error = iwn_clock_wait(sc)) != 0)
+ return error;
+
+ if ((error = iwn_nic_lock(sc)) != 0)
+ return error;
+ iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ);
+ DELAY(5);
+ iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ);
+ iwn_nic_unlock(sc);
+
+ IWN_CLRBITS(sc, IWN_EEPROM_GP, IWN_EEPROM_GP_IF_OWNER);
+ /* Clear ECC status. */
+ IWN_SETBITS(sc, IWN_OTP_GP,
+ IWN_OTP_GP_ECC_CORR_STTS | IWN_OTP_GP_ECC_UNCORR_STTS);
+
+ return 0;
+}
+
int
iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count)
{
@@ -792,8 +820,6 @@ iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count)
for (; count > 0; count -= 2, addr++) {
IWN_WRITE(sc, IWN_EEPROM, addr << 2);
- IWN_CLRBITS(sc, IWN_EEPROM, IWN_EEPROM_CMD);
-
for (ntries = 0; ntries < 10; ntries++) {
val = IWN_READ(sc, IWN_EEPROM);
if (val & IWN_EEPROM_READ_VALID)
@@ -801,10 +827,24 @@ iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count)
DELAY(5);
}
if (ntries == 10) {
- printf("%s: could not read EEPROM\n",
- sc->sc_dev.dv_xname);
+ printf("%s: timeout reading ROM at 0x%x\n",
+ sc->sc_dev.dv_xname, addr);
return ETIMEDOUT;
}
+ if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) {
+ /* OTPROM, check for ECC errors. */
+ uint32_t tmp = IWN_READ(sc, IWN_OTP_GP);
+ if (tmp & IWN_OTP_GP_ECC_UNCORR_STTS) {
+ printf("%s: OTPROM ECC error at 0x%x\n",
+ sc->sc_dev.dv_xname, addr);
+ return EIO;
+ }
+ if (tmp & IWN_OTP_GP_ECC_CORR_STTS) {
+ /* Correctable ECC error, clear bit. */
+ IWN_SETBITS(sc, IWN_OTP_GP,
+ IWN_OTP_GP_ECC_CORR_STTS);
+ }
+ }
*out++ = val >> 16;
if (count > 1)
*out++ = val >> 24;
@@ -1158,12 +1198,25 @@ iwn_read_eeprom(struct iwn_softc *sc)
uint16_t val;
int error;
+ /* Check whether adapter has an EEPROM or an OTPROM. */
+ if (IWN_READ(sc, IWN_OTP_GP) & IWN_OTP_GP_DEV_SEL_OTP)
+ sc->sc_flags |= IWN_FLAG_HAS_OTPROM;
+ DPRINTF(("%s found\n", (sc->sc_flags & IWN_FLAG_HAS_OTPROM) ?
+ "OTPROM" : "EEPROM"));
+
if ((IWN_READ(sc, IWN_EEPROM_GP) & 0x7) == 0) {
- printf("%s: bad EEPROM signature\n", sc->sc_dev.dv_xname);
+ printf("%s: bad ROM signature\n", sc->sc_dev.dv_xname);
return EIO;
}
if ((error = iwn_eeprom_lock(sc)) != 0) {
- printf("%s: could not lock EEPROM (error=%d)\n",
+ printf("%s: could not lock ROM (error=%d)\n",
+ sc->sc_dev.dv_xname, error);
+ return error;
+ }
+
+ if ((sc->sc_flags & IWN_FLAG_HAS_OTPROM) &&
+ ((error = iwn_init_otprom(sc)) != 0)) {
+ printf("%s: could not initialize OTPROM (error=%d)\n",
sc->sc_dev.dv_xname, error);
return error;
}
diff --git a/sys/dev/pci/if_iwnreg.h b/sys/dev/pci/if_iwnreg.h
index d6ee11d82ab..d9be5efd0a8 100644
--- a/sys/dev/pci/if_iwnreg.h
+++ b/sys/dev/pci/if_iwnreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwnreg.h,v 1.22 2009/03/10 20:39:21 damien Exp $ */
+/* $OpenBSD: if_iwnreg.h,v 1.23 2009/05/20 16:31:50 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -58,6 +58,7 @@
#define IWN_HW_REV 0x028
#define IWN_EEPROM 0x02c
#define IWN_EEPROM_GP 0x030
+#define IWN_OTP_GP 0x034
#define IWN_GIO 0x03c
#define IWN_UCODE_GP1_CLR 0x05c
#define IWN_LED 0x094
@@ -272,6 +273,15 @@
#define IWN_EEPROM_READ_VALID (1 << 0)
#define IWN_EEPROM_CMD (1 << 1)
+/* Possible flags for register IWN_EEPROM_GP. */
+#define IWN_EEPROM_GP_IF_OWNER 0x00000180
+
+/* Possible flags for register IWN_OTP_GP. */
+#define IWN_OTP_GP_DEV_SEL_OTP (1 << 16)
+#define IWN_OTP_GP_RELATIVE_ACCESS (1 << 17)
+#define IWN_OTP_GP_ECC_CORR_STTS (1 << 20)
+#define IWN_OTP_GP_ECC_UNCORR_STTS (1 << 21)
+
/* Possible flags for register IWN_SCHED_QUEUE_STATUS. */
#define IWN4965_TXQ_STATUS_ACTIVE 0x0007fc01
#define IWN4965_TXQ_STATUS_INACTIVE 0x0007fc00
@@ -287,9 +297,11 @@
/* Possible flags for register IWN_APMG_PS. */
#define IWN_APMG_PS_EARLY_PWROFF_DIS (1 << 22)
-#define IWN_APMG_PS_PWR_SRC_MASK (3 << 24)
#define IWN_APMG_PS_PWR_SRC(x) ((x) << 24)
#define IWN_APMG_PS_PWR_SRC_VMAIN 0
+#define IWN_APMG_PS_PWR_SRC_VAUX 2
+#define IWN_APMG_PS_PWR_SRC_MASK IWN_APMG_PS_PWR_SRC(3)
+#define IWN_APMG_PS_RESET_REQ (1 << 26)
/* Possible flags for IWN_APMG_PCI_STT. */
#define IWN_APMG_PCI_STT_L1A_DIS (1 << 11)
diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h
index 827b17ee693..35390eec9e1 100644
--- a/sys/dev/pci/if_iwnvar.h
+++ b/sys/dev/pci/if_iwnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwnvar.h,v 1.10 2009/05/12 19:10:57 damien Exp $ */
+/* $OpenBSD: if_iwnvar.h,v 1.11 2009/05/20 16:31:50 damien Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -203,7 +203,8 @@ struct iwn_softc {
u_int sc_flags;
#define IWN_FLAG_HAS_5GHZ (1 << 0)
-#define IWN_FLAG_FIRST_BOOT (1 << 1)
+#define IWN_FLAG_HAS_OTPROM (1 << 1)
+#define IWN_FLAG_FIRST_BOOT (1 << 2)
uint8_t hw_type;
const struct iwn_hal *sc_hal;