/************************************************************************** POLL - Wait for a frame ***************************************************************************/ static int prism2_poll(struct nic *nic, int retrieve) { uint16_t reg; uint16_t rxfid; uint16_t result; hfa384x_rx_frame_t rxdesc; hfa384x_t *hw = &hw_global; /* Check for received packet */ reg = hfa384x_getreg(hw, HFA384x_EVSTAT); if ( ! HFA384x_EVSTAT_ISRX(reg) ) { /* No packet received - return 0 */ return 0; } if ( ! retrieve ) return 1; /* Acknowledge RX event */ hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK); /* Get RX FID */ rxfid = hfa384x_getreg(hw, HFA384x_RXFID); /* Get the descriptor (including headers) */ result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc)); if ( result ) { return 0; /* fail */ } /* Byte order convert once up front. */ rxdesc.status = hfa384x2host_16(rxdesc.status); rxdesc.time = hfa384x2host_32(rxdesc.time); rxdesc.data_len = hfa384x2host_16(rxdesc.data_len); /* Fill in nic->packetlen */ nic->packetlen = rxdesc.data_len; if ( nic->packetlen > 0 ) { /* Fill in nic->packet */ /* * NOTE: Packets as received have an 8-byte header (LLC+SNAP(?)) terminating with the packet type. * Etherboot expects a 14-byte header terminating with the packet type (it ignores the rest of the * header), so we use a quick hack to achieve this. */ result = hfa384x_copy_from_bap(hw, rxfid, HFA384x_RX_DATA_OFF, nic->packet + ETH_HLEN - sizeof(wlan_80211hdr_t), nic->packetlen); if ( result ) { return 0; /* fail */ } } return 1; /* Packet successfully received */ }
/* * Prepare BAP for access. Assigns FID and RID, sets offset register * and waits for BAP to become available. * * Arguments: * hw device structure * id FID or RID, destined for the select register (host order) * offset An _even_ offset into the buffer for the given FID/RID. * Returns: * 0 success */ static int hfa384x_prepare_bap(hfa384x_t *hw, uint16_t id, uint16_t offset) { int result = 0; uint16_t reg; uint16_t i; /* Validate offset, buf, and len */ if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) { result = -EINVAL; } else { /* Write fid/rid and offset */ hfa384x_setreg(hw, id, HFA384x_SELECT0); udelay(10); hfa384x_setreg(hw, offset, HFA384x_OFFSET0); /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ i = 0; do { reg = hfa384x_getreg(hw, HFA384x_OFFSET0); if ( i > 0 ) udelay(2); i++; } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg)); if ( i >= BAP_TIMEOUT ) { /* failure */ result = reg; } else if ( HFA384x_OFFSET_ISERR(reg) ){ /* failure */ result = reg; } } return result; }
int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) { int result = 0; unsigned long timeout; UINT16 reg; DBFENTER; /* Assert reset and wait awhile * (note: these delays are _really_ long, but they appear to be * necessary.) */ hfa384x_setreg(hw, 0xc5, HFA384x_PCICOR); timeout = jiffies + HZ/4; while(time_before(jiffies, timeout)) udelay(5); if (genesis) { hfa384x_setreg(hw, genesis, HFA384x_PCIHCR); timeout = jiffies + HZ/4; while(time_before(jiffies, timeout)) udelay(5); } /* Clear the reset and wait some more */ hfa384x_setreg(hw, 0x45, HFA384x_PCICOR); timeout = jiffies + HZ/2; while(time_before(jiffies, timeout)) udelay(5); /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ timeout = jiffies + 2*HZ; reg = hfa384x_getreg(hw, HFA384x_CMD); while ( HFA384x_CMD_ISBUSY(reg) && time_before( jiffies, timeout) ) { reg = hfa384x_getreg(hw, HFA384x_CMD); udelay(10); } if (HFA384x_CMD_ISBUSY(reg)) { WLAN_LOG_WARNING("corereset: Timed out waiting for cmd register.\n"); result=1; } DBFEXIT; return result; }
/* * hfa384x_docmd_wait * * Waits for availability of the Command register, then * issues the given command. Then polls the Evstat register * waiting for command completion. * Arguments: * hw device structure * cmd Command in host order * parm0 Parameter0 in host order * parm1 Parameter1 in host order * parm2 Parameter2 in host order * Returns: * 0 success * >0 command indicated error, Status and Resp0-2 are * in hw structure. */ static int hfa384x_docmd_wait( hfa384x_t *hw, uint16_t cmd, uint16_t parm0, uint16_t parm1, uint16_t parm2) { uint16_t reg = 0; uint16_t counter = 0; /* wait for the busy bit to clear */ counter = 0; reg = hfa384x_getreg(hw, HFA384x_CMD); while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) { reg = hfa384x_getreg(hw, HFA384x_CMD); counter++; udelay(10); } if (HFA384x_CMD_ISBUSY(reg)) { printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg); return -ETIMEDOUT; } /* busy bit clear, write command */ hfa384x_setreg(hw, parm0, HFA384x_PARAM0); hfa384x_setreg(hw, parm1, HFA384x_PARAM1); hfa384x_setreg(hw, parm2, HFA384x_PARAM2); hw->lastcmd = cmd; hfa384x_setreg(hw, cmd, HFA384x_CMD); /* Now wait for completion */ counter = 0; reg = hfa384x_getreg(hw, HFA384x_EVSTAT); /* Initialization is the problem. It takes about 100ms. "normal" commands are typically is about 200-400 us (I've never seen less than 200). Longer is better so that we're not hammering the bus. */ while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) { reg = hfa384x_getreg(hw, HFA384x_EVSTAT); counter++; udelay(200); } if ( ! HFA384x_EVSTAT_ISCMD(reg) ) { printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg); return -ETIMEDOUT; } /* Read status and response */ hw->status = hfa384x_getreg(hw, HFA384x_STATUS); hw->resp0 = hfa384x_getreg(hw, HFA384x_RESP0); hw->resp1 = hfa384x_getreg(hw, HFA384x_RESP1); hw->resp2 = hfa384x_getreg(hw, HFA384x_RESP2); hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK); return HFA384x_STATUS_RESULT_GET(hw->status); }
/* * Wait for an event, with specified checking interval and timeout. * Automatically acknolwedges events. * * Arguments: * hw device structure * event_mask EVSTAT register mask of events to wait for * event_ack EVACK register set of events to be acknowledged if they happen (can be * used to acknowledge "ignorable" events in addition to the "main" event) * wait Time (in us) to wait between each poll of the register * timeout Maximum number of polls before timing out * descr Descriptive text string of what is being waited for * (will be printed out if a timeout happens) * * Returns: * value of EVSTAT register, or 0 on failure */ static int hfa384x_wait_for_event(hfa384x_t *hw, uint16_t event_mask, uint16_t event_ack, int wait, int timeout, const char *descr) { uint16_t reg; int count = 0; do { reg = hfa384x_getreg(hw, HFA384x_EVSTAT); if ( count > 0 ) udelay(wait); count++; } while ( !(reg & event_mask) && count < timeout); if ( count >= timeout ) { printf("hfa384x: Timed out waiting for %s\n", descr); return 0; /* Return failure */ } /* Acknowledge all events that we were waiting on */ hfa384x_setreg(hw, reg & ( event_mask | event_ack ), HFA384x_EVACK); return reg; }
/************************************************************************** TRANSMIT - Transmit a frame ***************************************************************************/ static void prism2_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */ { hfa384x_t *hw = &hw_global; hfa384x_tx_frame_t txdesc; wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} }; uint16_t fid; uint16_t status; int result; // Request FID allocation result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC), HFA384x_DRVR_TXBUF_MAX, 0, 0); if (result != 0) { printf("hfa384x: Tx FID allocate command failed: Aborting transmit..\n"); return; } if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_ALLOC, HFA384x_EVACK_INFO, 10, 50, "Tx FID to be allocated\n" ) ) return; fid = hfa384x_getreg(hw, HFA384x_ALLOCFID); /* Build Tx frame structure */ memset(&txdesc, 0, sizeof(txdesc)); txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1) ); txdesc.frame_control = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) | WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY) | WLAN_SET_FC_TODS(1) ); memcpy(txdesc.address1, hw->bssid, WLAN_ADDR_LEN); memcpy(txdesc.address2, nic->node_addr, WLAN_ADDR_LEN); memcpy(txdesc.address3, d, WLAN_ADDR_LEN); txdesc.data_len = host2hfa384x_16( sizeof(txdesc) + sizeof(p80211hdr) + s ); /* Set up SNAP header */ /* Let OUI default to RFC1042 (0x000000) */ p80211hdr.snap.type = htons(t); /* Copy txdesc, p80211hdr and payload parts to FID */ result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc)); if ( result ) return; /* fail */ result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) ); if ( result ) return; /* fail */ result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (uint8_t*)p, s ); if ( result ) return; /* fail */ /* Issue Tx command */ result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX), fid, 0, 0); if ( result != 0 ) { printf("hfa384x: Transmit failed with result %#hx.\n", result); return; } /* Wait for transmit completion (or exception) */ result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO, 200, 500, "Tx to complete\n" ); if ( !result ) return; /* timeout failure */ if ( HFA384x_EVSTAT_ISTXEXC(result) ) { fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID); printf ( "Tx exception occurred with fid %#hx\n", fid ); result = hfa384x_copy_from_bap(hw, fid, 0, &status, sizeof(status)); if ( result ) return; /* fail */ printf("hfa384x: Tx error occurred (status %#hx):\n", status); if ( HFA384x_TXSTATUS_ISACKERR(status) ) { printf(" ...acknowledgement error\n"); } if ( HFA384x_TXSTATUS_ISFORMERR(status) ) { printf(" ...format error\n"); } if ( HFA384x_TXSTATUS_ISDISCON(status) ) { printf(" ...disconnected error\n"); } if ( HFA384x_TXSTATUS_ISAGEDERR(status) ) { printf(" ...AGED error\n"); } if ( HFA384x_TXSTATUS_ISRETRYERR(status) ) { printf(" ...retry error\n"); } return; /* fail */ } }
/* * Noswap versions * Etherboot is i386 only, so swap and noswap are the same... */ static inline uint16_t hfa384x_getreg_noswap( hfa384x_t *hw, unsigned int reg ) { return hfa384x_getreg ( hw, reg ); }
/* * Noswap versions * Etherboot is i386 only, so swap and noswap are the same... */ static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg ) { return hfa384x_getreg ( hw, reg ); }