summaryrefslogtreecommitdiffstats
path: root/sys/dev/an
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2002-12-29 19:22:07 +0000
committerambrisko <ambrisko@FreeBSD.org>2002-12-29 19:22:07 +0000
commita533b45945ae54fcc48ff5129510549f213638c3 (patch)
treea6fad0ec9730bbbd04d5904f5219a75ce5c7cabb /sys/dev/an
parent1ec5f03e6d974f74f3960788e6bf478e5cce3bf1 (diff)
downloadFreeBSD-src-a533b45945ae54fcc48ff5129510549f213638c3.zip
FreeBSD-src-a533b45945ae54fcc48ff5129510549f213638c3.tar.gz
Add support for MPI-350 the mini-pci Cisco Aironet card. This needs more
work. The interface was gleaned from the Linux driver. Currently only one RX & one TX buffer are used. Firmware support is not tested so for the MPI-350 so it is disabled. Signal cache and monitor mode are not supported yet. Signal cache is not supported since in encapsulation mode ethernet frames are returned by the chip. LAN monitor mode support will be added shortly. Thanks to Warner for the MPI-350 card he sent me. Add support for RSSI map from PR kern/32880 which was incomplete. Enhanced with the ability to select the cache mode of raw, dbm or per-cent. Clean up Signal/Noise/Quality structures and units with help from Marco Molteni. Change flash to use a malloc'ed buffer when needed. PR: kern/32880 Submitted by: Douglas S. J. De Couto decouto@pdos.lcs.mit.edu, Marco Molteni MFC: 3 weeks
Diffstat (limited to 'sys/dev/an')
-rw-r--r--sys/dev/an/if_aironet_ieee.h44
-rw-r--r--sys/dev/an/if_an.c1337
-rw-r--r--sys/dev/an/if_an_pccard.c1
-rw-r--r--sys/dev/an/if_an_pci.c84
-rw-r--r--sys/dev/an/if_anreg.h165
5 files changed, 1301 insertions, 330 deletions
diff --git a/sys/dev/an/if_aironet_ieee.h b/sys/dev/an/if_aironet_ieee.h
index cc0e8a2..2a6e79e 100644
--- a/sys/dev/an/if_aironet_ieee.h
+++ b/sys/dev/an/if_aironet_ieee.h
@@ -132,6 +132,25 @@ struct an_sigcache {
};
#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,6 +354,7 @@ struct an_ltv_genconfig {
#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,6 +523,16 @@ struct an_ltv_radioinfo {
/* ??? */
};
+/*
+ * 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,7 +550,7 @@ struct an_ltv_status {
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_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,12 +571,15 @@ struct an_ltv_status {
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_normalized_strength; /* 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_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,6 +676,7 @@ struct an_ltv_leap_password {
#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
diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c
index 3dccf07..0a87b3c 100644
--- a/sys/dev/an/if_an.c
+++ b/sys/dev/an/if_an.c
@@ -96,8 +96,9 @@
#include <sys/socket.h>
#ifdef ANCACHE
#include <sys/syslog.h>
-#include <sys/sysctl.h>
#endif
+#include <sys/sysctl.h>
+#include <machine/clock.h> /* for DELAY */
#include <sys/module.h>
#include <sys/sysctl.h>
@@ -107,6 +108,7 @@
#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>
@@ -137,6 +139,7 @@ static const char rcsid[] =
/* These are global because we need them in sys/pci/if_an_p.c. */
static void an_reset (struct an_softc *);
+static int an_init_mpi350_desc (struct an_softc *);
static int an_ioctl (struct ifnet *, u_long, caddr_t);
static void an_init (void *);
static int an_init_tx_ring (struct an_softc *);
@@ -147,17 +150,24 @@ static void an_txeof (struct an_softc *, int);
static void an_promisc (struct an_softc *, int);
static int an_cmd (struct an_softc *, int, int);
+static int an_cmd_struct (struct an_softc *, struct an_command *,
+ struct an_reply *);
static int an_read_record (struct an_softc *, struct an_ltv_gen *);
static int an_write_record (struct an_softc *, struct an_ltv_gen *);
+static void an_kick (struct an_softc *);
static int an_read_data (struct an_softc *, int, int, caddr_t, int);
static int an_write_data (struct an_softc *, int, int, caddr_t, int);
static int an_seek (struct an_softc *, int, int, int);
static int an_alloc_nicmem (struct an_softc *, int, int *);
+static int an_dma_malloc (struct an_softc *, bus_size_t,
+ struct an_dma_alloc *, int);
+static void an_dma_free (struct an_softc *, struct an_dma_alloc *);
+static void an_dma_malloc_cb (void *, bus_dma_segment_t *, int, int);
static void an_stats_update (void *);
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);
+ struct mbuf *, u_int8_t, u_int8_t);
#endif
/* function definitions for use with the Cisco's Linux configuration
@@ -184,10 +194,17 @@ static int an_media_change (struct ifnet *);
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");
/* XXX violate ethernet/netgraph callback hooks */
@@ -201,17 +218,16 @@ sysctl_an_dump(SYSCTL_HANDLER_ARGS)
char *s = an_conf;
last = an_dump;
- bzero(an_conf, sizeof(an_conf));
switch (an_dump) {
case 0:
- strcat(an_conf, "off");
+ strcpy(an_conf, "off");
break;
case 1:
- strcat(an_conf, "type");
+ strcpy(an_conf, "type");
break;
case 2:
- strcat(an_conf, "dump");
+ strcpy(an_conf, "dump");
break;
default:
snprintf(an_conf, 5, "%x", an_dump);
@@ -220,7 +236,7 @@ sysctl_an_dump(SYSCTL_HANDLER_ARGS)
error = sysctl_handle_string(oidp, an_conf, sizeof(an_conf), req);
- if (strncmp(an_conf,"off", 4) == 0) {
+ if (strncmp(an_conf,"off", 3) == 0) {
an_dump = 0;
}
if (strncmp(an_conf,"dump", 4) == 0) {
@@ -251,6 +267,44 @@ sysctl_an_dump(SYSCTL_HANDLER_ARGS)
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
@@ -288,10 +342,11 @@ an_probe(dev)
ssid.an_type = AN_RID_SSIDLIST;
/* Make sure interrupts are disabled. */
- CSR_WRITE_2(sc, AN_INT_EN, 0);
- CSR_WRITE_2(sc, AN_EVENT_ACK, 0xFFFF);
+ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), 0xFFFF);
an_reset(sc);
+ /* No need for an_init_mpi350_desc since it will be done in attach */
if (an_cmd(sc, AN_CMD_READCFG, 0))
return(0);
@@ -330,6 +385,46 @@ an_alloc_port(dev, rid, size)
}
/*
+ * Allocate a memory resource with the given resource id.
+ */
+int an_alloc_memory(device_t dev, int rid, int size)
+{
+ struct an_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0ul, ~0ul, size, RF_ACTIVE);
+ if (res) {
+ sc->mem_rid = rid;
+ sc->mem_res = res;
+ sc->mem_used = size;
+ return (0);
+ } else {
+ return (ENOENT);
+ }
+}
+
+/*
+ * Allocate a auxilary memory resource with the given resource id.
+ */
+int an_alloc_aux_memory(device_t dev, int rid, int size)
+{
+ struct an_softc *sc = device_get_softc(dev);
+ struct resource *res;
+
+ res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0ul, ~0ul, size, RF_ACTIVE);
+ if (res) {
+ sc->mem_aux_rid = rid;
+ sc->mem_aux_res = res;
+ sc->mem_aux_used = size;
+ return (0);
+ } else {
+ return (ENOENT);
+ }
+}
+
+/*
* Allocate an irq resource with the given resource id.
*/
int
@@ -352,6 +447,69 @@ an_alloc_irq(dev, rid, flags)
}
}
+static void
+an_dma_malloc_cb(arg, segs, nseg, error)
+ void *arg;
+ bus_dma_segment_t *segs;
+ int nseg;
+ int error;
+{
+ bus_addr_t *paddr = (bus_addr_t*) arg;
+ *paddr = segs->ds_addr;
+}
+
+/*
+ * Alloc DMA memory and set the pointer to it
+ */
+static int
+an_dma_malloc(sc, size, dma, mapflags)
+ struct an_softc *sc;
+ bus_size_t size;
+ struct an_dma_alloc *dma;
+ int mapflags;
+{
+ int r;
+
+ r = bus_dmamap_create(sc->an_dtag, BUS_DMA_NOWAIT, &dma->an_dma_map);
+ if (r != 0)
+ goto fail_0;
+
+ r = bus_dmamem_alloc(sc->an_dtag, (void**) &dma->an_dma_vaddr,
+ BUS_DMA_NOWAIT, &dma->an_dma_map);
+ if (r != 0)
+ goto fail_1;
+
+ r = bus_dmamap_load(sc->an_dtag, dma->an_dma_map, dma->an_dma_vaddr,
+ size,
+ an_dma_malloc_cb,
+ &dma->an_dma_paddr,
+ mapflags | BUS_DMA_NOWAIT);
+ if (r != 0)
+ goto fail_2;
+
+ dma->an_dma_size = size;
+ return (0);
+
+fail_2:
+ bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
+fail_1:
+ bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
+fail_0:
+ bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
+ dma->an_dma_map = NULL;
+ return (r);
+}
+
+static void
+an_dma_free(sc, dma)
+ struct an_softc *sc;
+ struct an_dma_alloc *dma;
+{
+ bus_dmamap_unload(sc->an_dtag, dma->an_dma_map);
+ bus_dmamem_free(sc->an_dtag, dma->an_dma_vaddr, dma->an_dma_map);
+ bus_dmamap_destroy(sc->an_dtag, dma->an_dma_map);
+}
+
/*
* Release all resources
*/
@@ -360,17 +518,152 @@ an_release_resources(dev)
device_t dev;
{
struct an_softc *sc = device_get_softc(dev);
+ int i;
if (sc->port_res) {
bus_release_resource(dev, SYS_RES_IOPORT,
sc->port_rid, sc->port_res);
sc->port_res = 0;
}
+ if (sc->mem_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->mem_rid, sc->mem_res);
+ sc->mem_res = 0;
+ }
+ if (sc->mem_aux_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->mem_aux_rid, sc->mem_aux_res);
+ sc->mem_aux_res = 0;
+ }
if (sc->irq_res) {
bus_release_resource(dev, SYS_RES_IRQ,
sc->irq_rid, sc->irq_res);
sc->irq_res = 0;
}
+ if (sc->an_rid_buffer.an_dma_paddr) {
+ an_dma_free(sc, &sc->an_rid_buffer);
+ }
+ for (i = 0; i < AN_MAX_RX_DESC; i++)
+ if (sc->an_rx_buffer[i].an_dma_paddr) {
+ an_dma_free(sc, &sc->an_rx_buffer[i]);
+ }
+ for (i = 0; i < AN_MAX_TX_DESC; i++)
+ if (sc->an_tx_buffer[i].an_dma_paddr) {
+ an_dma_free(sc, &sc->an_tx_buffer[i]);
+ }
+ if (sc->an_dtag) {
+ bus_dma_tag_destroy(sc->an_dtag);
+ }
+
+}
+
+int
+an_init_mpi350_desc(sc)
+ struct an_softc *sc;
+{
+ struct an_command cmd_struct;
+ struct an_reply reply;
+ struct an_card_rid_desc an_rid_desc;
+ struct an_card_rx_desc an_rx_desc;
+ struct an_card_tx_desc an_tx_desc;
+ int i, desc;
+
+ if(!sc->an_rid_buffer.an_dma_paddr)
+ an_dma_malloc(sc, AN_RID_BUFFER_SIZE,
+ &sc->an_rid_buffer, 0);
+ for (i = 0; i < AN_MAX_RX_DESC; i++)
+ if(!sc->an_rx_buffer[i].an_dma_paddr)
+ an_dma_malloc(sc, AN_RX_BUFFER_SIZE,
+ &sc->an_rx_buffer[i], 0);
+ for (i = 0; i < AN_MAX_TX_DESC; i++)
+ if(!sc->an_tx_buffer[i].an_dma_paddr)
+ an_dma_malloc(sc, AN_TX_BUFFER_SIZE,
+ &sc->an_tx_buffer[i], 0);
+
+ /*
+ * Allocate RX descriptor
+ */
+ bzero(&reply,sizeof(reply));
+ cmd_struct.an_cmd = AN_CMD_ALLOC_DESC;
+ cmd_struct.an_parm0 = AN_DESCRIPTOR_RX;
+ cmd_struct.an_parm1 = AN_RX_DESC_OFFSET;
+ cmd_struct.an_parm2 = AN_MAX_RX_DESC;
+ if (an_cmd_struct(sc, &cmd_struct, &reply)) {
+ printf("an%d: failed to allocate RX descriptor\n",
+ sc->an_unit);
+ return(EIO);
+ }
+
+ for (desc = 0; desc < AN_MAX_RX_DESC; desc++) {
+ bzero(&an_rx_desc, sizeof(an_rx_desc));
+ an_rx_desc.an_valid = 1;
+ an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
+ an_rx_desc.an_done = 0;
+ an_rx_desc.an_phys = sc->an_rx_buffer[desc].an_dma_paddr;
+
+ for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc, AN_RX_DESC_OFFSET
+ + (desc * sizeof(an_rx_desc))
+ + (i * 4),
+ ((u_int32_t*)&an_rx_desc)[i]);
+ }
+
+ /*
+ * Allocate TX descriptor
+ */
+
+ bzero(&reply,sizeof(reply));
+ cmd_struct.an_cmd = AN_CMD_ALLOC_DESC;
+ cmd_struct.an_parm0 = AN_DESCRIPTOR_TX;
+ cmd_struct.an_parm1 = AN_TX_DESC_OFFSET;
+ cmd_struct.an_parm2 = AN_MAX_TX_DESC;
+ if (an_cmd_struct(sc, &cmd_struct, &reply)) {
+ printf("an%d: failed to allocate TX descriptor\n",
+ sc->an_unit);
+ return(EIO);
+ }
+
+ for (desc = 0; desc < AN_MAX_TX_DESC; desc++) {
+ bzero(&an_tx_desc, sizeof(an_tx_desc));
+ an_tx_desc.an_offset = 0;
+ an_tx_desc.an_eoc = 0;
+ an_tx_desc.an_valid = 0;
+ an_tx_desc.an_len = 0;
+ an_tx_desc.an_phys = sc->an_tx_buffer[desc].an_dma_paddr;
+
+ for (i = 0; i < sizeof(an_tx_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc, AN_TX_DESC_OFFSET
+ + (desc * sizeof(an_tx_desc))
+ + (i * 4),
+ ((u_int32_t*)&an_tx_desc)[i]);
+ }
+
+ /*
+ * Allocate RID descriptor
+ */
+
+ bzero(&reply,sizeof(reply));
+ cmd_struct.an_cmd = AN_CMD_ALLOC_DESC;
+ cmd_struct.an_parm0 = AN_DESCRIPTOR_HOSTRW;
+ cmd_struct.an_parm1 = AN_HOST_DESC_OFFSET;
+ cmd_struct.an_parm2 = 1;
+ if (an_cmd_struct(sc, &cmd_struct, &reply)) {
+ printf("an%d: failed to allocate host descriptor\n",
+ sc->an_unit);
+ return(EIO);
+ }
+
+ bzero(&an_rid_desc, sizeof(an_rid_desc));
+ an_rid_desc.an_valid = 1;
+ an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
+ an_rid_desc.an_rid = 0;
+ an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
+
+ for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
+ ((u_int32_t*)&an_rid_desc)[i]);
+
+ return(0);
}
int
@@ -380,6 +673,7 @@ an_attach(sc, unit, flags)
int flags;
{
struct ifnet *ifp = &sc->arpcom.ac_if;
+ int error;
mtx_init(&sc->an_mtx, device_get_nameunit(sc->an_dev), MTX_NETWORK_LOCK,
MTX_DEF | MTX_RECURSE);
@@ -389,9 +683,15 @@ an_attach(sc, unit, flags)
sc->an_associated = 0;
sc->an_monitor = 0;
sc->an_was_monitor = 0;
+ sc->an_flash_buffer = NULL;
/* Reset the NIC. */
an_reset(sc);
+ if(sc->mpi350) {
+ error = an_init_mpi350_desc(sc);
+ if (error)
+ return(error);
+ }
/* Load factory config */
if (an_cmd(sc, AN_CMD_READCFG, 0)) {
@@ -441,6 +741,23 @@ an_attach(sc, unit, flags)
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);
@@ -520,146 +837,252 @@ an_rxeof(sc)
struct an_rxframe rx_frame;
struct an_rxframe_802_3 rx_frame_802_3;
struct mbuf *m;
- int len, id, error = 0;
- int ieee80211_header_len;
- u_char *bpf_buf;
- u_short fc1;
+ int len, id, error = 0, i, count = 0;
+ int ieee80211_header_len;
+ u_char *bpf_buf;
+ u_short fc1;
+ struct an_card_rx_desc an_rx_desc;
+ u_int8_t *buf;
ifp = &sc->arpcom.ac_if;
- id = CSR_READ_2(sc, AN_RX_FID);
+ if (!sc->mpi350) {
+ id = CSR_READ_2(sc, AN_RX_FID);
- if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
- /* read raw 802.11 packet */
- bpf_buf = sc->buf_802_11;
-
- /* read header */
- if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
- sizeof(rx_frame))) {
- ifp->if_ierrors++;
- return;
- }
+ if (sc->an_monitor && (ifp->if_flags & IFF_PROMISC)) {
+ /* read raw 802.11 packet */
+ bpf_buf = sc->buf_802_11;
- /*
- * skip beacon by default since this increases the
- * system load a lot
- */
+ /* read header */
+ if (an_read_data(sc, id, 0x0, (caddr_t)&rx_frame,
+ sizeof(rx_frame))) {
+ ifp->if_ierrors++;
+ return;
+ }
- if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
- (rx_frame.an_frame_ctl & IEEE80211_FC0_SUBTYPE_BEACON)) {
- return;
- }
+ /*
+ * skip beacon by default since this increases the
+ * system load a lot
+ */
- if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
- len = rx_frame.an_rx_payload_len
- + sizeof(rx_frame);
- /* Check for insane frame length */
- if (len > sizeof(sc->buf_802_11)) {
- printf("an%d: oversized packet received (%d, %d)\n",
- sc->an_unit, len, MCLBYTES);
- ifp->if_ierrors++;
+ if (!(sc->an_monitor & AN_MONITOR_INCLUDE_BEACON) &&
+ (rx_frame.an_frame_ctl &
+ IEEE80211_FC0_SUBTYPE_BEACON)) {
return;
}
- bcopy((char *)&rx_frame,
- bpf_buf, sizeof(rx_frame));
+ if (sc->an_monitor & AN_MONITOR_AIRONET_HEADER) {
+ len = rx_frame.an_rx_payload_len
+ + sizeof(rx_frame);
+ /* Check for insane frame length */
+ if (len > sizeof(sc->buf_802_11)) {
+ printf("an%d: oversized packet "
+ "received (%d, %d)\n",
+ sc->an_unit, len, MCLBYTES);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ bcopy((char *)&rx_frame,
+ bpf_buf, sizeof(rx_frame));
+
+ error = an_read_data(sc, id, sizeof(rx_frame),
+ (caddr_t)bpf_buf+sizeof(rx_frame),
+ rx_frame.an_rx_payload_len);
+ } else {
+ fc1=rx_frame.an_frame_ctl >> 8;
+ ieee80211_header_len =
+ sizeof(struct ieee80211_frame);
+ if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
+ (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
+ ieee80211_header_len += ETHER_ADDR_LEN;
+ }
+
+ len = rx_frame.an_rx_payload_len
+ + ieee80211_header_len;
+ /* Check for insane frame length */
+ if (len > sizeof(sc->buf_802_11)) {
+ printf("an%d: oversized packet "
+ "received (%d, %d)\n",
+ sc->an_unit, len, MCLBYTES);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ ih = (struct ieee80211_frame *)bpf_buf;
+
+ bcopy((char *)&rx_frame.an_frame_ctl,
+ (char *)ih, ieee80211_header_len);
- error = an_read_data(sc, id, sizeof(rx_frame),
- (caddr_t)bpf_buf+sizeof(rx_frame),
- rx_frame.an_rx_payload_len);
+ error = an_read_data(sc, id, sizeof(rx_frame) +
+ rx_frame.an_gaplen,
+ (caddr_t)ih +ieee80211_header_len,
+ rx_frame.an_rx_payload_len);
+ }
+ /* dump raw 802.11 packet to bpf and skip ip stack */
+ BPF_TAP(ifp, bpf_buf, len);
} else {
- fc1=rx_frame.an_frame_ctl >> 8;
- ieee80211_header_len = sizeof(struct ieee80211_frame);
- if ((fc1 & IEEE80211_FC1_DIR_TODS) &&
- (fc1 & IEEE80211_FC1_DIR_FROMDS)) {
- ieee80211_header_len += ETHER_ADDR_LEN;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ MCLGET(m, M_DONTWAIT);
+ if (!(m->m_flags & M_EXT)) {
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
}
+ m->m_pkthdr.rcvif = ifp;
+ /* Read Ethernet encapsulated packet */
- len = rx_frame.an_rx_payload_len
- + ieee80211_header_len;
+#ifdef ANCACHE
+ /* Read NIC frame header */
+ if (an_read_data(sc, id, 0, (caddr_t)&rx_frame,
+ sizeof(rx_frame))) {
+ ifp->if_ierrors++;
+ return;
+ }
+#endif
+ /* Read in the 802_3 frame header */
+ if (an_read_data(sc, id, 0x34,
+ (caddr_t)&rx_frame_802_3,
+ sizeof(rx_frame_802_3))) {
+ ifp->if_ierrors++;
+ return;
+ }
+ if (rx_frame_802_3.an_rx_802_3_status != 0) {
+ ifp->if_ierrors++;
+ return;
+ }
/* Check for insane frame length */
+ len = rx_frame_802_3.an_rx_802_3_payload_len;
if (len > sizeof(sc->buf_802_11)) {
- printf("an%d: oversized packet received (%d, %d)\n",
+ printf("an%d: oversized packet "
+ "received (%d, %d)\n",
sc->an_unit, len, MCLBYTES);
ifp->if_ierrors++;
return;
}
+ m->m_pkthdr.len = m->m_len =
+ rx_frame_802_3.an_rx_802_3_payload_len + 12;
- ih = (struct ieee80211_frame *)bpf_buf;
+ eh = mtod(m, struct ether_header *);
- bcopy((char *)&rx_frame.an_frame_ctl,
- (char *)ih, ieee80211_header_len);
+ bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
+ (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
+ bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
+ (char *)&eh->ether_shost, ETHER_ADDR_LEN);
- error = an_read_data(sc, id, sizeof(rx_frame) +
- rx_frame.an_gaplen,
- (caddr_t)ih +ieee80211_header_len,
- rx_frame.an_rx_payload_len);
- }
- /* dump raw 802.11 packet to bpf and skip ip stack */
- BPF_TAP(ifp, bpf_buf, len);
- } else {
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL) {
- ifp->if_ierrors++;
- return;
- }
- MCLGET(m, M_DONTWAIT);
- if (!(m->m_flags & M_EXT)) {
- m_freem(m);
- ifp->if_ierrors++;
- return;
- }
- m->m_pkthdr.rcvif = ifp;
- /* Read Ethernet encapsulated packet */
+ /* in mbuf header type is just before payload */
+ error = an_read_data(sc, id, 0x44,
+ (caddr_t)&(eh->ether_type),
+ rx_frame_802_3.an_rx_802_3_payload_len);
+
+ if (error) {
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
+ }
+ ifp->if_ipackets++;
+ /* Receive packet. */
#ifdef ANCACHE
- /* Read NIC frame header */
- if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) {
- ifp->if_ierrors++;
- return;
- }
+ an_cache_store(sc, eh, m,
+ rx_frame.an_rx_signal_strength,
+ rx_frame.an_rsvd0);
#endif
- /* Read in the 802_3 frame header */
- if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3,
- sizeof(rx_frame_802_3))) {
- ifp->if_ierrors++;
- return;
+ (*ifp->if_input)(ifp, m);
}
- if (rx_frame_802_3.an_rx_802_3_status != 0) {
- ifp->if_ierrors++;
- return;
- }
- /* Check for insane frame length */
- if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
- ifp->if_ierrors++;
- return;
- }
- m->m_pkthdr.len = m->m_len =
- rx_frame_802_3.an_rx_802_3_payload_len + 12;
-
- eh = mtod(m, struct ether_header *);
-
- bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
- (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
- bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
- (char *)&eh->ether_shost, ETHER_ADDR_LEN);
- /* in mbuf header type is just before payload */
- error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
- rx_frame_802_3.an_rx_802_3_payload_len);
-
- if (error) {
- m_freem(m);
- ifp->if_ierrors++;
- return;
- }
- ifp->if_ipackets++;
+ } else { /* MPI-350 */
+ for (count = 0; count < AN_MAX_RX_DESC; count++){
+ for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
+ ((u_int32_t*)&an_rx_desc)[i]
+ = CSR_MEM_AUX_READ_4(sc,
+ AN_RX_DESC_OFFSET
+ + (count * sizeof(an_rx_desc))
+ + (i * 4));
+
+ if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
+ buf = sc->an_rx_buffer[count].an_dma_vaddr;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ MCLGET(m, M_DONTWAIT);
+ if (!(m->m_flags & M_EXT)) {
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
+ }
+ m->m_pkthdr.rcvif = ifp;
+ /* Read Ethernet encapsulated packet */
+
+ /*
+ * No ANCACHE support since we just get back
+ * an Ethernet packet no 802.11 info
+ */
+#if 0
+#ifdef ANCACHE
+ /* Read NIC frame header */
+ bcopy(buf, (caddr_t)&rx_frame,
+ sizeof(rx_frame));
+#endif
+#endif
+ /* Check for insane frame length */
+ len = an_rx_desc.an_len + 12;
+ if (len > MCLBYTES) {
+ printf("an%d: oversized packet "
+ "received (%d, %d)\n",
+ sc->an_unit, len, MCLBYTES);
+ ifp->if_ierrors++;
+ return;
+ }
- /* Receive packet. */
+ m->m_pkthdr.len = m->m_len =
+ an_rx_desc.an_len + 12;
+
+ eh = mtod(m, struct ether_header *);
+
+ bcopy(buf, (char *)eh,
+ m->m_pkthdr.len);
+
+ ifp->if_ipackets++;
+
+ /* Receive packet. */
+#if 0
#ifdef ANCACHE
- an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
+ an_cache_store(sc, eh, m,
+ rx_frame.an_rx_signal_strength,
+ rx_frame.an_rsvd0);
+#endif
#endif
- (*ifp->if_input)(ifp, m);
+ (*ifp->if_input)(ifp, m);
+
+ an_rx_desc.an_valid = 1;
+ an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
+ an_rx_desc.an_done = 0;
+ an_rx_desc.an_phys =
+ sc->an_rx_buffer[count].an_dma_paddr;
+
+ for (i = 0; i < sizeof(an_rx_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc,
+ AN_RX_DESC_OFFSET
+ + (count * sizeof(an_rx_desc))
+ + (i * 4),
+ ((u_int32_t*)&an_rx_desc)[i]);
+
+ } else {
+ printf("an%d: Didn't get valid RX packet "
+ "%x %x %d\n",
+ sc->an_unit,
+ an_rx_desc.an_done,
+ an_rx_desc.an_valid, an_rx_desc.an_len);
+ }
+ }
}
}
@@ -676,21 +1099,28 @@ an_txeof(sc, status)
ifp->if_timer = 0;
ifp->if_flags &= ~IFF_OACTIVE;
- id = CSR_READ_2(sc, AN_TX_CMP_FID);
+ if (!sc->mpi350) {
+ id = CSR_READ_2(sc, AN_TX_CMP_FID);
- if (status & AN_EV_TX_EXC) {
- ifp->if_oerrors++;
- } else
- ifp->if_opackets++;
+ if (status & AN_EV_TX_EXC) {
+ ifp->if_oerrors++;
+ } else
+ ifp->if_opackets++;
- for (i = 0; i < AN_TX_RING_CNT; i++) {
- if (id == sc->an_rdata.an_tx_ring[i]) {
- sc->an_rdata.an_tx_ring[i] = 0;
- break;
+ for (i = 0; i < AN_TX_RING_CNT; i++) {
+ if (id == sc->an_rdata.an_tx_ring[i]) {
+ sc->an_rdata.an_tx_ring[i] = 0;
+ break;
+ }
}
- }
- AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
+ AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);
+ } else { /* MPI 350 */
+ AN_INC(sc->an_rdata.an_tx_cons, AN_MAX_TX_DESC);
+ if (sc->an_rdata.an_tx_prod ==
+ sc->an_rdata.an_tx_cons)
+ sc->an_rdata.an_tx_empty = 1;
+ }
return;
}
@@ -758,43 +1188,44 @@ an_intr(xsc)
ifp = &sc->arpcom.ac_if;
/* Disable interrupts. */
- CSR_WRITE_2(sc, AN_INT_EN, 0);
+ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
- status = CSR_READ_2(sc, AN_EVENT_STAT);
- CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS);
+ status = CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350));
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), ~AN_INTRS);
if (status & AN_EV_AWAKE) {
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_AWAKE);
}
if (status & AN_EV_LINKSTAT) {
- if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED)
+ if (CSR_READ_2(sc, AN_LINKSTAT(sc->mpi350))
+ == AN_LINKSTAT_ASSOCIATED)
sc->an_associated = 1;
else
sc->an_associated = 0;
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_LINKSTAT);
}
if (status & AN_EV_RX) {
an_rxeof(sc);
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_RX);
}
if (status & AN_EV_TX) {
an_txeof(sc, status);
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX);
}
if (status & AN_EV_TX_EXC) {
an_txeof(sc, status);
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_TX_EXC);
}
if (status & AN_EV_ALLOC)
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
/* Re-enable interrupts. */
- CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
+ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS);
if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL))
an_start(ifp);
@@ -804,6 +1235,82 @@ an_intr(xsc)
return;
}
+static void
+an_kick(sc)
+ struct an_softc *sc;
+{
+ int i;
+
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_NOOP2);
+
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
+ } else {
+ for (i = 0; i < AN_TIMEOUT; i++) {
+ if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350))
+ & AN_EV_CMD)
+ break;
+ }
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
+ }
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
+ if (i == AN_TIMEOUT) {
+ printf ("COULDN'T CLEAR\n");
+ }
+ }
+}
+
+static int
+an_cmd_struct(sc, cmd, reply)
+ struct an_softc *sc;
+ struct an_command *cmd;
+ struct an_reply *reply;
+{
+ int i;
+
+ for (i = 0; i != AN_TIMEOUT; i++) {
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
+ DELAY(10);
+ }
+ else
+ break;
+ }
+ if( i == AN_TIMEOUT) {
+ printf("BUSY\n");
+ return(ETIMEDOUT);
+ }
+
+ CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), cmd->an_parm0);
+ CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), cmd->an_parm1);
+ CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), cmd->an_parm2);
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd->an_cmd);
+
+ for (i = 0; i < AN_TIMEOUT; i++) {
+ if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
+ break;
+ }
+
+ if (i == AN_TIMEOUT)
+ an_kick(sc);
+
+ reply->an_resp0 = CSR_READ_2(sc, AN_RESP0(sc->mpi350));
+ reply->an_resp1 = CSR_READ_2(sc, AN_RESP1(sc->mpi350));
+ reply->an_resp2 = CSR_READ_2(sc, AN_RESP2(sc->mpi350));
+ reply->an_status = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
+
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
+
+ /* Ack the command */
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
+
+ if (i == AN_TIMEOUT)
+ return(ETIMEDOUT);
+
+ return(0);
+}
+
static int
an_cmd(sc, cmd, val)
struct an_softc *sc;
@@ -812,34 +1319,34 @@ an_cmd(sc, cmd, val)
{
int i, s = 0;
- CSR_WRITE_2(sc, AN_PARAM0, val);
- CSR_WRITE_2(sc, AN_PARAM1, 0);
- CSR_WRITE_2(sc, AN_PARAM2, 0);
- CSR_WRITE_2(sc, AN_COMMAND, cmd);
+ CSR_WRITE_2(sc, AN_PARAM0(sc->mpi350), val);
+ CSR_WRITE_2(sc, AN_PARAM1(sc->mpi350), 0);
+ CSR_WRITE_2(sc, AN_PARAM2(sc->mpi350), 0);
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
for (i = 0; i < AN_TIMEOUT; i++) {
- if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
+ if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_CMD)
break;
else {
- if (CSR_READ_2(sc, AN_COMMAND) == cmd)
- CSR_WRITE_2(sc, AN_COMMAND, cmd);
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) == cmd)
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), cmd);
}
}
for (i = 0; i < AN_TIMEOUT; i++) {
- CSR_READ_2(sc, AN_RESP0);
- CSR_READ_2(sc, AN_RESP1);
- CSR_READ_2(sc, AN_RESP2);
- s = CSR_READ_2(sc, AN_STATUS);
+ CSR_READ_2(sc, AN_RESP0(sc->mpi350));
+ CSR_READ_2(sc, AN_RESP1(sc->mpi350));
+ CSR_READ_2(sc, AN_RESP2(sc->mpi350));
+ s = CSR_READ_2(sc, AN_STATUS(sc->mpi350));
if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
break;
}
/* Ack the command */
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CMD);
- if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY)
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_CLR_STUCK_BUSY);
if (i == AN_TIMEOUT)
return(ETIMEDOUT);
@@ -879,6 +1386,10 @@ an_read_record(sc, ltv)
struct an_softc *sc;
struct an_ltv_gen *ltv;
{
+ struct an_ltv_gen *an_ltv;
+ struct an_card_rid_desc an_rid_desc;
+ struct an_command cmd;
+ struct an_reply reply;
u_int16_t *ptr;
u_int8_t *ptr2;
int i, len;
@@ -886,43 +1397,84 @@ an_read_record(sc, ltv)
if (ltv->an_len < 4 || ltv->an_type == 0)
return(EINVAL);
- /* Tell the NIC to enter record read mode. */
- if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
- printf("an%d: RID access failed\n", sc->an_unit);
- return(EIO);
- }
+ if (!sc->mpi350){
+ /* Tell the NIC to enter record read mode. */
+ if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
+ printf("an%d: RID access failed\n", sc->an_unit);
+ return(EIO);
+ }
- /* Seek to the record. */
- if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
- printf("an%d: seek to record failed\n", sc->an_unit);
- return(EIO);
- }
+ /* Seek to the record. */
+ if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
+ printf("an%d: seek to record failed\n", sc->an_unit);
+ return(EIO);
+ }
- /*
- * Read the length and record type and make sure they
- * match what we expect (this verifies that we have enough
- * room to hold all of the returned data).
- * Length includes type but not length.
- */
- len = CSR_READ_2(sc, AN_DATA1);
- if (len > (ltv->an_len - 2)) {
- printf("an%d: record length mismatch -- expected %d, "
- "got %d for Rid %x\n", sc->an_unit,
- ltv->an_len - 2, len, ltv->an_type);
- len = ltv->an_len - 2;
- } else {
- ltv->an_len = len + 2;
- }
+ /*
+ * Read the length and record type and make sure they
+ * match what we expect (this verifies that we have enough
+ * room to hold all of the returned data).
+ * Length includes type but not length.
+ */
+ len = CSR_READ_2(sc, AN_DATA1);
+ if (len > (ltv->an_len - 2)) {
+ printf("an%d: record length mismatch -- expected %d, "
+ "got %d for Rid %x\n", sc->an_unit,
+ ltv->an_len - 2, len, ltv->an_type);
+ len = ltv->an_len - 2;
+ } else {
+ ltv->an_len = len + 2;
+ }
- /* Now read the data. */
- len -= 2; /* skip the type */
- ptr = &ltv->an_val;
- for (i = len; i > 1; i -= 2)
- *ptr++ = CSR_READ_2(sc, AN_DATA1);
- if (i) {
- ptr2 = (u_int8_t *)ptr;
- *ptr2 = CSR_READ_1(sc, AN_DATA1);
+ /* Now read the data. */
+ len -= 2; /* skip the type */
+ ptr = &ltv->an_val;
+ for (i = len; i > 1; i -= 2)
+ *ptr++ = CSR_READ_2(sc, AN_DATA1);
+ if (i) {
+ ptr2 = (u_int8_t *)ptr;
+ *ptr2 = CSR_READ_1(sc, AN_DATA1);
+ }
+ } else { /* MPI-350 */
+ an_rid_desc.an_valid = 1;
+ an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
+ an_rid_desc.an_rid = 0;
+ an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
+ bzero(sc->an_rid_buffer.an_dma_vaddr, AN_RID_BUFFER_SIZE);
+
+ bzero(&cmd, sizeof(cmd));
+ bzero(&reply, sizeof(reply));
+ cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_READ;
+ cmd.an_parm0 = ltv->an_type;
+
+ for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
+ ((u_int32_t*)&an_rid_desc)[i]);
+
+ if (an_cmd_struct(sc, &cmd, &reply)
+ || reply.an_status & AN_CMD_QUAL_MASK) {
+ printf("an%d: failed to read RID %x %x %x %x %x, %d\n",
+ sc->an_unit, ltv->an_type,
+ reply.an_status,
+ reply.an_resp0,
+ reply.an_resp1,
+ reply.an_resp2,
+ i);
+ return(EIO);
+ }
+
+ an_ltv = (struct an_ltv_gen *)sc->an_rid_buffer.an_dma_vaddr;
+ if (an_ltv->an_len + 2 < an_rid_desc.an_len) {
+ an_rid_desc.an_len = an_ltv->an_len;
+ }
+
+ if (an_rid_desc.an_len > 2)
+ bcopy(&an_ltv->an_type,
+ &ltv->an_val,
+ an_rid_desc.an_len - 2);
+ ltv->an_len = an_rid_desc.an_len + 2;
}
+
if (an_dump)
an_dump_record(sc, ltv, "Read");
@@ -937,6 +1489,10 @@ an_write_record(sc, ltv)
struct an_softc *sc;
struct an_ltv_gen *ltv;
{
+ struct an_card_rid_desc an_rid_desc;
+ struct an_command cmd;
+ struct an_reply reply;
+ char *buf;
u_int16_t *ptr;
u_int8_t *ptr2;
int i, len;
@@ -944,29 +1500,84 @@ an_write_record(sc, ltv)
if (an_dump)
an_dump_record(sc, ltv, "Write");
- if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
- return(EIO);
+ if (!sc->mpi350){
+ if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
+ return(EIO);
- if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
- return(EIO);
+ if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
+ return(EIO);
- /*
- * Length includes type but not length.
- */
- len = ltv->an_len - 2;
- CSR_WRITE_2(sc, AN_DATA1, len);
+ /*
+ * Length includes type but not length.
+ */
+ len = ltv->an_len - 2;
+ CSR_WRITE_2(sc, AN_DATA1, len);
+
+ len -= 2; /* skip the type */
+ ptr = &ltv->an_val;
+ for (i = len; i > 1; i -= 2)
+ CSR_WRITE_2(sc, AN_DATA1, *ptr++);
+ if (i) {
+ ptr2 = (u_int8_t *)ptr;
+ CSR_WRITE_1(sc, AN_DATA0, *ptr2);
+ }
- len -= 2; /* skip the type */
- ptr = &ltv->an_val;
- for (i = len; i > 1; i -= 2)
- CSR_WRITE_2(sc, AN_DATA1, *ptr++);
- if (i) {
- ptr2 = (u_int8_t *)ptr;
- CSR_WRITE_1(sc, AN_DATA0, *ptr2);
- }
+ if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
+ return(EIO);
+ } else { /* MPI-350 */
+
+ for (i = 0; i != AN_TIMEOUT; i++) {
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
+ DELAY(10);
+ }
+ else
+ break;
+ }
+ if (i == AN_TIMEOUT) {
+ printf("BUSY\n");
+ }
- if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
+ an_rid_desc.an_valid = 1;
+ an_rid_desc.an_len = ltv->an_len - 2;
+ an_rid_desc.an_rid = ltv->an_type;
+ an_rid_desc.an_phys = sc->an_rid_buffer.an_dma_paddr;
+
+ bcopy(&ltv->an_type, sc->an_rid_buffer.an_dma_vaddr,
+ an_rid_desc.an_len);
+
+ bzero(&cmd,sizeof(cmd));
+ bzero(&reply,sizeof(reply));
+ cmd.an_cmd = AN_CMD_ACCESS|AN_ACCESS_WRITE;
+ cmd.an_parm0 = ltv->an_type;
+
+ for (i = 0; i < sizeof(an_rid_desc) / 4; i++)
+ CSR_MEM_AUX_WRITE_4(sc, AN_HOST_DESC_OFFSET + i * 4,
+ ((u_int32_t*)&an_rid_desc)[i]);
+
+ if ((i = an_cmd_struct(sc, &cmd, &reply))) {
+ printf("an%d: failed to write RID %x %x %x %x %x, %d\n",
+ sc->an_unit, ltv->an_type,
+ reply.an_status,
+ reply.an_resp0,
+ reply.an_resp1,
+ reply.an_resp2,
+ i);
return(EIO);
+ }
+
+ ptr = (u_int16_t *)buf;
+
+ if (reply.an_status & AN_CMD_QUAL_MASK) {
+ printf("an%d: failed to write RID %x %x %x %x %x, %d\n",
+ sc->an_unit, ltv->an_type,
+ reply.an_status,
+ reply.an_resp0,
+ reply.an_resp1,
+ reply.an_resp2,
+ i);
+ return(EIO);
+ }
+ }
return(0);
}
@@ -1125,14 +1736,14 @@ an_alloc_nicmem(sc, len, id)
}
for (i = 0; i < AN_TIMEOUT; i++) {
- if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
+ if (CSR_READ_2(sc, AN_EVENT_STAT(sc->mpi350)) & AN_EV_ALLOC)
break;
}
if (i == AN_TIMEOUT)
return(ETIMEDOUT);
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
*id = CSR_READ_2(sc, AN_ALLOC_FID);
if (an_seek(sc, *id, 0, AN_BAP0))
@@ -1247,6 +1858,8 @@ an_promisc(sc, promisc)
{
if (sc->an_was_monitor)
an_reset(sc);
+ if (sc->mpi350)
+ an_init_mpi350_desc(sc);
if (sc->an_monitor || sc->an_was_monitor)
an_init(sc);
@@ -1827,16 +2440,19 @@ an_init_tx_ring(sc)
if (sc->an_gone)
return (0);
- for (i = 0; i < AN_TX_RING_CNT; i++) {
- if (an_alloc_nicmem(sc, 1518 +
- 0x44, &id))
- return(ENOMEM);
- sc->an_rdata.an_tx_fids[i] = id;
- sc->an_rdata.an_tx_ring[i] = 0;
+ if (!sc->mpi350) {
+ for (i = 0; i < AN_TX_RING_CNT; i++) {
+ if (an_alloc_nicmem(sc, 1518 +
+ 0x44, &id))
+ return(ENOMEM);
+ sc->an_rdata.an_tx_fids[i] = id;
+ sc->an_rdata.an_tx_ring[i] = 0;
+ }
}
sc->an_rdata.an_tx_prod = 0;
sc->an_rdata.an_tx_cons = 0;
+ sc->an_rdata.an_tx_empty = 1;
return(0);
}
@@ -1863,6 +2479,8 @@ an_init(xsc)
/* Allocate the TX buffers */
if (an_init_tx_ring(sc)) {
an_reset(sc);
+ if (sc->mpi350)
+ an_init_mpi350_desc(sc);
if (an_init_tx_ring(sc)) {
printf("an%d: tx buffer allocation "
"failed\n", sc->an_unit);
@@ -1897,6 +2515,9 @@ an_init(xsc)
}
}
+ 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);
@@ -1935,7 +2556,7 @@ an_init(xsc)
an_cmd(sc, AN_CMD_SET_MODE, 0xffff);
/* enable interrupts */
- CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
+ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), AN_INTRS);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@@ -1954,9 +2575,11 @@ an_start(ifp)
struct mbuf *m0 = NULL;
struct an_txframe_802_3 tx_frame_802_3;
struct ether_header *eh;
- int id;
- int idx;
+ int id, idx, i;
unsigned char txcontrol;
+ struct an_card_tx_desc an_tx_desc;
+ u_int8_t *ptr;
+ u_int8_t *buf;
sc = ifp->if_softc;
@@ -1981,55 +2604,129 @@ an_start(ifp)
}
idx = sc->an_rdata.an_tx_prod;
- bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
- while (sc->an_rdata.an_tx_ring[idx] == 0) {
- IF_DEQUEUE(&ifp->if_snd, m0);
- if (m0 == NULL)
- break;
+ if (!sc->mpi350) {
+ bzero((char *)&tx_frame_802_3, sizeof(tx_frame_802_3));
+
+ while (sc->an_rdata.an_tx_ring[idx] == 0) {
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+
+ id = sc->an_rdata.an_tx_fids[idx];
+ eh = mtod(m0, struct ether_header *);
+
+ bcopy((char *)&eh->ether_dhost,
+ (char *)&tx_frame_802_3.an_tx_dst_addr,
+ ETHER_ADDR_LEN);
+ bcopy((char *)&eh->ether_shost,
+ (char *)&tx_frame_802_3.an_tx_src_addr,
+ ETHER_ADDR_LEN);
+
+ /* minus src/dest mac & type */
+ tx_frame_802_3.an_tx_802_3_payload_len =
+ m0->m_pkthdr.len - 12;
- id = sc->an_rdata.an_tx_fids[idx];
- eh = mtod(m0, struct ether_header *);
+ m_copydata(m0, sizeof(struct ether_header) - 2 ,
+ tx_frame_802_3.an_tx_802_3_payload_len,
+ (caddr_t)&sc->an_txbuf);
- bcopy((char *)&eh->ether_dhost,
- (char *)&tx_frame_802_3.an_tx_dst_addr, ETHER_ADDR_LEN);
- bcopy((char *)&eh->ether_shost,
- (char *)&tx_frame_802_3.an_tx_src_addr, ETHER_ADDR_LEN);
+ txcontrol = AN_TXCTL_8023;
+ /* write the txcontrol only */
+ an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
+ sizeof(txcontrol));
- tx_frame_802_3.an_tx_802_3_payload_len =
- m0->m_pkthdr.len - 12; /* minus src/dest mac & type */
+ /* 802_3 header */
+ an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
+ sizeof(struct an_txframe_802_3));
- m_copydata(m0, sizeof(struct ether_header) - 2 ,
- tx_frame_802_3.an_tx_802_3_payload_len,
- (caddr_t)&sc->an_txbuf);
+ /* in mbuf header type is just before payload */
+ an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
+ tx_frame_802_3.an_tx_802_3_payload_len);
- txcontrol = AN_TXCTL_8023;
- /* write the txcontrol only */
- an_write_data(sc, id, 0x08, (caddr_t)&txcontrol,
+ /*
+ * If there's a BPF listner, bounce a copy of
+ * this frame to him.
+ */
+ BPF_MTAP(ifp, m0);
+
+ m_freem(m0);
+ m0 = NULL;
+
+ sc->an_rdata.an_tx_ring[idx] = id;
+ if (an_cmd(sc, AN_CMD_TX, id))
+ printf("an%d: xmit failed\n", sc->an_unit);
+
+ AN_INC(idx, AN_TX_RING_CNT);
+ }
+ } else { /* MPI-350 */
+ while (sc->an_rdata.an_tx_empty ||
+ idx != sc->an_rdata.an_tx_cons) {
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL) {
+ break;
+ }
+ buf = sc->an_tx_buffer[idx].an_dma_vaddr;
+
+ eh = mtod(m0, struct ether_header *);
+
+ /* DJA optimize this to limit bcopy */
+ bcopy((char *)&eh->ether_dhost,
+ (char *)&tx_frame_802_3.an_tx_dst_addr,
+ ETHER_ADDR_LEN);
+ bcopy((char *)&eh->ether_shost,
+ (char *)&tx_frame_802_3.an_tx_src_addr,
+ ETHER_ADDR_LEN);
+
+ /* minus src/dest mac & type */
+ tx_frame_802_3.an_tx_802_3_payload_len =
+ m0->m_pkthdr.len - 12;
+
+ m_copydata(m0, sizeof(struct ether_header) - 2 ,
+ tx_frame_802_3.an_tx_802_3_payload_len,
+ (caddr_t)&sc->an_txbuf);
+
+ txcontrol = AN_TXCTL_8023;
+ /* write the txcontrol only */
+ bcopy((caddr_t)&txcontrol, &buf[0x08],
sizeof(txcontrol));
- /* 802_3 header */
- an_write_data(sc, id, 0x34, (caddr_t)&tx_frame_802_3,
+ /* 802_3 header */
+ bcopy((caddr_t)&tx_frame_802_3, &buf[0x34],
sizeof(struct an_txframe_802_3));
- /* in mbuf header type is just before payload */
- an_write_data(sc, id, 0x44, (caddr_t)&sc->an_txbuf,
- tx_frame_802_3.an_tx_802_3_payload_len);
+ /* in mbuf header type is just before payload */
+ bcopy((caddr_t)&sc->an_txbuf, &buf[0x44],
+ tx_frame_802_3.an_tx_802_3_payload_len);
+
+
+ bzero(&an_tx_desc, sizeof(an_tx_desc));
+ an_tx_desc.an_offset = 0;
+ an_tx_desc.an_eoc = 1;
+ an_tx_desc.an_valid = 1;
+ an_tx_desc.an_len = 0x44 +
+ tx_frame_802_3.an_tx_802_3_payload_len;
+ an_tx_desc.an_phys = sc->an_tx_buffer[idx].an_dma_paddr;
+ ptr = (u_int8_t*)&an_tx_desc;
+ for (i = 0; i < sizeof(an_tx_desc); i++) {
+ CSR_MEM_AUX_WRITE_1(sc, AN_TX_DESC_OFFSET + i,
+ ptr[i]);
+ }
- /*
- * If there's a BPF listner, bounce a copy of
- * this frame to him.
- */
- BPF_MTAP(ifp, m0);
+ /*
+ * If there's a BPF listner, bounce a copy of
+ * this frame to him.
+ */
+ BPF_MTAP(ifp, m0);
- m_freem(m0);
- m0 = NULL;
+ m_freem(m0);
+ m0 = NULL;
- sc->an_rdata.an_tx_ring[idx] = id;
- if (an_cmd(sc, AN_CMD_TX, id))
- printf("an%d: xmit failed\n", sc->an_unit);
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350), AN_EV_ALLOC);
- AN_INC(idx, AN_TX_RING_CNT);
+ AN_INC(idx, AN_MAX_TX_DESC);
+ sc->an_rdata.an_tx_empty = 0;
+ }
}
if (m0 != NULL)
@@ -2062,7 +2759,7 @@ an_stop(sc)
ifp = &sc->arpcom.ac_if;
an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0);
- CSR_WRITE_2(sc, AN_INT_EN, 0);
+ CSR_WRITE_2(sc, AN_INT_EN(sc->mpi350), 0);
an_cmd(sc, AN_CMD_DISABLE, 0);
for (i = 0; i < AN_TX_RING_CNT; i++)
@@ -2072,6 +2769,11 @@ an_stop(sc)
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;
@@ -2094,6 +2796,8 @@ an_watchdog(ifp)
printf("an%d: device timeout\n", sc->an_unit);
an_reset(sc);
+ if (sc->mpi350)
+ an_init_mpi350_desc(sc);
an_init(sc);
ifp->if_oerrors++;
@@ -2175,11 +2879,12 @@ SYSCTL_INT(_machdep, OID_AUTO, an_cache_iponly, CTLFLAG_RW,
* strength in MAC (src) indexed cache.
*/
static void
-an_cache_store (sc, eh, m, rx_quality)
+an_cache_store (sc, eh, m, rx_rssi, rx_quality)
struct an_softc *sc;
struct ether_header *eh;
struct mbuf *m;
- unsigned short rx_quality;
+ u_int8_t rx_rssi;
+ u_int8_t rx_quality;
{
struct ip *ip = 0;
int i;
@@ -2211,7 +2916,7 @@ an_cache_store (sc, eh, m, rx_quality)
#ifdef SIGDEBUG
printf("an: q value %x (MSB=0x%x, LSB=0x%x) \n",
- rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
+ rx_rssi & 0xffff, rx_rssi >> 8, rx_rssi & 0xff);
#endif
/* find the ip header. we want to store the ip_src
@@ -2288,7 +2993,41 @@ an_cache_store (sc, eh, m, rx_quality)
}
bcopy( eh->ether_shost, sc->an_sigcache[cache_slot].macsrc, 6);
- sc->an_sigcache[cache_slot].signal = rx_quality;
+
+ 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;
}
@@ -2552,7 +3291,9 @@ writerids(ifp, l_ioctl)
* Linux driver
*/
-#define FLASH_DELAY(x) tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
+#define FLASH_DELAY(x) tsleep(ifp, PZERO, "flash", ((x) / hz) + 1);
+#define FLASH_COMMAND 0x7e7e
+#define FLASH_SIZE 32 * 1024
static int
unstickbusy(ifp)
@@ -2560,8 +3301,9 @@ unstickbusy(ifp)
{
struct an_softc *sc = ifp->if_softc;
- if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
- CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
+ if (CSR_READ_2(sc, AN_COMMAND(sc->mpi350)) & AN_CMD_BUSY) {
+ CSR_WRITE_2(sc, AN_EVENT_ACK(sc->mpi350),
+ AN_EV_CLR_STUCK_BUSY);
return 1;
}
return 0;
@@ -2584,7 +3326,7 @@ WaitBusy(ifp, uSec)
while ((statword & AN_CMD_BUSY) && delay <= (1000 * 100)) {
FLASH_DELAY(10);
delay += 10;
- statword = CSR_READ_2(sc, AN_COMMAND);
+ statword = CSR_READ_2(sc, AN_COMMAND(sc->mpi350));
if ((AN_CMD_BUSY & statword) && (delay % 200)) {
unstickbusy(ifp);
@@ -2609,12 +3351,12 @@ cmdreset(ifp)
an_cmd(sc, AN_CMD_DISABLE, 0);
- if (!(status = WaitBusy(ifp, 600))) {
+ if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
printf("an%d: Waitbusy hang b4 RESET =%d\n",
sc->an_unit, status);
return -EBUSY;
}
- CSR_WRITE_2(sc, AN_COMMAND, AN_CMD_FW_RESTART);
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), AN_CMD_FW_RESTART);
FLASH_DELAY(1000); /* WAS 600 12/7/00 */
@@ -2630,7 +3372,6 @@ cmdreset(ifp)
/*
* STEP 2) Put the card in legendary flash mode
*/
-#define FLASH_COMMAND 0x7e7e
static int
setflashmode(ifp)
@@ -2639,10 +3380,10 @@ setflashmode(ifp)
int status;
struct an_softc *sc = ifp->if_softc;
- CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
- CSR_WRITE_2(sc, AN_SW1, FLASH_COMMAND);
- CSR_WRITE_2(sc, AN_SW0, FLASH_COMMAND);
- CSR_WRITE_2(sc, AN_COMMAND, FLASH_COMMAND);
+ CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
+ CSR_WRITE_2(sc, AN_SW1(sc->mpi350), FLASH_COMMAND);
+ CSR_WRITE_2(sc, AN_SW0(sc->mpi350), FLASH_COMMAND);
+ CSR_WRITE_2(sc, AN_COMMAND(sc->mpi350), FLASH_COMMAND);
/*
* mdelay(500); // 500ms delay
@@ -2650,7 +3391,7 @@ setflashmode(ifp)
FLASH_DELAY(500);
- if (!(status = WaitBusy(ifp, 600))) {
+ if (!(status = WaitBusy(ifp, AN_TIMEOUT))) {
printf("Waitbusy hang after setflash mode\n");
return -EIO;
}
@@ -2674,7 +3415,7 @@ flashgchar(ifp, matchbyte, dwelltime)
do {
- rchar = CSR_READ_2(sc, AN_SW1);
+ rchar = CSR_READ_2(sc, AN_SW1(sc->mpi350));
if (dwelltime && !(0x8000 & rchar)) {
dwelltime -= 10;
@@ -2684,13 +3425,13 @@ flashgchar(ifp, matchbyte, dwelltime)
rbyte = 0xff & rchar;
if ((rbyte == matchbyte) && (0x8000 & rchar)) {
- CSR_WRITE_2(sc, AN_SW1, 0);
+ CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
success = 1;
break;
}
if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
break;
- CSR_WRITE_2(sc, AN_SW1, 0);
+ CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
} while (dwelltime > 0);
return success;
@@ -2721,7 +3462,7 @@ flashpchar(ifp, byte, dwelltime)
* Wait for busy bit d15 to go false indicating buffer empty
*/
do {
- pollbusy = CSR_READ_2(sc, AN_SW0);
+ pollbusy = CSR_READ_2(sc, AN_SW0(sc->mpi350));
if (pollbusy & 0x8000) {
FLASH_DELAY(50);
@@ -2743,14 +3484,14 @@ flashpchar(ifp, byte, dwelltime)
* Port is clear now write byte and wait for it to echo back
*/
do {
- CSR_WRITE_2(sc, AN_SW0, byte);
+ CSR_WRITE_2(sc, AN_SW0(sc->mpi350), byte);
FLASH_DELAY(50);
dwelltime -= 50;
- echo = CSR_READ_2(sc, AN_SW1);
+ echo = CSR_READ_2(sc, AN_SW1(sc->mpi350));
} while (dwelltime >= 0 && echo != byte);
- CSR_WRITE_2(sc, AN_SW1, 0);
+ CSR_WRITE_2(sc, AN_SW1(sc->mpi350), 0);
return echo == byte;
}
@@ -2760,9 +3501,6 @@ flashpchar(ifp, byte, dwelltime)
* the card
*/
-static char flashbuffer[1024 * 38]; /* RAW Buffer for flash will be
- * dynamic next */
-
static int
flashputbuf(ifp)
struct ifnet *ifp;
@@ -2773,16 +3511,23 @@ flashputbuf(ifp)
/* Write stuff */
- bufp = (unsigned short *)flashbuffer;
+ bufp = sc->an_flash_buffer;
- CSR_WRITE_2(sc, AN_AUX_PAGE, 0x100);
- CSR_WRITE_2(sc, AN_AUX_OFFSET, 0);
+ if (!sc->mpi350) {
+ 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);
+ for (nwords = 0; nwords != FLASH_SIZE / 2; nwords++) {
+ CSR_WRITE_2(sc, AN_AUX_DATA, bufp[nwords] & 0xffff);
+ }
+ } else {
+ for (nwords = 0; nwords != FLASH_SIZE / 4; nwords++) {
+ CSR_MEM_AUX_WRITE_4(sc, 0x8000,
+ ((u_int32_t *)bufp)[nwords] & 0xffff);
+ }
}
- CSR_WRITE_2(sc, AN_SW0, 0x8000);
+ CSR_WRITE_2(sc, AN_SW0(sc->mpi350), 0x8000);
return 0;
}
@@ -2819,6 +3564,11 @@ flashcard(ifp, l_ioctl)
struct an_softc *sc;
sc = ifp->if_softc;
+ if (sc->mpi350) {
+ printf("an%d: flashing not supported on MPI 350 yet\n",
+ sc->an_unit);
+ return(-1);
+ }
status = l_ioctl->command;
switch (l_ioctl->command) {
@@ -2826,7 +3576,15 @@ flashcard(ifp, l_ioctl)
return cmdreset(ifp);
break;
case AIROFLSHSTFL:
- return setflashmode(ifp);
+ 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);
@@ -2845,12 +3603,12 @@ flashcard(ifp, l_ioctl)
return 0;
break;
case AIROFLPUTBUF: /* Send 32k to card */
- if (l_ioctl->len > sizeof(flashbuffer)) {
- printf("an%d: Buffer to big, %x %zx\n", sc->an_unit,
- l_ioctl->len, sizeof(flashbuffer));
+ 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, &flashbuffer, l_ioctl->len);
+ copyin(l_ioctl->data, sc->an_flash_buffer, l_ioctl->len);
if ((status = flashputbuf(ifp)) != 0)
return -EIO;
@@ -2872,4 +3630,3 @@ flashcard(ifp, l_ioctl)
return -EINVAL;
}
-
diff --git a/sys/dev/an/if_an_pccard.c b/sys/dev/an/if_an_pccard.c
index ddc827a..a246d6b 100644
--- a/sys/dev/an/if_an_pccard.c
+++ b/sys/dev/an/if_an_pccard.c
@@ -193,4 +193,3 @@ an_pccard_attach(device_t dev)
error = an_attach(sc, device_get_unit(dev), flags);
return (error);
}
-
diff --git a/sys/dev/an/if_an_pci.c b/sys/dev/an/if_an_pci.c
index b1aa0f3..2fe45e0 100644
--- a/sys/dev/an/if_an_pci.c
+++ b/sys/dev/an/if_an_pci.c
@@ -101,6 +101,7 @@ struct an_type {
#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,6 +133,12 @@ an_probe_pci(device_t dev)
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,21 +155,26 @@ an_attach_pci(dev)
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;
+ if (pci_get_vendor(dev) == AIRONET_VENDORID &&
+ pci_get_device(dev) == AIRONET_DEVICEID_MPI350) {
+ sc->mpi350 = 1;
+ 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;
}
-
- sc->port_rid = AN_PCI_LOIO;
error = an_alloc_port(dev, sc->port_rid, 1);
if (error) {
@@ -173,17 +185,55 @@ an_attach_pci(dev)
sc->an_btag = rman_get_bustag(sc->port_res);
sc->an_bhandle = rman_get_bushandle(sc->port_res);
+ /* Allocate memory for MPI350 */
+ if (sc->mpi350) {
+ /* Allocate memory */
+ sc->mem_rid = PCIR_MAPS + 4;
+ error = an_alloc_memory(dev, sc->mem_rid, 1);
+ if (error) {
+ printf("an%d: couldn't map memory\n", unit);
+ goto fail;
+ }
+ sc->an_mem_btag = rman_get_bustag(sc->mem_res);
+ sc->an_mem_bhandle = rman_get_bushandle(sc->mem_res);
+
+ /* Allocate aux. memory */
+ sc->mem_aux_rid = PCIR_MAPS + 8;
+ error = an_alloc_aux_memory(dev, sc->mem_aux_rid,
+ AN_AUXMEMSIZE);
+ if (error) {
+ printf("an%d: couldn't map aux memory\n", unit);
+ goto fail;
+ }
+ sc->an_mem_aux_btag = rman_get_bustag(sc->mem_aux_res);
+ sc->an_mem_aux_bhandle = rman_get_bushandle(sc->mem_aux_res);
+
+ /* Allocate DMA region */
+ error = bus_dma_tag_create(NULL, /* parent */
+ 1, 0, /* alignment, bounds */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ 0x3ffff, /* maxsize XXX */
+ 1, /* nsegments */
+ 0xffff, /* maxsegsize XXX */
+ BUS_DMA_ALLOCNOW, /* flags */
+ &sc->an_dtag);
+ if (error) {
+ printf("an%d: couldn't get DMA region\n", unit);
+ goto fail;
+ }
+ }
+
/* Allocate interrupt */
error = an_alloc_irq(dev, 0, RF_SHAREABLE);
if (error) {
- an_release_resources(dev);
goto fail;
}
error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
an_intr, sc, &sc->irq_handle);
if (error) {
- an_release_resources(dev);
goto fail;
}
@@ -191,6 +241,8 @@ an_attach_pci(dev)
error = an_attach(sc, device_get_unit(dev), flags);
fail:
+ if (error)
+ an_release_resources(dev);
return(error);
}
diff --git a/sys/dev/an/if_anreg.h b/sys/dev/an/if_anreg.h
index a1e1aa2..c9bf1fc 100644
--- a/sys/dev/an/if_anreg.h
+++ b/sys/dev/an/if_anreg.h
@@ -32,7 +32,7 @@
* $FreeBSD$
*/
-#define AN_TIMEOUT 65536
+#define AN_TIMEOUT 600000
/* Default network name: <empty string> */
#define AN_DEFAULT_NETNAME ""
@@ -58,24 +58,59 @@
bus_space_read_1(sc->an_btag, sc->an_bhandle, reg)
/*
+ * memory space access macros
+ */
+#define CSR_MEM_WRITE_2(sc, reg, val) \
+ bus_space_write_2(sc->an_mem_btag, sc->an_mem_bhandle, reg, val)
+
+#define CSR_MEM_READ_2(sc, reg) \
+ bus_space_read_2(sc->an_mem_btag, sc->an_mem_bhandle, reg)
+
+#define CSR_MEM_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->an_mem_btag, sc->an_mem_bhandle, reg, val)
+
+#define CSR_MEM_READ_1(sc, reg) \
+ bus_space_read_1(sc->an_mem_btag, sc->an_mem_bhandle, reg)
+
+/*
+ * aux. memory space access macros
+ */
+#define CSR_MEM_AUX_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg, val)
+
+#define CSR_MEM_AUX_READ_4(sc, reg) \
+ bus_space_read_4(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg)
+
+#define CSR_MEM_AUX_WRITE_1(sc, reg, val) \
+ bus_space_write_1(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg, val)
+
+#define CSR_MEM_AUX_READ_1(sc, reg) \
+ bus_space_read_1(sc->an_mem_aux_btag, sc->an_mem_aux_bhandle, reg)
+
+/*
* Size of Aironet I/O space.
*/
#define AN_IOSIZ 0x40
/*
+ * Size of aux. memory space ... probably not needed DJA
+ */
+#define AN_AUXMEMSIZE (256 * 1024)
+
+/*
* Hermes register definitions and what little I know about them.
*/
/* Hermes command/status registers. */
-#define AN_COMMAND 0x00
-#define AN_PARAM0 0x02
-#define AN_PARAM1 0x04
-#define AN_PARAM2 0x06
-#define AN_STATUS 0x08
-#define AN_RESP0 0x0A
-#define AN_RESP1 0x0C
-#define AN_RESP2 0x0E
-#define AN_LINKSTAT 0x10
+#define AN_COMMAND(x) (x ? 0x00 : 0x00)
+#define AN_PARAM0(x) (x ? 0x04 : 0x02)
+#define AN_PARAM1(x) (x ? 0x08 : 0x04)
+#define AN_PARAM2(x) (x ? 0x0c : 0x06)
+#define AN_STATUS(x) (x ? 0x10 : 0x08)
+#define AN_RESP0(x) (x ? 0x14 : 0x0A)
+#define AN_RESP1(x) (x ? 0x18 : 0x0C)
+#define AN_RESP2(x) (x ? 0x1c : 0x0E)
+#define AN_LINKSTAT(x) (x ? 0x20 : 0x10)
/* Command register */
#define AN_CMD_BUSY 0x8000 /* busy bit */
@@ -97,6 +132,7 @@
#define AN_CMD_TX 0x000B /* transmit */
#define AN_CMD_DEALLOC_MEM 0x000C
#define AN_CMD_NOOP2 0x0010
+#define AN_CMD_ALLOC_DESC 0x0020
#define AN_CMD_ACCESS 0x0021
#define AN_CMD_ALLOC_BUF 0x0028
#define AN_CMD_PSP_NODES 0x0030
@@ -106,6 +142,69 @@
#define AN_CMD_SAVECFG 0x0108
/*
+ * MPI 350 DMA descriptor information
+ */
+#define AN_DESCRIPTOR_TX 0x01
+#define AN_DESCRIPTOR_RX 0x02
+#define AN_DESCRIPTOR_TXCMP 0x04
+#define AN_DESCRIPTOR_HOSTWRITE 0x08
+#define AN_DESCRIPTOR_HOSTREAD 0x10
+#define AN_DESCRIPTOR_HOSTRW 0x20
+
+#define AN_MAX_RX_DESC 1
+#define AN_MAX_TX_DESC 1
+#define AN_HOSTBUFSIZ 1840
+
+struct an_card_rid_desc
+{
+ unsigned an_rid:16;
+ unsigned an_len:15;
+ unsigned an_valid:1;
+ u_int64_t an_phys;
+};
+
+struct an_card_rx_desc
+{
+ unsigned an_ctrl:15;
+ unsigned an_done:1;
+ unsigned an_len:15;
+ unsigned an_valid:1;
+ u_int64_t an_phys;
+};
+
+struct an_card_tx_desc
+{
+ unsigned an_offset:15;
+ unsigned an_eoc:1;
+ unsigned an_len:15;
+ unsigned an_valid:1;
+ u_int64_t an_phys;
+};
+
+#define AN_RID_BUFFER_SIZE 2048
+#define AN_RX_BUFFER_SIZE 1840
+#define AN_TX_BUFFER_SIZE 1840
+#define AN_HOST_DESC_OFFSET 0x8
+#define AN_RX_DESC_OFFSET (AN_HOST_DESC_OFFSET + \
+ sizeof(struct an_card_rid_desc))
+#define AN_TX_DESC_OFFSET (AN_RX_DESC_OFFSET + \
+ (AN_MAX_RX_DESC * sizeof(struct an_card_rx_desc)))
+
+struct an_command {
+ u_int16_t an_cmd;
+ u_int16_t an_parm0;
+ u_int16_t an_parm1;
+ u_int16_t an_parm2;
+};
+
+struct an_reply {
+ u_int16_t an_status;
+ u_int16_t an_resp0;
+ u_int16_t an_resp1;
+ u_int16_t an_resp2;
+};
+
+/*
* Reclaim qualifier bit, applicable to the
* TX command.
*/
@@ -169,9 +268,10 @@
#define AN_OFF_DATAOFF 0x0FFF
/* Event registers */
-#define AN_EVENT_STAT 0x30 /* Event status */
-#define AN_INT_EN 0x32 /* Interrupt enable/disable */
-#define AN_EVENT_ACK 0x34 /* Ack event */
+#define AN_EVENT_STAT(x) (x ? 0x60 : 0x30) /* Event status */
+#define AN_INT_EN(x) (x ? 0x64 : 0x32) /* Interrupt enable/
+ disable */
+#define AN_EVENT_ACK(x) (x ? 0x68 : 0x34) /* Ack event */
/* Events */
#define AN_EV_CLR_STUCK_BUSY 0x4000 /* clear stuck busy bit */
@@ -188,10 +288,10 @@
(AN_EV_RX|AN_EV_TX|AN_EV_TX_EXC|AN_EV_ALLOC|AN_EV_LINKSTAT)
/* Host software registers */
-#define AN_SW0 0x28
-#define AN_SW1 0x2A
-#define AN_SW2 0x2C
-#define AN_SW3 0x2E
+#define AN_SW0(x) (x ? 0x50 : 0x28)
+#define AN_SW1(x) (x ? 0x54 : 0x2A)
+#define AN_SW2(x) (x ? 0x58 : 0x2C)
+#define AN_SW3(x) (x ? 0x5c : 0x2E)
#define AN_CNTL 0x14
@@ -311,6 +411,15 @@ struct an_snap_hdr {
u_int16_t an_snap_type;
};
+struct an_dma_alloc {
+ u_int32_t an_dma_paddr;
+ caddr_t an_dma_vaddr;
+ bus_dmamap_t an_dma_map;
+ bus_dma_segment_t an_dma_seg;
+ bus_size_t an_dma_size;
+ int an_dma_nseg;
+};
+
#define AN_TX_RING_CNT 4
#define AN_INC(x, y) (x) = (x + 1) % y
@@ -319,6 +428,7 @@ struct an_tx_ring_data {
u_int16_t an_tx_ring[AN_TX_RING_CNT];
int an_tx_prod;
int an_tx_cons;
+ int an_tx_empty;
};
struct an_softc {
@@ -328,13 +438,24 @@ struct an_softc {
int port_rid; /* resource id for port range */
struct resource* port_res; /* resource for port range */
+ int mem_rid; /* resource id for memory range */
+ int mem_used; /* nonzero if memory used */
+ struct resource* mem_res; /* resource for memory range */
+ int mem_aux_rid; /* resource id for memory range */
+ int mem_aux_used; /* nonzero if memory used */
+ struct resource* mem_aux_res; /* resource for memory range */
int irq_rid; /* resource id for irq */
- struct resource* irq_res; /* resource for irq */
void* irq_handle; /* handle for irq handler */
+ struct resource* irq_res; /* resource for irq */
bus_space_handle_t an_bhandle_p;
bus_space_handle_t an_bhandle;
bus_space_tag_t an_btag;
+ bus_space_handle_t an_mem_bhandle;
+ bus_space_tag_t an_mem_btag;
+ bus_space_handle_t an_mem_aux_bhandle;
+ bus_space_tag_t an_mem_aux_btag;
+ bus_dma_tag_t an_dtag;
struct an_ltv_genconfig an_config;
struct an_ltv_caps an_caps;
struct an_ltv_ssidlist an_ssidlist;
@@ -354,6 +475,8 @@ struct an_softc {
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,6 +486,11 @@ struct an_softc {
int an_was_monitor;
u_char buf_802_11[MCLBYTES];
struct an_req areq;
+ unsigned short* an_flash_buffer;
+ int mpi350;
+ struct an_dma_alloc an_rid_buffer;
+ struct an_dma_alloc an_rx_buffer[AN_MAX_RX_DESC];
+ struct an_dma_alloc an_tx_buffer[AN_MAX_TX_DESC];
};
#define AN_LOCK(_sc) mtx_lock(&(_sc)->an_mtx)
@@ -371,6 +499,7 @@ struct an_softc {
void an_release_resources (device_t);
int an_alloc_port (device_t, int, int);
int an_alloc_memory (device_t, int, int);
+int an_alloc_aux_memory (device_t, int, int);
int an_alloc_irq (device_t, int, int);
int an_probe (device_t);
void an_shutdown (device_t);
OpenPOWER on IntegriCloud