// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Contact Information: * Intel Linux Wireless <[email protected]> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> #include <net/mac80211.h> #include "common.h" #include "3945.h" /* Send led command */ static int il3945_send_led_cmd(struct il_priv *il, struct il_led_cmd *led_cmd) { … } #define IL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) … /* * Parameter order: * rate, prev rate, next rate, prev tgg rate, next tgg rate * * If there isn't a valid next or previous rate then INV is used which * maps to RATE_INVALID * */ const struct il3945_rate_info il3945_rates[RATE_COUNT_3945] = …; static inline u8 il3945_get_prev_ieee_rate(u8 rate_idx) { … } /* 1 = enable the il3945_disable_events() function */ #define IL_EVT_DISABLE … #define IL_EVT_DISABLE_SIZE … /* * il3945_disable_events - Disable selected events in uCode event log * * Disable an event by writing "1"s into "disable" * bitmap in SRAM. Bit position corresponds to Event # (id/type). * Default values of 0 enable uCode events to be logged. * Use for only special debugging. This function is just a placeholder as-is, * you'll need to provide the special bits! ... * ... and set IL_EVT_DISABLE to 1. */ void il3945_disable_events(struct il_priv *il) { … } static int il3945_hwrate_to_plcp_idx(u8 plcp) { … } #ifdef CONFIG_IWLEGACY_DEBUG #define TX_STATUS_ENTRY(x) … static const char * il3945_get_tx_fail_reason(u32 status) { … } #else static inline const char * il3945_get_tx_fail_reason(u32 status) { return ""; } #endif /* * get ieee prev rate from rate scale table. * for A and B mode we need to overright prev * value */ int il3945_rs_next_rate(struct il_priv *il, int rate) { … } /* * il3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd * * When FW advances 'R' idx, all entries between old and new 'R' idx * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ static void il3945_tx_queue_reclaim(struct il_priv *il, int txq_id, int idx) { … } /* * il3945_hdl_tx - Handle Tx response */ static void il3945_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb) { … } /***************************************************************************** * * Intel PRO/Wireless 3945ABG/BG Network Connection * * RX handler implementations * *****************************************************************************/ #ifdef CONFIG_IWLEGACY_DEBUGFS static void il3945_accumulative_stats(struct il_priv *il, __le32 * stats) { … } #endif void il3945_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb) { … } void il3945_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb) { … } /****************************************************************************** * * Misc. internal state and helper functions * ******************************************************************************/ /* This is necessary only for a number of stats, see the caller. */ static int il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header) { … } #define SMALL_PACKET_SIZE … static void il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, struct ieee80211_rx_status *stats) { … } #define IL_DELAY_NEXT_SCAN_AFTER_ASSOC … static void il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) { … } int il3945_hw_txq_attach_buf_to_tfd(struct il_priv *il, struct il_tx_queue *txq, dma_addr_t addr, u16 len, u8 reset, u8 pad) { … } /* * il3945_hw_txq_free_tfd - Free one TFD, those at idx [txq->q.read_ptr] * * Does NOT advance any idxes */ void il3945_hw_txq_free_tfd(struct il_priv *il, struct il_tx_queue *txq) { … } /* * il3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * */ void il3945_hw_build_tx_cmd_rate(struct il_priv *il, struct il_device_cmd *cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, int sta_id) { … } static u8 il3945_sync_sta(struct il_priv *il, int sta_id, u16 tx_rate) { … } static void il3945_set_pwr_vmain(struct il_priv *il) { … } static int il3945_rx_init(struct il_priv *il, struct il_rx_queue *rxq) { … } static int il3945_tx_reset(struct il_priv *il) { … } /* * il3945_txq_ctx_reset - Reset TX queue context * * Destroys all DMA structures and initialize them again */ static int il3945_txq_ctx_reset(struct il_priv *il) { … } /* * Start up 3945's basic functionality after it has been reset * (e.g. after platform boot, or shutdown via il_apm_stop()) * NOTE: This does not load uCode nor start the embedded processor */ static int il3945_apm_init(struct il_priv *il) { … } static void il3945_nic_config(struct il_priv *il) { … } int il3945_hw_nic_init(struct il_priv *il) { … } /* * il3945_hw_txq_ctx_free - Free TXQ Context * * Destroy all TX DMA queues and structures */ void il3945_hw_txq_ctx_free(struct il_priv *il) { … } void il3945_hw_txq_ctx_stop(struct il_priv *il) { … } /* * il3945_hw_reg_adjust_power_by_temp * return idx delta into power gain settings table */ static int il3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) { … } /* * il3945_hw_reg_temp_out_of_range - Keep temperature in sane range */ static inline int il3945_hw_reg_temp_out_of_range(int temperature) { … } int il3945_hw_get_temperature(struct il_priv *il) { … } /* * il3945_hw_reg_txpower_get_temperature * get the current temperature by reading from NIC */ static int il3945_hw_reg_txpower_get_temperature(struct il_priv *il) { … } /* Adjust Txpower only if temperature variance is greater than threshold. * * Both are lower than older versions' 9 degrees */ #define IL_TEMPERATURE_LIMIT_TIMER … /* * il3945_is_temp_calib_needed - determines if new calibration is needed * * records new temperature in tx_mgr->temperature. * replaces tx_mgr->last_temperature *only* if calib needed * (assumes caller will actually do the calibration!). */ static int il3945_is_temp_calib_needed(struct il_priv *il) { … } #define IL_MAX_GAIN_ENTRIES … #define IL_CCK_FROM_OFDM_POWER_DIFF … #define IL_CCK_FROM_OFDM_IDX_DIFF … /* radio and DSP power table, each step is 1/2 dB. * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */ static struct il3945_tx_power power_gain_table[2][IL_MAX_GAIN_ENTRIES] = …; static inline u8 il3945_hw_reg_fix_power_idx(int idx) { … } /* Kick off thermal recalibration check every 60 seconds */ #define REG_RECALIB_PERIOD … /* * il3945_hw_reg_set_scan_power - Set Tx power for scan probe requests * * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK) * or 6 Mbit (OFDM) rates. */ static void il3945_hw_reg_set_scan_power(struct il_priv *il, u32 scan_tbl_idx, s32 rate_idx, const s8 *clip_pwrs, struct il_channel_info *ch_info, int band_idx) { … } /* * il3945_send_tx_power - fill in Tx Power command with gain settings * * Configures power settings for all rates for the current channel, * using values from channel info struct, and send to NIC */ static int il3945_send_tx_power(struct il_priv *il) { … } /* * il3945_hw_reg_set_new_power - Configures power tables at new levels * @ch_info: Channel to update. Uses power_info.requested_power. * * Replace requested_power and base_power_idx ch_info fields for * one channel. * * Called if user or spectrum management changes power preferences. * Takes into account h/w and modulation limitations (clip power). * * This does *not* send anything to NIC, just sets up ch_info for one channel. * * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to * properly fill out the scan powers, and actual h/w gain settings, * and send changes to NIC */ static int il3945_hw_reg_set_new_power(struct il_priv *il, struct il_channel_info *ch_info) { … } /* * il3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel * * NOTE: Returned power limit may be less (but not more) than requested, * based strictly on regulatory (eeprom and spectrum mgt) limitations * (no consideration for h/w clipping limitations). */ static int il3945_hw_reg_get_ch_txpower_limit(struct il_channel_info *ch_info) { … } /* * il3945_hw_reg_comp_txpower_temp - Compensate for temperature * * Compensate txpower settings of *all* channels for temperature. * This only accounts for the difference between current temperature * and the factory calibration temperatures, and bases the new settings * on the channel's base_power_idx. * * If RxOn is "associated", this sends the new Txpower to NIC! */ static int il3945_hw_reg_comp_txpower_temp(struct il_priv *il) { … } int il3945_hw_reg_set_txpower(struct il_priv *il, s8 power) { … } static int il3945_send_rxon_assoc(struct il_priv *il) { … } /* * il3945_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ int il3945_commit_rxon(struct il_priv *il) { … } /* * il3945_reg_txpower_periodic - called when time to check our temperature. * * -- reset periodic timer * -- see if temp has changed enough to warrant re-calibration ... if so: * -- correct coeffs for temp (can reset temp timer) * -- save this temp as "last", * -- send new set of gain settings to NIC * NOTE: This should continue working, even when we're not associated, * so we can keep our internal table of scan powers current. */ void il3945_reg_txpower_periodic(struct il_priv *il) { … } static void il3945_bg_reg_txpower_periodic(struct work_struct *work) { … } /* * il3945_hw_reg_get_ch_grp_idx - find the channel-group idx (0-4) for channel. * * This function is used when initializing channel-info structs. * * NOTE: These channel groups do *NOT* match the bands above! * These channel groups are based on factory-tested channels; * on A-band, EEPROM's "group frequency" entries represent the top * channel in each group 1-4. Group 5 All B/G channels are in group 0. */ static u16 il3945_hw_reg_get_ch_grp_idx(struct il_priv *il, const struct il_channel_info *ch_info) { … } /* * il3945_hw_reg_get_matched_power_idx - Interpolate to get nominal idx * * Interpolate to get nominal (i.e. at factory calibration temperature) idx * into radio/DSP gain settings table for requested power. */ static int il3945_hw_reg_get_matched_power_idx(struct il_priv *il, s8 requested_power, s32 setting_idx, s32 *new_idx) { … } static void il3945_hw_reg_init_channel_groups(struct il_priv *il) { … } /* * il3945_txpower_set_from_eeprom - Set channel power info based on EEPROM * * Second pass (during init) to set up il->channel_info * * Set up Tx-power settings in our channel info database for each VALID * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values * and current temperature. * * Since this is based on current temperature (at init time), these values may * not be valid for very long, but it gives us a starting/default point, * and allows us to active (i.e. using Tx) scan. * * This does *not* write values to NIC, just sets up our internal table. */ int il3945_txpower_set_from_eeprom(struct il_priv *il) { … } int il3945_hw_rxq_stop(struct il_priv *il) { … } int il3945_hw_tx_queue_init(struct il_priv *il, struct il_tx_queue *txq) { … } /* * HCMD utils */ static u16 il3945_get_hcmd_size(u8 cmd_id, u16 len) { … } static u16 il3945_build_addsta_hcmd(const struct il_addsta_cmd *cmd, u8 * data) { … } static int il3945_add_bssid_station(struct il_priv *il, const u8 * addr, u8 * sta_id_r) { … } static int il3945_manage_ibss_station(struct il_priv *il, struct ieee80211_vif *vif, bool add) { … } /* * il3945_init_hw_rate_table - Initialize the hardware rate fallback table */ int il3945_init_hw_rate_table(struct il_priv *il) { … } /* Called when initializing driver */ int il3945_hw_set_hw_params(struct il_priv *il) { … } unsigned int il3945_hw_get_beacon_cmd(struct il_priv *il, struct il3945_frame *frame, u8 rate) { … } void il3945_hw_handler_setup(struct il_priv *il) { … } void il3945_hw_setup_deferred_work(struct il_priv *il) { … } void il3945_hw_cancel_deferred_work(struct il_priv *il) { … } /* check contents of special bootstrap uCode SRAM */ static int il3945_verify_bsm(struct il_priv *il) { … } /****************************************************************************** * * EEPROM related functions * ******************************************************************************/ /* * Clear the OWNER_MSK, to establish driver (instead of uCode running on * embedded controller) as EEPROM reader; each read is a series of pulses * to/from the EEPROM chip, not a single event, so even reads could conflict * if they weren't arbitrated by some ownership mechanism. Here, the driver * simply claims ownership, which should be safe when this function is called * (i.e. before loading uCode!). */ static int il3945_eeprom_acquire_semaphore(struct il_priv *il) { … } static void il3945_eeprom_release_semaphore(struct il_priv *il) { … } /* * il3945_load_bsm - Load bootstrap instructions * * BSM operation: * * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program * in special SRAM that does not power down during RFKILL. When powering back * up after power-saving sleeps (or during initial uCode load), the BSM loads * the bootstrap program into the on-board processor, and starts it. * * The bootstrap program loads (via DMA) instructions and data for a new * program from host DRAM locations indicated by the host driver in the * BSM_DRAM_* registers. Once the new program is loaded, it starts * automatically. * * When initializing the NIC, the host driver points the BSM to the * "initialize" uCode image. This uCode sets up some internal data, then * notifies host via "initialize alive" that it is complete. * * The host then replaces the BSM_DRAM_* pointer values to point to the * normal runtime uCode instructions and a backup uCode data cache buffer * (filled initially with starting data values for the on-board processor), * then triggers the "initialize" uCode to load and launch the runtime uCode, * which begins normal operation. * * When doing a power-save shutdown, runtime uCode saves data SRAM into * the backup data cache in DRAM before SRAM is powered down. * * When powering back up, the BSM loads the bootstrap program. This reloads * the runtime uCode instructions and the backup data cache into SRAM, * and re-launches the runtime uCode from where it left off. */ static int il3945_load_bsm(struct il_priv *il) { … } const struct il_ops il3945_ops = …; static const struct il_cfg il3945_bg_cfg = …; static const struct il_cfg il3945_abg_cfg = …; const struct pci_device_id il3945_hw_card_ids[] = …; MODULE_DEVICE_TABLE(pci, il3945_hw_card_ids);