Module Name:    src
Committed By:   nonaka
Date:           Wed Jul 22 15:18:01 UTC 2015

Modified Files:
        src/sys/dev/pci: if_iwm.c if_iwmvar.h

Log Message:
iwm(4) can read the firmware image from disk when interface up.
This change is useful for full-disk encryption environment.


To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/sys/dev/pci/if_iwm.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/pci/if_iwmvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_iwm.c
diff -u src/sys/dev/pci/if_iwm.c:1.35 src/sys/dev/pci/if_iwm.c:1.36
--- src/sys/dev/pci/if_iwm.c:1.35	Fri May 22 15:32:21 2015
+++ src/sys/dev/pci/if_iwm.c	Wed Jul 22 15:18:01 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwm.c,v 1.35 2015/05/22 15:32:21 nonaka Exp $	*/
+/*	$NetBSD: if_iwm.c,v 1.36 2015/07/22 15:18:01 nonaka Exp $	*/
 /*	OpenBSD: if_iwm.c,v 1.41 2015/05/22 06:50:54 kettenis Exp	*/
 
 /*
@@ -105,7 +105,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.35 2015/05/22 15:32:21 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.36 2015/07/22 15:18:01 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -437,6 +437,9 @@ static int	iwm_activate(device_t, enum d
 static void	iwm_wakeup(struct iwm_softc *);
 #endif
 static void	iwm_radiotap_attach(struct iwm_softc *);
+static int	iwm_sysctl_fw_loaded_handler(SYSCTLFN_PROTO);
+
+static int iwm_sysctl_root_num;
 
 static int
 iwm_firmload(struct iwm_softc *sc)
@@ -445,6 +448,9 @@ iwm_firmload(struct iwm_softc *sc)
 	firmware_handle_t fwh;
 	int error;
 
+	if (ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED))
+		return 0;
+
 	/* Open firmware image. */
 	if ((error = firmware_open("if_iwm", sc->sc_fwname, &fwh)) != 0) {
 		aprint_error_dev(sc->sc_dev,
@@ -452,6 +458,11 @@ iwm_firmload(struct iwm_softc *sc)
 		return error;
 	}
 
+	if (fw->fw_rawdata != NULL && fw->fw_rawsize > 0) {
+		kmem_free(fw->fw_rawdata, fw->fw_rawsize);
+		fw->fw_rawdata = NULL;
+	}
+
 	fw->fw_rawsize = firmware_get_size(fwh);
 	/*
 	 * Well, this is how the Linux driver checks it ....
@@ -466,8 +477,7 @@ iwm_firmload(struct iwm_softc *sc)
 	/* some sanity */
 	if (fw->fw_rawsize > IWM_FWMAXSIZE) {
 		aprint_error_dev(sc->sc_dev,
-		    "firmware size is ridiculous: %zd bytes\n",
-		fw->fw_rawsize);
+		    "firmware size is ridiculous: %zd bytes\n", fw->fw_rawsize);
 		error = EINVAL;
 		goto out;
 	}
@@ -487,6 +497,7 @@ iwm_firmload(struct iwm_softc *sc)
 		goto out;
 	}
 
+	SET(sc->sc_flags, IWM_FLAG_FW_LOADED);
  out:
 	/* caller will release memory, if necessary */
 
@@ -816,6 +827,7 @@ iwm_read_firmware(struct iwm_softc *sc)
 	if (error && fw->fw_rawdata != NULL) {
 		kmem_free(fw->fw_rawdata, fw->fw_rawsize);
 		fw->fw_rawdata = NULL;
+		CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
 	}
 	return error;
 }
@@ -5917,17 +5929,25 @@ iwm_ioctl(struct ifnet *ifp, u_long cmd,
 
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+		if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
+			error = ENXIO;
+			break;
+		}
 		sa = ifreq_getaddr(SIOCADDMULTI, (struct ifreq *)data);
 		error = (cmd == SIOCADDMULTI) ?
 		    ether_addmulti(sa, &sc->sc_ec) :
 		    ether_delmulti(sa, &sc->sc_ec);
-
 		if (error == ENETRESET)
 			error = 0;
 		break;
 
 	default:
+		if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
+			error = ether_ioctl(ifp, cmd, data);
+			break;
+		}
 		error = ieee80211_ioctl(ic, cmd, data);
+		break;
 	}
 
 	if (error == ENETRESET) {
@@ -6523,13 +6543,9 @@ iwm_match(device_t parent, cfdata_t matc
 static int
 iwm_preinit(struct iwm_softc *sc)
 {
+	struct ieee80211com *ic = &sc->sc_ic;
 	int error;
 
-	if ((error = iwm_prepare_card_hw(sc)) != 0) {
-		aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
-		return error;
-	}
-
 	if (sc->sc_flags & IWM_FLAG_ATTACHED)
 		return 0;
 
@@ -6540,20 +6556,8 @@ iwm_preinit(struct iwm_softc *sc)
 
 	error = iwm_run_init_mvm_ucode(sc, 1);
 	iwm_stop_device(sc);
-	return error;
-}
-
-static void
-iwm_attach_hook(device_t dev)
-{
-	struct iwm_softc *sc = device_private(dev);
-	struct ieee80211com *ic = &sc->sc_ic;
-	struct ifnet *ifp = &sc->sc_ec.ec_if;
-
-	KASSERT(!cold);
-
-	if (iwm_preinit(sc) != 0)
-		return;
+	if (error)
+		return error;
 
 	sc->sc_flags |= IWM_FLAG_ATTACHED;
 
@@ -6565,52 +6569,11 @@ iwm_attach_hook(device_t dev)
 	    IWM_UCODE_API(sc->sc_fwver),
 	    ether_sprintf(sc->sc_nvm.hw_addr));
 
-	ic->ic_ifp = ifp;
-	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
-	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
-	ic->ic_state = IEEE80211_S_INIT;
-
-	/* Set device capabilities. */
-	ic->ic_caps =
-	    IEEE80211_C_WEP |		/* WEP */
-	    IEEE80211_C_WPA |		/* 802.11i */
-	    IEEE80211_C_SHSLOT |	/* short slot time supported */
-	    IEEE80211_C_SHPREAMBLE;	/* short preamble supported */
-
 	/* not all hardware can do 5GHz band */
 	if (sc->sc_nvm.sku_cap_band_52GHz_enable)
 		ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
-	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
-	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
-
-	for (int i = 0; i < __arraycount(sc->sc_phyctxt); i++) {
-		sc->sc_phyctxt[i].id = i;
-	}
-
-	sc->sc_amrr.amrr_min_success_threshold =  1;
-	sc->sc_amrr.amrr_max_success_threshold = 15;
-
-	/* IBSS channel undefined for now. */
-	ic->ic_ibss_chan = &ic->ic_channels[1];
-
-#if 0
-	/* Max RSSI */
-	ic->ic_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM;
-#endif
 
-	ifp->if_softc = sc;
-	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-	ifp->if_init = iwm_init;
-	ifp->if_stop = iwm_stop;
-	ifp->if_ioctl = iwm_ioctl;
-	ifp->if_start = iwm_start;
-	ifp->if_watchdog = iwm_watchdog;
-	IFQ_SET_READY(&ifp->if_snd);
-	memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
-
-	if_initialize(ifp);
 	ieee80211_ifattach(ic);
-	if_register(ifp);
 
 	ic->ic_node_alloc = iwm_node_alloc;
 
@@ -6621,15 +6584,16 @@ iwm_attach_hook(device_t dev)
 	ieee80211_announce(ic);
 
 	iwm_radiotap_attach(sc);
-	callout_init(&sc->sc_calib_to, 0);
-	callout_setfunc(&sc->sc_calib_to, iwm_calib_timeout, sc);
 
-	//task_set(&sc->init_task, iwm_init_task, sc);
+	return 0;
+}
 
-	if (pmf_device_register(dev, NULL, NULL))
-		pmf_class_network_register(dev, ifp);
-	else
-		aprint_error_dev(dev, "couldn't establish power handler\n");
+static void
+iwm_attach_hook(device_t dev)
+{
+	struct iwm_softc *sc = device_private(dev);
+
+	iwm_preinit(sc);
 }
 
 static void
@@ -6637,6 +6601,8 @@ iwm_attach(device_t parent, device_t sel
 {
 	struct iwm_softc *sc = device_private(self);
 	struct pci_attach_args *pa = aux;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ifnet *ifp = &sc->sc_ec.ec_if;
 #ifndef __HAVE_PCI_MSI_MSIX
 	pci_intr_handle_t ih;
 #endif
@@ -6644,6 +6610,7 @@ iwm_attach(device_t parent, device_t sel
 	const char *intrstr;
 	int error;
 	int txq_i;
+	const struct sysctlnode *node;
 
 	sc->sc_dev = self;
 	sc->sc_pct = pa->pa_pc;
@@ -6810,6 +6777,92 @@ iwm_attach(device_t parent, device_t sel
 	/* Clear pending interrupts. */
 	IWM_WRITE(sc, IWM_CSR_INT, 0xffffffff);
 
+	if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
+	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
+	    SYSCTL_DESCR("iwm per-controller controls"),
+	    NULL, 0, NULL, 0,
+	    CTL_HW, iwm_sysctl_root_num, CTL_CREATE,
+	    CTL_EOL)) != 0) {
+		aprint_normal_dev(sc->sc_dev,
+		    "couldn't create iwm per-controller sysctl node\n");
+	}
+	if (error == 0) {
+		int iwm_nodenum = node->sysctl_num;
+
+		/* Reload firmware sysctl node */
+		if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
+		    CTLFLAG_READWRITE, CTLTYPE_INT, "fw_loaded",
+		    SYSCTL_DESCR("Reload firmware"),
+		    iwm_sysctl_fw_loaded_handler, 0, (void *)sc, 0,
+		    CTL_HW, iwm_sysctl_root_num, iwm_nodenum, CTL_CREATE,
+		    CTL_EOL)) != 0) {
+			aprint_normal_dev(sc->sc_dev,
+			    "couldn't create load_fw sysctl node\n");
+		}
+	}
+
+	/*
+	 * Attach interface
+	 */
+	ic->ic_ifp = ifp;
+	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
+	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
+	ic->ic_state = IEEE80211_S_INIT;
+
+	/* Set device capabilities. */
+	ic->ic_caps =
+	    IEEE80211_C_WEP |		/* WEP */
+	    IEEE80211_C_WPA |		/* 802.11i */
+	    IEEE80211_C_SHSLOT |	/* short slot time supported */
+	    IEEE80211_C_SHPREAMBLE;	/* short preamble supported */
+
+	/* all hardware can do 2.4GHz band */
+	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
+	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
+
+	for (int i = 0; i < __arraycount(sc->sc_phyctxt); i++) {
+		sc->sc_phyctxt[i].id = i;
+	}
+
+	sc->sc_amrr.amrr_min_success_threshold =  1;
+	sc->sc_amrr.amrr_max_success_threshold = 15;
+
+	/* IBSS channel undefined for now. */
+	ic->ic_ibss_chan = &ic->ic_channels[1];
+
+#if 0
+	/* Max RSSI */
+	ic->ic_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM;
+#endif
+
+	ifp->if_softc = sc;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_init = iwm_init;
+	ifp->if_stop = iwm_stop;
+	ifp->if_ioctl = iwm_ioctl;
+	ifp->if_start = iwm_start;
+	ifp->if_watchdog = iwm_watchdog;
+	IFQ_SET_READY(&ifp->if_snd);
+	memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
+
+	if_initialize(ifp);
+#if 0
+	ieee80211_ifattach(ic);
+#else
+	ether_ifattach(ifp, ic->ic_myaddr);	/* XXX */
+#endif
+	if_register(ifp);
+
+	callout_init(&sc->sc_calib_to, 0);
+	callout_setfunc(&sc->sc_calib_to, iwm_calib_timeout, sc);
+
+	//task_set(&sc->init_task, iwm_init_task, sc);
+
+	if (pmf_device_register(self, NULL, NULL))
+		pmf_class_network_register(self, ifp);
+	else
+		aprint_error_dev(self, "couldn't establish power handler\n");
+
 	/*
 	 * We can't do normal attach before the file system is mounted
 	 * because we cannot read the MAC address without loading the
@@ -6907,10 +6960,32 @@ iwm_activate(device_t self, enum devact 
 CFATTACH_DECL_NEW(iwm, sizeof(struct iwm_softc), iwm_match, iwm_attach,
 	NULL, NULL);
 
-#ifdef IWM_DEBUG
+static int
+iwm_sysctl_fw_loaded_handler(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct iwm_softc *sc;
+	int error, t;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	t = ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED) ? 1 : 0;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t == 0)
+		CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
+	return 0;
+}
+
 SYSCTL_SETUP(sysctl_iwm, "sysctl iwm(4) subtree setup")
 {
-	const struct sysctlnode *rnode, *cnode;
+	const struct sysctlnode *rnode;
+#ifdef IWM_DEBUG
+	const struct sysctlnode *cnode;
+#endif /* IWM_DEBUG */
 	int rc;
 
 	if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
@@ -6919,16 +6994,19 @@ SYSCTL_SETUP(sysctl_iwm, "sysctl iwm(4) 
 	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
 		goto err;
 
+	iwm_sysctl_root_num = rnode->sysctl_num;
+
+#ifdef IWM_DEBUG
 	/* control debugging printfs */
 	if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
 	    "debug", SYSCTL_DESCR("Enable debugging output"),
 	    NULL, 0, &iwm_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
 		goto err;
+#endif /* IWM_DEBUG */
 
 	return;
 
  err:
 	aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
 }
-#endif /* IWM_DEBUG */

Index: src/sys/dev/pci/if_iwmvar.h
diff -u src/sys/dev/pci/if_iwmvar.h:1.7 src/sys/dev/pci/if_iwmvar.h:1.8
--- src/sys/dev/pci/if_iwmvar.h:1.7	Fri May 15 08:44:15 2015
+++ src/sys/dev/pci/if_iwmvar.h	Wed Jul 22 15:18:01 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwmvar.h,v 1.7 2015/05/15 08:44:15 knakahara Exp $	*/
+/*	$NetBSD: if_iwmvar.h,v 1.8 2015/07/22 15:18:01 nonaka Exp $	*/
 /*	OpenBSD: if_iwmvar.h,v 1.7 2015/03/02 13:51:10 jsg Exp 	*/
 
 /*
@@ -287,12 +287,13 @@ struct iwm_rx_ring {
 	int			cur;
 };
 
-#define IWM_FLAG_USE_ICT	0x01
-#define IWM_FLAG_HW_INITED	0x02
-#define IWM_FLAG_STOPPED	0x04
-#define IWM_FLAG_RFKILL		0x08
-#define IWM_FLAG_BUSY		0x10
-#define IWM_FLAG_ATTACHED	0x20
+#define IWM_FLAG_USE_ICT	__BIT(0)
+#define IWM_FLAG_HW_INITED	__BIT(1)
+#define IWM_FLAG_STOPPED	__BIT(2)
+#define IWM_FLAG_RFKILL		__BIT(3)
+#define IWM_FLAG_BUSY		__BIT(4)
+#define IWM_FLAG_ATTACHED	__BIT(5)
+#define IWM_FLAG_FW_LOADED	__BIT(6)
 
 struct iwm_ucode_status {
 	uint32_t uc_error_event_table;
@@ -478,6 +479,8 @@ struct iwm_softc {
 
 	int host_interrupt_operation_mode;
 
+	struct sysctllog *sc_clog;
+
 	struct bpf_if *		sc_drvbpf;
 
 	union {

Reply via email to