Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Oct 2002 20:42:54 -0700 (PDT)
From:      Doug Ambrisko <ambrisko@ambrisko.com>
To:        David Wolfskill <david@catwhisker.org>
Cc:        current@FreeBSD.org
Subject:   Re: "Expensive timeout(9) function" @an_stats_update() [/usr/src/sys/dev/an/if_an.c:724]
Message-ID:  <200210250342.g9P3gsu86966@ambrisko.com>
In-Reply-To: <200210221422.g9MEMxwU006241@bunrab.catwhisker.org>

next in thread | previous in thread | raw e-mail | index | archive | help
David Wolfskill writes:
| Noticed a bunch of:
| > Expensive timeout(9) function: 0xc0170e40(0xc274c000) 0.001114387
| 
| from running (yesterday's) -CURRENT, so I thought I'd check against
| (yesterday's kernel.debug (before I replaced it with today's).
| 
| I do have some patches to the "an" driver installed (from Doug Ambrisko)
| that don't seem to have been committed (yet?).
| 
| If he (or anyone else) would like me to test things, I'm willing and
| able.

I haven't seen that but -current isn't being very stable on my laptop
so I have to keep going back to -stable for my job.  I'm getting some
patches ready to commit.  Need some work on the man page.  It closes
a PR that was partially incomplete.  You might want to get rid of
that old stuff and try this.  The only timeout calls an_stats_update.
I don't really see why it would take a long time.  Note this patch
doesn't touch that function so it shouldn't fix that problem.

Doug A.

Index: sys/dev/an/if_aironet_ieee.h
===================================================================
RCS file: /cvs/src/sys/dev/an/if_aironet_ieee.h,v
retrieving revision 1.10
diff -c -r1.10 if_aironet_ieee.h
*** sys/dev/an/if_aironet_ieee.h	23 Sep 2002 18:54:29 -0000	1.10
--- sys/dev/an/if_aironet_ieee.h	25 Oct 2002 03:33:33 -0000
***************
*** 132,137 ****
--- 132,156 ----
  };
  #endif
  
+ /*
+  * The card provides an 8-bit signal strength value (RSSI), which can
+  * be converted to a dBm power value (or a percent) using a table in
+  * the card's firmware (when available).  The tables are slightly
+  * different in individual cards, even of the same model.  If the
+  * table is not available, the mapping can be approximated by dBm =
+  * RSSI - 100.  This approximation can be seen by plotting a few
+  * tables, and also matches some info on the Intersil web site (I
+  * think they make the RF front end for the cards.  However, the linux
+  * driver uses the approximation dBm = RSSI/2 - 95.  I think that is
+  * just wrong. 
+  */
+ 
+ struct an_rssi_entry {
+ 	u_int8_t	an_rss_pct;
+ 	u_int8_t	an_rss_dbm;
+ };
+ 
+ 
  struct an_ltv_key {
  	u_int16_t	an_len;
  	u_int16_t	an_type;
***************
*** 335,340 ****
--- 354,360 ----
  #define AN_RXMODE_80211_MONITOR_ANYBSS		0x0004
  #define AN_RXMODE_LAN_MONITOR_CURBSS		0x0005
  #define AN_RXMODE_NO_8023_HEADER		0x0100
+ #define AN_RXMODE_NORMALIZED_RSSI		0x0200
  
  #define AN_RATE_1MBPS				0x0002
  #define AN_RATE_2MBPS				0x0004
***************
*** 503,508 ****
--- 523,538 ----
  	/* ??? */
  };
  
+ /* 
+  * RSSI map.  If available in the card's firmware, this can be used to
+  * convert the 8-bit RSSI values from the card into dBm.
+  */
+ struct an_ltv_rssi_map {
+ 	u_int16_t		an_len;
+ 	u_int16_t		an_type;
+ 	struct an_rssi_entry	an_entries[256];
+ };
+ 
  /*
   * Status (read only). Note: the manual claims this RID is 108 bytes
   * long (0x6A is the last datum, which is 2 bytes long) however when
***************
*** 520,526 ****
  	u_int8_t		an_macaddr[6];		/* 0x02 */
  	u_int16_t		an_opmode;		/* 0x08 */
  	u_int16_t		an_errcode;		/* 0x0A */
! 	u_int16_t		an_cur_signal_strength;	/* 0x0C */
  	u_int16_t		an_ssidlen;		/* 0x0E */
  	u_int8_t		an_ssid[32];		/* 0x10 */
  	u_int8_t		an_ap_name[16];		/* 0x30 */
--- 550,556 ----
  	u_int8_t		an_macaddr[6];		/* 0x02 */
  	u_int16_t		an_opmode;		/* 0x08 */
  	u_int16_t		an_errcode;		/* 0x0A */
! 	u_int16_t		an_signal_quality;	/* 0x0C */
  	u_int16_t		an_ssidlen;		/* 0x0E */
  	u_int8_t		an_ssid[32];		/* 0x10 */
  	u_int8_t		an_ap_name[16];		/* 0x30 */
***************
*** 541,552 ****
  	u_int16_t		an_cur_signal_quality;	/* 0x6C */
  	u_int16_t		an_current_tx_rate;	/* 0x6E */
  	u_int16_t		an_ap_device;		/* 0x70 */
! 	u_int16_t		an_normalized_rssi;	/* 0x72 */
  	u_int16_t		an_short_pre_in_use;	/* 0x74 */
  	u_int8_t		an_ap_ip_addr[4];	/* 0x76 */
! 	u_int16_t		an_max_noise_prev_sec;	/* 0x7A */
! 	u_int16_t		an_avg_noise_prev_min;	/* 0x7C */
! 	u_int16_t		an_max_noise_prev_min;	/* 0x7E */
  	u_int16_t		an_spare[5];
  };
  
--- 571,585 ----
  	u_int16_t		an_cur_signal_quality;	/* 0x6C */
  	u_int16_t		an_current_tx_rate;	/* 0x6E */
  	u_int16_t		an_ap_device;		/* 0x70 */
! 	u_int16_t		an_normalized_strength;	/* 0x72 */
  	u_int16_t		an_short_pre_in_use;	/* 0x74 */
  	u_int8_t		an_ap_ip_addr[4];	/* 0x76 */
! 	u_int8_t		an_noise_prev_sec_pc;   /* 0x7A */
! 	u_int8_t		an_noise_prev_sec_db;   /* 0x7B */
! 	u_int8_t		an_avg_noise_prev_min_pc;       /* 0x7C */
! 	u_int8_t		an_avg_noise_prev_min_db;       /* 0x7D */
! 	u_int8_t		an_max_noise_prev_min_pc;       /* 0x7E */
! 	u_int8_t		an_max_noise_prev_min_db;       /* 0x7F */
  	u_int16_t		an_spare[5];
  };
  
***************
*** 643,648 ****
--- 676,682 ----
  #define AN_RID_CAPABILITIES	0xFF00	/* PC 4500/4800 capabilities */
  #define AN_RID_AP_INFO		0xFF01	/* Access point info */
  #define AN_RID_RADIO_INFO	0xFF02	/* Radio info */
+ #define AN_RID_RSSI_MAP         0xFF04  /* RSSI <-> dBm table */
  #define AN_RID_STATUS		0xFF50	/* Current status info */
  #define AN_RID_BEACONS_HST	0xFF51
  #define AN_RID_BUSY_HST		0xFF52
Index: sys/dev/an/if_an.c
===================================================================
RCS file: /cvs/src/sys/dev/an/if_an.c,v
retrieving revision 1.37
diff -c -r1.37 if_an.c
*** sys/dev/an/if_an.c	28 Sep 2002 17:14:23 -0000	1.37
--- sys/dev/an/if_an.c	25 Oct 2002 03:33:33 -0000
***************
*** 107,112 ****
--- 107,113 ----
  #include <sys/lock.h>
  #include <sys/mutex.h>
  #include <machine/resource.h>
+ #include <sys/malloc.h>
  
  #include <net/if.h>
  #include <net/if_arp.h>
***************
*** 157,163 ****
  static void an_setdef		(struct an_softc *, struct an_req *);
  #ifdef ANCACHE
  static void an_cache_store	(struct an_softc *, struct ether_header *,
! 					struct mbuf *, unsigned short);
  #endif
  
  /* function definitions for use with the Cisco's Linux configuration
--- 158,164 ----
  static void an_setdef		(struct an_softc *, struct an_req *);
  #ifdef ANCACHE
  static void an_cache_store	(struct an_softc *, struct ether_header *,
! 					struct mbuf *, u_int8_t, u_int8_t);
  #endif
  
  /* function definitions for use with the Cisco's Linux configuration
***************
*** 184,193 ****
--- 185,201 ----
  static void an_media_status	(struct ifnet *, struct ifmediareq *);
  
  static int	an_dump = 0;
+ static int	an_cache_mode = 0;
+ 
+ #define DBM 0
+ #define PERCENT 1
+ #define RAW 2
  
  static char an_conf[256];
+ static char an_conf_cache[256];
  
  /* sysctl vars */
+ 
  SYSCTL_NODE(_machdep, OID_AUTO, an, CTLFLAG_RD, 0, "dump RID");
  
  static int
***************
*** 197,213 ****
  	char 	*s = an_conf;
  
  	last = an_dump;
- 	bzero(an_conf, sizeof(an_conf));
  
  	switch (an_dump) {
  	case 0:
! 		strcat(an_conf, "off");
  		break;
  	case 1:
! 		strcat(an_conf, "type");
  		break;
  	case 2:
! 		strcat(an_conf, "dump");
  		break;
  	default:
  		snprintf(an_conf, 5, "%x", an_dump);
--- 205,220 ----
  	char 	*s = an_conf;
  
  	last = an_dump;
  
  	switch (an_dump) {
  	case 0:
! 		strcpy(an_conf, "off");
  		break;
  	case 1:
! 		strcpy(an_conf, "type");
  		break;
  	case 2:
! 		strcpy(an_conf, "dump");
  		break;
  	default:
  		snprintf(an_conf, 5, "%x", an_dump);
***************
*** 216,222 ****
  
  	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
  
! 	if (strncmp(an_conf,"off", 4) == 0) {
  		an_dump = 0;
   	}
  	if (strncmp(an_conf,"dump", 4) == 0) {
--- 223,229 ----
  
  	error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
  
! 	if (strncmp(an_conf,"off", 3) == 0) {
  		an_dump = 0;
   	}
  	if (strncmp(an_conf,"dump", 4) == 0) {
***************
*** 247,252 ****
--- 254,297 ----
  SYSCTL_PROC(_machdep, OID_AUTO, an_dump, CTLTYPE_STRING | CTLFLAG_RW,
              0, sizeof(an_conf), sysctl_an_dump, "A", "");
  
+ static int
+ sysctl_an_cache_mode(SYSCTL_HANDLER_ARGS)
+ {
+ 	int	error, last;
+ 
+ 	last = an_cache_mode;
+ 
+ 	switch (an_cache_mode) {
+ 	case 1:
+ 		strcpy(an_conf_cache, "per");
+ 		break;
+ 	case 2:
+ 		strcpy(an_conf_cache, "raw");
+ 		break;
+ 	default:
+ 		strcpy(an_conf_cache, "dbm");
+ 		break;
+ 	}
+ 
+ 	error = sysctl_handle_string(oidp, an_conf_cache, 
+ 			sizeof(an_conf_cache), req);
+ 
+ 	if (strncmp(an_conf_cache,"dbm", 3) == 0) {
+ 		an_cache_mode = 0;
+ 	}
+ 	if (strncmp(an_conf_cache,"per", 3) == 0) {
+ 		an_cache_mode = 1;
+  	}
+ 	if (strncmp(an_conf_cache,"raw", 3) == 0) {
+ 		an_cache_mode = 2;
+ 	}
+ 
+ 	return error;
+ }
+ 
+ SYSCTL_PROC(_machdep, OID_AUTO, an_cache_mode, CTLTYPE_STRING | CTLFLAG_RW,
+             0, sizeof(an_conf_cache), sysctl_an_cache_mode, "A", "");
+ 
  /*
   * We probe for an Aironet 4500/4800 card by attempting to
   * read the default SSID list. On reset, the first entry in
***************
*** 385,390 ****
--- 430,436 ----
  	sc->an_associated = 0;
  	sc->an_monitor = 0;
  	sc->an_was_monitor = 0;
+ 	sc->an_flash_buffer = NULL;
  
  	/* Reset the NIC. */
  	an_reset(sc);
***************
*** 437,442 ****
--- 483,505 ----
  		return(EIO);
  	}
  
+ #ifdef ANCACHE
+ 	/* Read the RSSI <-> dBm map */
+ 	sc->an_have_rssimap = 0;
+ 	if (sc->an_caps.an_softcaps & 8) {
+ 		sc->an_rssimap.an_type = AN_RID_RSSI_MAP;
+ 		sc->an_rssimap.an_len = sizeof(struct an_ltv_rssi_map);
+ 		if (an_read_record(sc, (struct an_ltv_gen *)&sc->an_rssimap)) {
+ 			printf("an%d: unable to get RSSI <-> dBM map\n", sc->an_unit);
+ 		} else {
+ 			printf("an%d: got RSSI <-> dBM map\n", sc->an_unit);
+ 			sc->an_have_rssimap = 1;
+ 		}
+ 	} else {
+ 		printf("an%d: no RSSI <-> dBM map\n", sc->an_unit);
+ 	}
+ #endif
+ 
  	bcopy((char *)&sc->an_caps.an_oemaddr,
  	   (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
  
***************
*** 656,662 ****
  		/* Receive packet. */
  		m_adj(m, sizeof(struct ether_header));
  #ifdef ANCACHE
! 		an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
  #endif
  		ether_input(ifp, eh, m);
  	}
--- 719,726 ----
  		/* Receive packet. */
  		m_adj(m, sizeof(struct ether_header));
  #ifdef ANCACHE
! 		an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength,
! 			       rx_frame.an_rsvd0);
  #endif
  		ether_input(ifp, eh, m);
  	}
***************
*** 1898,1903 ****
--- 1962,1970 ----
  		}
  	}
  
+ 	if (sc->an_have_rssimap)
+ 		sc->an_config.an_rxmode |= AN_RXMODE_NORMALIZED_RSSI;
+ 
  	/* Set the ssid list */
  	sc->an_ssidlist.an_type = AN_RID_SSIDLIST;
  	sc->an_ssidlist.an_len = sizeof(struct an_ltv_ssidlist);
***************
*** 2074,2079 ****
--- 2141,2151 ----
  
  	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
  
+ 	if (sc->an_flash_buffer) {
+ 		free(sc->an_flash_buffer, M_DEVBUF);
+ 		sc->an_flash_buffer = NULL;
+ 	}
+ 
  	AN_UNLOCK(sc);
  
  	return;
***************
*** 2177,2187 ****
   * strength in MAC (src) indexed cache.
   */
  static void
! an_cache_store (sc, eh, m, rx_quality)
  	struct an_softc *sc;
  	struct ether_header *eh;
  	struct mbuf *m;
! 	unsigned short rx_quality;
  {
  	struct ip *ip = 0;
  	int i;
--- 2249,2260 ----
   * strength in MAC (src) indexed cache.
   */
  static void
! an_cache_store (sc, eh, m, rx_rssi, rx_quality)
  	struct an_softc *sc;
  	struct ether_header *eh;
  	struct mbuf *m;
! 	u_int8_t rx_rssi;
! 	u_int8_t rx_quality;
  {
  	struct ip *ip = 0;
  	int i;
***************
*** 2213,2219 ****
  
  #ifdef SIGDEBUG
  	printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
! 	    rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
  #endif
  
  	/* find the ip header.  we want to store the ip_src
--- 2286,2292 ----
  
  #ifdef SIGDEBUG
  	printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
! 		rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
  #endif
  
  	/* find the ip header.  we want to store the ip_src
***************
*** 2290,2296 ****
  	}
  	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
  
! 	sc->an_sigcache[cache_slot].signal = rx_quality;
  
  	return;
  }
--- 2363,2403 ----
  	}
  	bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc,  6);
  
! 
! 	switch (an_cache_mode) {
! 	case DBM:
! 		if (sc->an_have_rssimap) {
! 			sc->an_sigcache[cache_slot].signal = 
! 				- sc->an_rssimap.an_entries[rx_rssi].an_rss_dbm;
! 			sc->an_sigcache[cache_slot].quality = 
! 				- sc->an_rssimap.an_entries[rx_quality].an_rss_dbm;
! 		} else {
! 			sc->an_sigcache[cache_slot].signal = rx_rssi - 100;
! 			sc->an_sigcache[cache_slot].quality = rx_quality - 100;
! 		}
! 		break;
! 	case PERCENT:
! 		if (sc->an_have_rssimap) {
! 			sc->an_sigcache[cache_slot].signal = 
! 				sc->an_rssimap.an_entries[rx_rssi].an_rss_pct;
! 			sc->an_sigcache[cache_slot].quality = 
! 				sc->an_rssimap.an_entries[rx_quality].an_rss_pct;
! 		} else {
! 			if (rx_rssi > 100)
! 				rx_rssi = 100;
! 			if (rx_quality > 100)
! 				rx_quality = 100;
! 			sc->an_sigcache[cache_slot].signal = rx_rssi;
! 			sc->an_sigcache[cache_slot].quality = rx_quality;
! 		}
! 		break;
! 	case RAW:
! 		sc->an_sigcache[cache_slot].signal = rx_rssi;
! 		sc->an_sigcache[cache_slot].quality = rx_quality;
! 		break;
! 	}
! 
! 	sc->an_sigcache[cache_slot].noise = 0;
  
  	return;
  }
***************
*** 2554,2560 ****
   * Linux driver
   */
  
! #define FLASH_DELAY(x) tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
  
  static int
  unstickbusy(ifp)
--- 2661,2669 ----
   * Linux driver
   */
  
! #define FLASH_DELAY(x)	tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
! #define FLASH_COMMAND	0x7e7e
! #define FLASH_SIZE	32 * 1024
  
  static int
  unstickbusy(ifp)
***************
*** 2632,2638 ****
  /*
   * STEP 2) Put the card in legendary flash mode
   */
- #define FLASH_COMMAND  0x7e7e
  
  static int
  setflashmode(ifp)
--- 2741,2746 ----
***************
*** 2762,2770 ****
   * the card
   */
  
- static char     flashbuffer[1024 * 38];	/* RAW Buffer for flash will be
- 					 * dynamic next */
- 
  static int
  flashputbuf(ifp)
  	struct ifnet   *ifp;
--- 2870,2875 ----
***************
*** 2775,2786 ****
  
  	/* Write stuff */
  
! 	bufp = (unsigned short *)flashbuffer;
  
  	CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
  	CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
  
! 	for (nwords = 0; nwords != 16384; nwords++) {
  		CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
  	}
  
--- 2880,2891 ----
  
  	/* Write stuff */
  
! 	bufp = sc->an_flash_buffer;
  
  	CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
  	CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
  
! 	for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
  		CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
  	}
  
***************
*** 2828,2834 ****
  		return cmdreset(ifp);
  		break;
  	case AIROFLSHSTFL:
! 		return setflashmode(ifp);
  		break;
  	case AIROFLSHGCHR:	/* Get char from aux */
  		copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
--- 2933,2947 ----
  		return cmdreset(ifp);
  		break;
  	case AIROFLSHSTFL:
! 		if (sc->an_flash_buffer) {
! 			free(sc->an_flash_buffer, M_DEVBUF);
! 			sc->an_flash_buffer = NULL;
! 		}
! 		sc->an_flash_buffer = malloc(FLASH_SIZE, M_DEVBUF, M_WAITOK);
! 		if (sc->an_flash_buffer)
! 			return setflashmode(ifp);
! 		else
! 			return ENOBUFS;
  		break;
  	case AIROFLSHGCHR:	/* Get char from aux */
  		copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
***************
*** 2847,2858 ****
  			return 0;
  		break;
  	case AIROFLPUTBUF:	/* Send 32k to card */
! 		if (l_ioctl->len > sizeof(flashbuffer)) {
  			printf("an%d: Buffer to big, %x %x\n", sc->an_unit,
! 			       l_ioctl->len, sizeof(flashbuffer));
  			return -EINVAL;
  		}
! 		copyin(l_ioctl->data, &flashbuffer, l_ioctl->len);
  
  		if ((status = flashputbuf(ifp)) != 0)
  			return -EIO;
--- 2960,2971 ----
  			return 0;
  		break;
  	case AIROFLPUTBUF:	/* Send 32k to card */
! 		if (l_ioctl->len > FLASH_SIZE) {
  			printf("an%d: Buffer to big, %x %x\n", sc->an_unit,
! 			       l_ioctl->len, FLASH_SIZE);
  			return -EINVAL;
  		}
! 		copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
  
  		if ((status = flashputbuf(ifp)) != 0)
  			return -EIO;
Index: sys/dev/an/if_an_pci.c
===================================================================
RCS file: /cvs/src/sys/dev/an/if_an_pci.c,v
retrieving revision 1.13
diff -c -r1.13 if_an_pci.c
*** sys/dev/an/if_an_pci.c	20 Mar 2002 02:02:34 -0000	1.13
--- sys/dev/an/if_an_pci.c	25 Oct 2002 03:33:33 -0000
***************
*** 101,106 ****
--- 101,107 ----
  #define AIRONET_DEVICEID_4500	0x4500
  #define AIRONET_DEVICEID_4800	0x4800
  #define AIRONET_DEVICEID_4xxx	0x0001
+ #define AIRONET_DEVICEID_MPI350	0xA504
  #define AN_PCI_PLX_LOIO		0x14	/* PLX chip iobase */
  #define AN_PCI_LOIO		0x18	/* Aironet iobase */
  
***************
*** 132,137 ****
--- 133,144 ----
  		t++;
  	}
  
+ 	if (pci_get_vendor(dev) == AIRONET_VENDORID &&
+ 	    pci_get_device(dev) == AIRONET_DEVICEID_MPI350) {
+ 			device_set_desc(dev, "Cisco Aironet MPI350");
+ 			return(0);
+ 	}
+ 
  	return(ENXIO);
  }
  
***************
*** 148,168 ****
  	flags = device_get_flags(dev);
  	bzero(sc, sizeof(struct an_softc));
  
! 	/*
! 	 * Map control/status registers.
!  	 */
! 	command = pci_read_config(dev, PCIR_COMMAND, 4);
! 	command |= PCIM_CMD_PORTEN;
! 	pci_write_config(dev, PCIR_COMMAND, command, 4);
! 	command = pci_read_config(dev, PCIR_COMMAND, 4);
! 
! 	if (!(command & PCIM_CMD_PORTEN)) {
! 		printf("an%d: failed to enable I/O ports!\n", unit);
! 		error = ENXIO;
! 		goto fail;
  	}
- 
- 	sc->port_rid = AN_PCI_LOIO;
  	error = an_alloc_port(dev, sc->port_rid, 1);
  
  	if (error) {
--- 155,178 ----
  	flags = device_get_flags(dev);
  	bzero(sc, sizeof(struct an_softc));
  
! 	if (pci_get_device(dev) == AIRONET_DEVICEID_MPI350) {
! 		sc->port_rid = PCIR_MAPS;
! 	} else {
! 		/*
! 		 * Map control/status registers.
! 	 	 */
! 		command = pci_read_config(dev, PCIR_COMMAND, 4);
! 		command |= PCIM_CMD_PORTEN;
! 		pci_write_config(dev, PCIR_COMMAND, command, 4);
! 		command = pci_read_config(dev, PCIR_COMMAND, 4);
! 
! 		if (!(command & PCIM_CMD_PORTEN)) {
! 			printf("an%d: failed to enable I/O ports!\n", unit);
! 			error = ENXIO;
! 			goto fail;
! 		}
! 		sc->port_rid = AN_PCI_LOIO;
  	}
  	error = an_alloc_port(dev, sc->port_rid, 1);
  
  	if (error) {
Index: sys/dev/an/if_anreg.h
===================================================================
RCS file: /cvs/src/sys/dev/an/if_anreg.h,v
retrieving revision 1.13
diff -c -r1.13 if_anreg.h
*** sys/dev/an/if_anreg.h	23 Sep 2002 18:54:29 -0000	1.13
--- sys/dev/an/if_anreg.h	25 Oct 2002 03:33:33 -0000
***************
*** 354,359 ****
--- 354,361 ----
  	int			an_sigitems;
  	struct an_sigcache	an_sigcache[MAXANCACHE];
  	int			an_nextitem;
+ 	int			an_have_rssimap;
+ 	struct an_ltv_rssi_map	an_rssimap;
  #endif
  	struct callout_handle	an_stat_ch;
  	struct mtx		an_mtx;
***************
*** 363,368 ****
--- 365,371 ----
  	int		        an_was_monitor;
  	u_char			buf_802_11[MCLBYTES];
  	struct an_req		areq;
+ 	unsigned short*		an_flash_buffer;
  };
  
  #define AN_LOCK(_sc)		mtx_lock(&(_sc)->an_mtx)
Index: usr.sbin/ancontrol/ancontrol.8
===================================================================
RCS file: /cvs/src/usr.sbin/ancontrol/ancontrol.8,v
retrieving revision 1.23
diff -c -r1.23 ancontrol.8
*** usr.sbin/ancontrol/ancontrol.8	14 Jul 2002 14:42:17 -0000	1.23
--- usr.sbin/ancontrol/ancontrol.8	25 Oct 2002 03:33:33 -0000
***************
*** 50,55 ****
--- 50,61 ----
  .Nm
  .Fl i Ar iface Fl C
  .Nm
+ .Fl i Ar iface Fl Q
+ .Nm
+ .Fl i Ar iface Fl Z
+ .Nm
+ .Fl i Ar iface Fl R
+ .Nm
  .Fl i Ar iface Fl t Cm 0 Ns - Ns Cm 4
  .Nm
  .Fl i Ar iface Fl s Cm 0 Ns - Ns Cm 3
***************
*** 190,195 ****
--- 196,216 ----
  This shows the current operation mode,
  receive mode, MAC address, power save settings, various timing settings,
  channel selection, diversity, transmit power and transmit speed.
+ .It Fl i Ar iface Fl Q
+ Display the cached signal strength information maintained by the
+ .Xr an 4
+ driver.
+ The driver retains information about signal strength and
+ noise level for packets received from different hosts.
+ The signal strength and noise level values are displayed in units of dBms by
+ default.   The sysctl machdep.an_cache_mode can be set to raw, dbm or per.
+ XXX needs work.
+ .It Fl i Ar iface Fl Z
+ Clear the signal strength cache maintained internally by the
+ .Xr an 4
+ driver.
+ .It Fl i Ar iface Fl R
+ Display RSSI map that converts from the RSSI index to percent and dBm.
  .It Fl i Ar iface Fl t Cm 0 Ns - Ns Cm 4
  Select transmit speed.
  The available settings are as follows:
Index: usr.sbin/ancontrol/ancontrol.c
===================================================================
RCS file: /cvs/src/usr.sbin/ancontrol/ancontrol.c,v
retrieving revision 1.18
diff -c -r1.18 ancontrol.c
*** usr.sbin/ancontrol/ancontrol.c	11 Jul 2002 18:20:49 -0000	1.18
--- usr.sbin/ancontrol/ancontrol.c	25 Oct 2002 03:33:33 -0000
***************
*** 58,65 ****
  #include <errno.h>
  #include <err.h>
  #include <md4.h>
  
! static void an_getval(const char *, struct an_req *);
  static void an_setval(const char *, struct an_req *);
  static void an_printwords(u_int16_t *, int);
  static void an_printspeeds(u_int8_t*, int);
--- 58,66 ----
  #include <errno.h>
  #include <err.h>
  #include <md4.h>
+ #include <ctype.h>
  
! static int an_getval(const char *, struct an_req *);
  static void an_setval(const char *, struct an_req *);
  static void an_printwords(u_int16_t *, int);
  static void an_printspeeds(u_int8_t*, int);
***************
*** 86,91 ****
--- 87,93 ----
  static void an_setkeys(const char *, char *, int);
  static void an_enable_tx_key(const char *, char *);
  static void an_enable_leap_mode(const char *, char *);
+ static void an_dumprssimap(const char *);
  static void usage(char *);
  int main(int, char **);
  
***************
*** 131,142 ****
  #define ACT_SET_MONITOR_MODE 37
  #define ACT_SET_LEAP_MODE 38
  
! static void an_getval(iface, areq)
  	const char		*iface;
  	struct an_req		*areq;
  {
  	struct ifreq		ifr;
! 	int			s;
  
  	bzero((char *)&ifr, sizeof(ifr));
  
--- 133,146 ----
  #define ACT_SET_MONITOR_MODE 37
  #define ACT_SET_LEAP_MODE 38
  
! #define ACT_DUMPRSSIMAP 39
! 
! static int an_getval(iface, areq)
  	const char		*iface;
  	struct an_req		*areq;
  {
  	struct ifreq		ifr;
! 	int			s, okay = 1;
  
  	bzero((char *)&ifr, sizeof(ifr));
  
***************
*** 148,159 ****
  	if (s == -1)
  		err(1, "socket");
  
! 	if (ioctl(s, SIOCGAIRONET, &ifr) == -1)
  		err(1, "SIOCGAIRONET");
  
  	close(s);
  
! 	return;
  }
  
  static void an_setval(iface, areq)
--- 152,165 ----
  	if (s == -1)
  		err(1, "socket");
  
! 	if (ioctl(s, SIOCGAIRONET, &ifr) == -1) {
! 		okay = 0;
  		err(1, "SIOCGAIRONET");
+ 	}
  
  	close(s);
  
! 	return okay;
  }
  
  static void an_setval(iface, areq)
***************
*** 260,265 ****
--- 266,286 ----
  {
  	struct an_ltv_status	*sts;
  	struct an_req		areq;
+ 	struct an_ltv_rssi_map	an_rssimap;
+ 	int rssimap_valid = 0;
+ 
+ 	/*
+ 	 * Try to get RSSI to percent and dBM table
+ 	 */
+ 
+ 	an_rssimap.an_len = sizeof(an_rssimap);
+ 	an_rssimap.an_type = AN_RID_RSSI_MAP;
+ 	rssimap_valid = an_getval(iface, (struct an_req*)&an_rssimap);	
+ 
+ 	if (rssimap_valid)
+ 		printf("RSSI table:\t\t[ present ]\n");
+ 	else
+ 		printf("RSSI table:\t\t[ not available ]\n");
  
  	areq.an_len = sizeof(areq);
  	areq.an_type = AN_RID_STATUS;
***************
*** 288,297 ****
  	printf("]\n");
  	printf("Error code:\t\t");
  	an_printhex((char *)&sts->an_errcode, 1);
! 	printf("\nSignal quality:\t\t");
! 	an_printhex((char *)&sts->an_cur_signal_quality, 1);
! 	printf("\nSignal strength:\t[ %d%% ]",sts->an_normalized_rssi);
! 	printf("\nMax Noise:\t\t[ %d%% ]",sts->an_avg_noise_prev_min);
  	/*
  	 * XXX: This uses the old definition of the rate field (units of
  	 * 500kbps).  Technically the new definition is that this field
--- 309,330 ----
  	printf("]\n");
  	printf("Error code:\t\t");
  	an_printhex((char *)&sts->an_errcode, 1);
! 	if (rssimap_valid)
! 		printf("\nSignal strength:\t[ %d%% ]",
! 		    an_rssimap.an_entries[
! 			sts->an_normalized_strength].an_rss_pct);
! 	else 
! 		printf("\nSignal strength:\t[ %d%% ]",
! 		    sts->an_normalized_strength);
! 	printf("\nAverage Noise:\t\t[ %d%% ]",sts->an_avg_noise_prev_min_pc);
! 	if (rssimap_valid)
! 		printf("\nSignal quality:\t\t[ %d%% ]", 
! 		    an_rssimap.an_entries[
! 			sts->an_cur_signal_quality].an_rss_pct);
! 	else 
! 		printf("\nSignal quality:\t\t[ %d ]", 
! 		    sts->an_cur_signal_quality);
! 	printf("\nMax Noise:\t\t[ %d%% ]",sts->an_max_noise_prev_min_pc);
  	/*
  	 * XXX: This uses the old definition of the rate field (units of
  	 * 500kbps).  Technically the new definition is that this field
***************
*** 378,384 ****
  	printf("\nSupported speeds:\t");
  	an_printspeeds(caps->an_rates, 8);
  	printf("\nRX Diversity:\t\t[ ");
! 	if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
--- 411,419 ----
  	printf("\nSupported speeds:\t");
  	an_printspeeds(caps->an_rates, 8);
  	printf("\nRX Diversity:\t\t[ ");
! 	if (caps->an_rx_diversity == AN_DIVERSITY_FACTORY_DEFAULT)
! 		printf("factory default");
! 	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
***************
*** 386,396 ****
  		printf("antenna 1 and 2");
  	printf(" ]");
  	printf("\nTX Diversity:\t\t[ ");
! 	if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
! 	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
! 	else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
  		printf("antenna 1 and 2");
  	printf(" ]");
  	printf("\nSupported power levels:\t");
--- 421,433 ----
  		printf("antenna 1 and 2");
  	printf(" ]");
  	printf("\nTX Diversity:\t\t[ ");
! 	if (caps->an_tx_diversity == AN_DIVERSITY_FACTORY_DEFAULT)
! 		printf("factory default");
! 	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
! 	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
! 	else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2)
  		printf("antenna 1 and 2");
  	printf(" ]");
  	printf("\nSupported power levels:\t");
***************
*** 786,792 ****
  	printf(" ]");
  	printf("\nRX Diversity:\t\t\t\t[ ");
  	diversity = cfg->an_diversity & 0xFF;
! 	if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
--- 823,831 ----
  	printf(" ]");
  	printf("\nRX Diversity:\t\t\t\t[ ");
  	diversity = cfg->an_diversity & 0xFF;
! 	if (diversity == AN_DIVERSITY_FACTORY_DEFAULT)
! 		printf("factory default");
! 	else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
***************
*** 795,801 ****
  	printf(" ]");
  	printf("\nTX Diversity:\t\t\t\t[ ");
  	diversity = (cfg->an_diversity >> 8) & 0xFF;
! 	if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
--- 834,842 ----
  	printf(" ]");
  	printf("\nTX Diversity:\t\t\t\t[ ");
  	diversity = (cfg->an_diversity >> 8) & 0xFF;
! 	if (diversity == AN_DIVERSITY_FACTORY_DEFAULT)
! 		printf("factory default");
! 	else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY)
  		printf("antenna 1 only");
  	else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY)
  		printf("antenna 2 only");
***************
*** 828,833 ****
--- 869,902 ----
  	return;
  }
  
+ static void an_dumprssimap(iface)
+ 	const char		*iface;
+ {
+ 	struct an_ltv_rssi_map	*rssi;
+ 	struct an_req		areq;
+ 	int                     i;
+ 
+ 	areq.an_len = sizeof(areq);
+ 	areq.an_type = AN_RID_RSSI_MAP;
+ 
+ 	an_getval(iface, &areq);
+ 
+ 	rssi = (struct an_ltv_rssi_map *)&areq;
+ 
+ 	printf("idx\tpct\t dBm\n");
+ 
+ 	for (i = 0; i < 0xFF; i++) {
+ 		/* 
+ 		 * negate the dBm value: it's the only way the power 
+ 		 * level makes sense 
+ 		 */
+ 		printf("%3d\t%3d\t%4d\n", i, 
+ 			rssi->an_entries[i].an_rss_pct,
+ 			- rssi->an_entries[i].an_rss_dbm);
+ 	}
+ 
+ 	return;
+ }
  
  static void usage(p)
  	char			*p;
***************
*** 838,843 ****
--- 907,913 ----
  	fprintf(stderr, "\t%s -i iface -I (show NIC capabilities)\n", p);
  	fprintf(stderr, "\t%s -i iface -T (show stats counters)\n", p);
  	fprintf(stderr, "\t%s -i iface -C (show current config)\n", p);
+ 	fprintf(stderr, "\t%s -i iface -R (show RSSI map)\n", p);
  	fprintf(stderr, "\t%s -i iface -t 0-4 (set TX speed)\n", p);
  	fprintf(stderr, "\t%s -i iface -s 0-3 (set power save mode)\n", p);
  	fprintf(stderr, "\t%s -i iface [-v 1-4] -a AP (specify AP)\n", p);
***************
*** 924,935 ****
  			errx(1, "bad diversity setting: %d", diversity);
  			break;
  		}
! 		if (atoi(arg) == ACT_SET_DIVERSITY_RX) {
! 			cfg->an_diversity &= 0x00FF;
! 			cfg->an_diversity |= (diversity << 8);
! 		} else {
  			cfg->an_diversity &= 0xFF00;
  			cfg->an_diversity |= diversity;
  		}
  		break;
  	case ACT_SET_TXPWR:
--- 994,1005 ----
  			errx(1, "bad diversity setting: %d", diversity);
  			break;
  		}
! 		if (act == ACT_SET_DIVERSITY_RX) {
  			cfg->an_diversity &= 0xFF00;
  			cfg->an_diversity |= diversity;
+ 		} else {
+ 			cfg->an_diversity &= 0x00FF;
+ 			cfg->an_diversity |= (diversity << 8);
  		}
  		break;
  	case ACT_SET_TXPWR:
***************
*** 1519,1525 ****
  	opterr = 1;
  
  	while ((ch = getopt(argc, argv,
! 	    "ANISCTht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZM:L:")) != -1) {
  		switch(ch) {
  		case 'Z':
  #ifdef ANCACHE
--- 1589,1595 ----
  	opterr = 1;
  
  	while ((ch = getopt(argc, argv,
! 	    "ANISCTRht:a:e:o:s:n:v:d:j:b:c:r:p:w:m:l:k:K:W:QZM:L:")) != -1) {
  		switch(ch) {
  		case 'Z':
  #ifdef ANCACHE
***************
*** 1553,1558 ****
--- 1623,1631 ----
  		case 'C':
  			act = ACT_DUMPCONFIG;
  			break;
+ 		case 'R':
+ 			act = ACT_DUMPRSSIMAP;
+ 			break;
  		case 't':
  			act = ACT_SET_TXRATE;
  			arg = optarg;
***************
*** 1605,1613 ****
  				act = ACT_SET_DIVERSITY_TX;
  				break;
  			default:
! 				errx(1, "must specift RX or TX diversity");
  				break;
  			}
  			arg = optarg;
  			break;
  		case 'j':
--- 1678,1690 ----
  				act = ACT_SET_DIVERSITY_TX;
  				break;
  			default:
! 				errx(1, "must specify RX or TX diversity");
  				break;
  			}
+ 			if (!isdigit(*optarg)) {
+ 				errx(1, "%s is not numeric", optarg);
+ 				exit(1);
+ 			}
  			arg = optarg;
  			break;
  		case 'j':
***************
*** 1717,1722 ****
--- 1794,1802 ----
  		break;
  	case ACT_DUMPAP:
  		an_dumpap(iface);
+ 		break;
+ 	case ACT_DUMPRSSIMAP:
+ 		an_dumprssimap(iface);
  		break;
  	case ACT_SET_SSID1:
  	case ACT_SET_SSID2:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200210250342.g9P3gsu86966>