> Date: Sun, 09 Feb 2014 10:34:04 +0100
> From: Benoit Lecocq <[email protected]>
>
> On 02/08/14 23:34, Mark Kettenis wrote:
> >>
> >> Hi tech@,
> >>
> >> the diff below adds support for the Intel Centrino Wireless-N 2230
> >> card found in my Lenovo E330 to iwn(4).
> >>
> >> iwn0 at pci2 dev 0 function 0 "Intel Centrino Wireless-N 2230" rev 0xc4:
> >> msi, MIMO 2T2R, BGN, address 60:6c:66:3b:ea:39
> >>
> >> This is the 0x0888 version.
> >>
> >> I've got most changes from
> >> https://github.com/seanbruno/freebsd-iwl/commit/53e6056c2df7355650abab77068943ac097a70c6#diff-7a5322b995ac8545b4f5d9096c3b5a5aR5445
> >>
> >> which (i think) mostly landed in freebsd as part of
> >> http://svnweb.freebsd.org/base?view=revision&revision=258035
> >>
> >> This is the only iwn(4) device i have, so hopefully i did not broke
> >> another supported device.
> >> Any feedback and tests are welcome.
> >>
> >> Regards,
> >> Fabian Raetz
> >
> > Hi Fabian,
> >
> > Finally had some time to look at this. I cleaned your diff up a bit.
> > Also noticed that the sensitivy limits didn't match the Linux driver I
> > was looking at. Does the diff below still result in working hardware
> > for you?
> >
> > Thanks,
> >
> > Mark
> >
> >
>
> Hi,
>
> With your patch the network card is detected :
>
> iwn0 at pci3 dev 0 function 0 "Intel Centrino Wireless-N 2030" rev 0xc4:
> msi, MIMO 2T2R, BGN, address 68:5d:43:20:8b:68
>
> But I have the following message :
>
> iwn0: fatal firmware error
> firmware error log:
> error type = "UNKNOWN" (0x00001038)
> program counter = 0x0002A698
> source line = 0x00001014
> error data = 0x0000000000001014
> branch link = 0x0002A5B40002A5B4
> interrupt link = 0x0000EC7A00000000
> time = 969333536
> driver status:
> tx ring 0: qid=0 cur=6 queued=0
> tx ring 1: qid=1 cur=0 queued=0
> tx ring 2: qid=2 cur=0 queued=0
> tx ring 3: qid=3 cur=0 queued=0
> tx ring 4: qid=4 cur=36 queued=0
> tx ring 5: qid=5 cur=0 queued=0
> tx ring 6: qid=6 cur=0 queued=0
> tx ring 7: qid=7 cur=0 queued=0
> tx ring 8: qid=8 cur=0 queued=0
> tx ring 9: qid=9 cur=0 queued=0
> tx ring 10: qid=10 cur=0 queued=0
> tx ring 11: qid=11 cur=0 queued=0
> tx ring 12: qid=12 cur=0 queued=0
> tx ring 13: qid=13 cur=0 queued=0
> tx ring 14: qid=14 cur=0 queued=0
> tx ring 15: qid=15 cur=0 queued=0
> tx ring 16: qid=16 cur=0 queued=0
> tx ring 17: qid=17 cur=0 queued=0
> tx ring 18: qid=18 cur=0 queued=0
> tx ring 19: qid=19 cur=0 queued=0
> rx ring: cur=22
> 802.11 state 4
>
> I have not the same issue with the patch from Fabian.
Does the interface work despite this message?
Does the following diff work better?
Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.127
diff -u -p -r1.127 if_iwn.c
--- if_iwn.c 6 Dec 2013 21:03:04 -0000 1.127
+++ if_iwn.c 9 Feb 2014 11:18:29 -0000
@@ -94,6 +94,8 @@ static const struct pci_matchid iwn_devi
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_2 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_1 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_2 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2030_1 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2030_2 },
};
int iwn_match(struct device *, void *, void *);
@@ -244,6 +246,7 @@ int iwn5000_send_calibration(struct iwn
int iwn5000_send_wimax_coex(struct iwn_softc *);
int iwn5000_crystal_calib(struct iwn_softc *);
int iwn5000_temp_offset_calib(struct iwn_softc *);
+int iwn2000_temp_offset_calib(struct iwn_softc *);
int iwn4965_post_alive(struct iwn_softc *);
int iwn5000_post_alive(struct iwn_softc *);
int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *,
@@ -651,6 +654,11 @@ iwn5000_attach(struct iwn_softc *sc, pci
} else
sc->fwname = "iwn-6005";
break;
+ case IWN_HW_REV_TYPE_2030:
+ sc->limits = &iwn2000_sensitivity_limits;
+ sc->fwname = "iwn-2030";
+ sc->sc_flags |= IWN_FLAG_ADV_BT_COEX;
+ break;
default:
printf(": adapter type %d not supported\n", sc->hw_type);
return ENOTSUP;
@@ -1529,6 +1537,14 @@ iwn5000_read_eeprom(struct iwn_softc *sc
hdr.version, hdr.pa_type, letoh16(hdr.volt)));
sc->calib_ver = hdr.version;
+ if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+ sc->eeprom_voltage = letoh16(hdr.volt);
+ iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
+ sc->eeprom_temp = letoh16(val);
+ iwn_read_prom_data(sc, base + IWN2000_EEPROM_RAWTEMP, &val, 2);
+ sc->eeprom_rawtemp = letoh16(val);
+ }
+
if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
/* Compute temperature offset. */
iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
@@ -2095,7 +2111,8 @@ iwn5000_rx_calib_results(struct iwn_soft
switch (calib->code) {
case IWN5000_PHY_CALIB_DC:
- if (sc->hw_type == IWN_HW_REV_TYPE_5150)
+ if (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
+ sc->hw_type == IWN_HW_REV_TYPE_2030)
idx = 0;
break;
case IWN5000_PHY_CALIB_LO:
@@ -4160,29 +4177,55 @@ iwn_send_advanced_btcoex(struct iwn_soft
0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa,
0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
};
- struct iwn6000_btcoex_config btconfig;
struct iwn_btcoex_priotable btprio;
struct iwn_btcoex_prot btprot;
int error, i;
- memset(&btconfig, 0, sizeof btconfig);
- btconfig.flags = IWN_BT_FLAG_COEX6000_CHAN_INHIBITION |
- (IWN_BT_FLAG_COEX6000_MODE_3W << IWN_BT_FLAG_COEX6000_MODE_SHIFT) |
- IWN_BT_FLAG_SYNC_2_BT_DISABLE;
- btconfig.max_kill = 5;
- btconfig.bt3_t7_timer = 1;
- btconfig.kill_ack = htole32(0xffff0000);
- btconfig.kill_cts = htole32(0xffff0000);
- btconfig.sample_time = 2;
- btconfig.bt3_t2_timer = 0xc;
- for (i = 0; i < 12; i++)
- btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
- btconfig.valid = htole16(0xff);
- btconfig.prio_boost = 0xf0;
- DPRINTF(("configuring advanced bluetooth coexistence\n"));
- error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1);
- if (error != 0)
- return (error);
+ if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+ struct iwn2000_btcoex_config btconfig;
+
+ memset(&btconfig, 0, sizeof btconfig);
+ btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
+ (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
+ IWN_BT_SYNC_2_BT_DISABLE;
+ btconfig.max_kill = 5;
+ btconfig.bt3_t7_timer = 1;
+ btconfig.kill_ack = htole32(0xffff0000);
+ btconfig.kill_cts = htole32(0xffff0000);
+ btconfig.sample_time = 2;
+ btconfig.bt3_t2_timer = 0xc;
+ for (i = 0; i < 12; i++)
+ btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
+ btconfig.valid = htole16(0xff);
+ btconfig.prio_boost = htole32(0xf0);
+ DPRINTF(("configuring advanced bluetooth coexistence\n"));
+ error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
+ sizeof(btconfig), 1);
+ if (error != 0)
+ return (error);
+ } else {
+ struct iwn6000_btcoex_config btconfig;
+
+ memset(&btconfig, 0, sizeof btconfig);
+ btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
+ (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
+ IWN_BT_SYNC_2_BT_DISABLE;
+ btconfig.max_kill = 5;
+ btconfig.bt3_t7_timer = 1;
+ btconfig.kill_ack = htole32(0xffff0000);
+ btconfig.kill_cts = htole32(0xffff0000);
+ btconfig.sample_time = 2;
+ btconfig.bt3_t2_timer = 0xc;
+ for (i = 0; i < 12; i++)
+ btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
+ btconfig.valid = htole16(0xff);
+ btconfig.prio_boost = 0xf0;
+ DPRINTF(("configuring advanced bluetooth coexistence\n"));
+ error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
+ sizeof(btconfig), 1);
+ if (error != 0)
+ return (error);
+ }
memset(&btprio, 0, sizeof btprio);
btprio.calib_init1 = 0x6;
@@ -4233,14 +4276,21 @@ iwn_config(struct iwn_softc *sc)
uint16_t rxchain;
int error;
+ /* Set radio temperature sensor offset. */
if (sc->hw_type == IWN_HW_REV_TYPE_6005) {
- /* Set radio temperature sensor offset. */
error = iwn5000_temp_offset_calib(sc);
if (error != 0) {
printf("%s: could not set temperature offset\n",
sc->sc_dev.dv_xname);
return error;
}
+ } else if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+ error = iwn2000_temp_offset_calib(sc);
+ if (error != 0) {
+ printf("%s: could not set temperature offset\n",
+ sc->sc_dev.dv_xname);
+ return error;
+ }
}
if (sc->hw_type == IWN_HW_REV_TYPE_6050 ||
@@ -5005,6 +5055,29 @@ iwn5000_temp_offset_calib(struct iwn_sof
return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
}
+int
+iwn2000_temp_offset_calib(struct iwn_softc *sc)
+{
+ struct iwn2000_phy_calib_temp_offset cmd;
+
+ memset(&cmd, 0, sizeof cmd);
+ cmd.code = IWN2000_PHY_CALIB_TEMP_OFFSET;
+ cmd.ngroups = 1;
+ cmd.isvalid = 1;
+ if (sc->eeprom_rawtemp != 0) {
+ cmd.offset_low = htole16(sc->eeprom_rawtemp);
+ cmd.offset_high = htole16(sc->eeprom_temp);
+ } else {
+ cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET);
+ cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET);
+ }
+ cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage);
+ DPRINTF(("setting radio sensor offset to %d:%d, voltage to %d\n",
+ letoh16(cmd.offset_low), letoh16(cmd.offset_high),
+ letoh16(cmd.burnt_voltage_ref)));
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
+}
+
/*
* This function is called after the runtime firmware notifies us of its
* readiness (called in a process context).
@@ -5681,6 +5754,8 @@ iwn5000_nic_config(struct iwn_softc *sc)
}
if (sc->hw_type == IWN_HW_REV_TYPE_6005)
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2);
+ if (sc->hw_type == IWN_HW_REV_TYPE_2030)
+ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_IQ_INVERT);
return 0;
}
Index: if_iwnreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v
retrieving revision 1.45
diff -u -p -r1.45 if_iwnreg.h
--- if_iwnreg.h 26 Nov 2013 20:33:17 -0000 1.45
+++ if_iwnreg.h 9 Feb 2014 11:18:29 -0000
@@ -205,6 +205,7 @@
#define IWN_HW_REV_TYPE_6000 7
#define IWN_HW_REV_TYPE_6050 8
#define IWN_HW_REV_TYPE_6005 11
+#define IWN_HW_REV_TYPE_2030 12
/* Possible flags for register IWN_GIO_CHICKEN. */
#define IWN_GIO_CHICKEN_L1A_NO_L0S_RX (1 << 23)
@@ -219,6 +220,7 @@
#define IWN_GP_DRIVER_RADIO_2X2_IPA (2 << 0)
#define IWN_GP_DRIVER_CALIB_VER6 (1 << 2)
#define IWN_GP_DRIVER_6050_1X2 (1 << 3)
+#define IWN_GP_DRIVER_RADIO_IQ_INVERT (1 << 7)
/* Possible flags for register IWN_UCODE_GP1_CLR. */
#define IWN_UCODE_GP1_RFKILL (1 << 1)
@@ -852,15 +854,15 @@ struct iwn_bluetooth {
struct iwn6000_btcoex_config {
uint8_t flags;
-#define IWN_BT_FLAG_COEX6000_CHAN_INHIBITION 1
-#define IWN_BT_FLAG_COEX6000_MODE_MASK ((1 << 3) | (1 << 4) |
(1 << 5))
-#define IWN_BT_FLAG_COEX6000_MODE_SHIFT 3
-#define IWN_BT_FLAG_COEX6000_MODE_DISABLED 0
-#define IWN_BT_FLAG_COEX6000_MODE_LEGACY_2W 1
-#define IWN_BT_FLAG_COEX6000_MODE_3W 2
-#define IWN_BT_FLAG_COEX6000_MODE_4W 3
-#define IWN_BT_FLAG_UCODE_DEFAULT (1<<6)
-#define IWN_BT_FLAG_SYNC_2_BT_DISABLE (1<<7)
+#define IWN_BT_COEX6000_CHAN_INHIBITION 1
+#define IWN_BT_COEX6000_MODE_MASK ((1 << 3) | (1 << 4) | (1 << 5))
+#define IWN_BT_COEX6000_MODE_SHIFT 3
+#define IWN_BT_COEX6000_MODE_DISABLED 0
+#define IWN_BT_COEX6000_MODE_LEGACY_2W 1
+#define IWN_BT_COEX6000_MODE_3W 2
+#define IWN_BT_COEX6000_MODE_4W 3
+#define IWN_BT_UCODE_DEFAULT (1<<6)
+#define IWN_BT_SYNC_2_BT_DISABLE (1<<7)
uint8_t lead_time;
uint8_t max_kill;
@@ -878,6 +880,25 @@ struct iwn6000_btcoex_config {
uint16_t rx_prio_boost;
} __packed;
+struct iwn2000_btcoex_config {
+ uint8_t flags; /* same as in iwn6000_btcoex_config */
+ uint8_t lead_time;
+ uint8_t max_kill;
+ uint8_t bt3_t7_timer;
+ uint32_t kill_ack;
+ uint32_t kill_cts;
+ uint8_t sample_time;
+ uint8_t bt3_t2_timer;
+ uint16_t bt4_reaction;
+ uint32_t lookup_table[12];
+ uint16_t bt4_decision;
+ uint16_t valid;
+ uint32_t prio_boost;
+ uint8_t reserved;
+ uint8_t tx_prio_boost;
+ uint16_t rx_prio_boost;
+} __packed;
+
/* Structure for command IWN_CMD_BT_COEX_PRIOTABLE */
struct iwn_btcoex_priotable {
uint8_t calib_init1;
@@ -972,6 +993,8 @@ struct iwn_phy_calib {
#define IWN5000_PHY_CALIB_RESET_NOISE_GAIN 18
#define IWN5000_PHY_CALIB_NOISE_GAIN 19
+#define IWN2000_PHY_CALIB_TEMP_OFFSET 18
+
uint8_t group;
uint8_t ngroups;
uint8_t isvalid;
@@ -998,6 +1021,17 @@ struct iwn5000_phy_calib_temp_offset {
uint16_t reserved;
} __packed;
+struct iwn2000_phy_calib_temp_offset {
+ uint8_t code;
+ uint8_t group;
+ uint8_t ngroups;
+ uint8_t isvalid;
+ int16_t offset_high;
+ int16_t offset_low;
+ int16_t burnt_voltage_ref;
+ int16_t reserved;
+} __packed;
+
struct iwn_phy_calib_gain {
uint8_t code;
uint8_t group;
@@ -1411,6 +1445,7 @@ struct iwn_fw_tlv {
#define IWN5000_EEPROM_CRYSTAL 0x128
#define IWN5000_EEPROM_TEMP 0x12a
#define IWN5000_EEPROM_VOLT 0x12b
+#define IWN2000_EEPROM_RAWTEMP 0x12b
/* Possible flags for IWN_EEPROM_SKU_CAP. */
#define IWN_EEPROM_SKU_CAP_11N (1 << 6)
@@ -1718,6 +1753,18 @@ static const struct iwn_sensitivity_limi
97,
100
};
+
+static const struct iwn_sensitivity_limits iwn2000_sensitivity_limits = {
+ 105, 110,
+ 128, 232, /* Linux has 192, 232 */
+ 80, 145,
+ 128, 232,
+ 125, 175,
+ 160, 310,
+ 97,
+ 97,
+ 110 /* Linux has 100 */
+ };
/* Map TID to TX scheduler's FIFO. */
static const uint8_t iwn_tid2fifo[] = {
Index: if_iwnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v
retrieving revision 1.26
diff -u -p -r1.26 if_iwnvar.h
--- if_iwnvar.h 30 Nov 2013 19:41:21 -0000 1.26
+++ if_iwnvar.h 9 Feb 2014 11:18:29 -0000
@@ -275,6 +275,7 @@ struct iwn_softc {
uint32_t eeprom_crystal;
int16_t eeprom_temp;
int16_t eeprom_voltage;
+ int16_t eeprom_rawtemp;
int8_t maxpwr2GHz;
int8_t maxpwr5GHz;
int8_t maxpwr[IEEE80211_CHAN_MAX];