| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * Copyright (C) 2008, cozybit Inc. |
| * Copyright (C) 2007, Red Hat, Inc. |
| * Copyright (C) 2003-2006, Marvell International Ltd. |
| */ |
| #include <linux/spinlock.h> |
| #include <linux/device.h> |
| #include <linux/kthread.h> |
| #include <net/mac80211.h> |
| |
| #include "deb_defs.h" |
| |
| #ifndef DRV_NAME |
| #define DRV_NAME "libertas_tf" |
| #endif |
| |
| #define MRVL_DEFAULT_RETRIES 9 |
| #define MRVL_PER_PACKET_RATE 0x10 |
| #define MRVL_MAX_BCN_SIZE 440 |
| #define CMD_OPTION_WAITFORRSP 0x0002 |
| |
| /* Return command are almost always the same as the host command, but with |
| * bit 15 set high. There are a few exceptions, though... |
| */ |
| #define CMD_RET(cmd) (0x8000 | cmd) |
| |
| /* Command codes */ |
| #define CMD_GET_HW_SPEC 0x0003 |
| #define CMD_802_11_RESET 0x0005 |
| #define CMD_MAC_MULTICAST_ADR 0x0010 |
| #define CMD_802_11_RADIO_CONTROL 0x001c |
| #define CMD_802_11_RF_CHANNEL 0x001d |
| #define CMD_802_11_RF_TX_POWER 0x001e |
| #define CMD_MAC_CONTROL 0x0028 |
| #define CMD_802_11_MAC_ADDRESS 0x004d |
| #define CMD_SET_BOOT2_VER 0x00a5 |
| #define CMD_802_11_BEACON_CTRL 0x00b0 |
| #define CMD_802_11_BEACON_SET 0x00cb |
| #define CMD_802_11_SET_MODE 0x00cc |
| #define CMD_802_11_SET_BSSID 0x00cd |
| |
| #define CMD_ACT_GET 0x0000 |
| #define CMD_ACT_SET 0x0001 |
| |
| /* Define action or option for CMD_802_11_RESET */ |
| #define CMD_ACT_HALT 0x0003 |
| |
| /* Define action or option for CMD_MAC_CONTROL */ |
| #define CMD_ACT_MAC_RX_ON 0x0001 |
| #define CMD_ACT_MAC_TX_ON 0x0002 |
| #define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 |
| #define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 |
| #define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 |
| #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 |
| |
| /* Define action or option for CMD_802_11_RADIO_CONTROL */ |
| #define CMD_TYPE_AUTO_PREAMBLE 0x0001 |
| #define CMD_TYPE_SHORT_PREAMBLE 0x0002 |
| #define CMD_TYPE_LONG_PREAMBLE 0x0003 |
| |
| #define TURN_ON_RF 0x01 |
| #define RADIO_ON 0x01 |
| #define RADIO_OFF 0x00 |
| |
| #define SET_AUTO_PREAMBLE 0x05 |
| #define SET_SHORT_PREAMBLE 0x03 |
| #define SET_LONG_PREAMBLE 0x01 |
| |
| /* Define action or option for CMD_802_11_RF_CHANNEL */ |
| #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 |
| #define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 |
| |
| /* Codes for CMD_802_11_SET_MODE */ |
| enum lbtf_mode { |
| LBTF_PASSIVE_MODE, |
| LBTF_STA_MODE, |
| LBTF_AP_MODE, |
| }; |
| |
| /** Card Event definition */ |
| #define MACREG_INT_CODE_FIRMWARE_READY 48 |
| /** Buffer Constants */ |
| |
| /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical |
| * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas |
| * driver has more local TxPDs. Each TxPD on the host memory is associated |
| * with a Tx control node. The driver maintains 8 RxPD descriptors for |
| * station firmware to store Rx packet information. |
| * |
| * Current version of MAC has a 32x6 multicast address buffer. |
| * |
| * 802.11b can have up to 14 channels, the driver keeps the |
| * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. |
| */ |
| |
| #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 |
| #define LBS_NUM_CMD_BUFFERS 10 |
| #define LBS_CMD_BUFFER_SIZE (2 * 1024) |
| #define MRVDRV_MAX_CHANNEL_SIZE 14 |
| #define MRVDRV_SNAP_HEADER_LEN 8 |
| |
| #define LBS_UPLD_SIZE 2312 |
| #define DEV_NAME_LEN 32 |
| |
| /** Misc constants */ |
| /* This section defines 802.11 specific contants */ |
| |
| #define MRVDRV_MAX_REGION_CODE 6 |
| /** |
| * the table to keep region code |
| */ |
| #define LBTF_REGDOMAIN_US 0x10 |
| #define LBTF_REGDOMAIN_CA 0x20 |
| #define LBTF_REGDOMAIN_EU 0x30 |
| #define LBTF_REGDOMAIN_SP 0x31 |
| #define LBTF_REGDOMAIN_FR 0x32 |
| #define LBTF_REGDOMAIN_JP 0x40 |
| |
| #define SBI_EVENT_CAUSE_SHIFT 3 |
| |
| /** RxPD status */ |
| |
| #define MRVDRV_RXPD_STATUS_OK 0x0001 |
| |
| |
| /* This is for firmware specific length */ |
| #define EXTRA_LEN 36 |
| |
| #define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ |
| (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) |
| |
| #define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ |
| (ETH_FRAME_LEN + sizeof(struct rxpd) \ |
| + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) |
| |
| #define CMD_F_HOSTCMD (1 << 0) |
| #define FW_CAPINFO_WPA (1 << 0) |
| |
| #define RF_ANTENNA_1 0x1 |
| #define RF_ANTENNA_2 0x2 |
| #define RF_ANTENNA_AUTO 0xFFFF |
| |
| #define LBTF_EVENT_BCN_SENT 55 |
| |
| /** Global Variable Declaration */ |
| /** mv_ms_type */ |
| enum mv_ms_type { |
| MVMS_DAT = 0, |
| MVMS_CMD = 1, |
| MVMS_TXDONE = 2, |
| MVMS_EVENT |
| }; |
| |
| extern struct workqueue_struct *lbtf_wq; |
| |
| struct lbtf_private; |
| |
| struct lbtf_offset_value { |
| u32 offset; |
| u32 value; |
| }; |
| |
| struct channel_range { |
| u8 regdomain; |
| u8 start; |
| u8 end; /* exclusive (channel must be less than end) */ |
| }; |
| |
| struct if_usb_card; |
| |
| struct lbtf_ops { |
| /** Hardware access */ |
| int (*hw_host_to_card)(struct lbtf_private *priv, u8 type, |
| u8 *payload, u16 nb); |
| int (*hw_prog_firmware)(struct lbtf_private *priv); |
| int (*hw_reset_device)(struct lbtf_private *priv); |
| }; |
| |
| /** Private structure for the MV device */ |
| struct lbtf_private { |
| void *card; |
| struct ieee80211_hw *hw; |
| const struct lbtf_ops *ops; |
| |
| /* Command response buffer */ |
| u8 cmd_resp_buff[LBS_UPLD_SIZE]; |
| /* Download sent: |
| bit0 1/0=data_sent/data_tx_done, |
| bit1 1/0=cmd_sent/cmd_tx_done, |
| all other bits reserved 0 */ |
| struct ieee80211_vif *vif; |
| |
| struct work_struct cmd_work; |
| struct work_struct tx_work; |
| |
| /** Wlan adapter data structure*/ |
| /** STATUS variables */ |
| u32 fwrelease; |
| u32 fwcapinfo; |
| /* protected with big lock */ |
| |
| struct mutex lock; |
| |
| /** command-related variables */ |
| u16 seqnum; |
| /* protected by big lock */ |
| |
| struct cmd_ctrl_node *cmd_array; |
| /** Current command */ |
| struct cmd_ctrl_node *cur_cmd; |
| /** command Queues */ |
| /** Free command buffers */ |
| struct list_head cmdfreeq; |
| /** Pending command buffers */ |
| struct list_head cmdpendingq; |
| |
| /** spin locks */ |
| spinlock_t driver_lock; |
| |
| /** Timers */ |
| struct timer_list command_timer; |
| int nr_retries; |
| int cmd_timed_out; |
| |
| u8 cmd_response_rxed; |
| |
| /** capability Info used in Association, start, join */ |
| u16 capability; |
| |
| /** MAC address information */ |
| u8 current_addr[ETH_ALEN]; |
| u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; |
| u32 nr_of_multicastmacaddr; |
| int cur_freq; |
| |
| struct sk_buff *skb_to_tx; |
| struct sk_buff *tx_skb; |
| |
| /** NIC Operation characteristics */ |
| u16 mac_control; |
| u16 regioncode; |
| struct channel_range range; |
| |
| u8 radioon; |
| u32 preamble; |
| |
| struct ieee80211_channel channels[14]; |
| struct ieee80211_rate rates[12]; |
| struct ieee80211_supported_band band; |
| struct lbtf_offset_value offsetvalue; |
| |
| u8 surpriseremoved; |
| struct sk_buff_head bc_ps_buf; |
| |
| /* Most recently reported noise in dBm */ |
| s8 noise; |
| }; |
| |
| /* 802.11-related definitions */ |
| |
| /* TxPD descriptor */ |
| struct txpd { |
| /* Current Tx packet status */ |
| __le32 tx_status; |
| /* Tx control */ |
| __le32 tx_control; |
| __le32 tx_packet_location; |
| /* Tx packet length */ |
| __le16 tx_packet_length; |
| struct_group_attr(tx_dest_addr, __packed, |
| /* First 2 byte of destination MAC address */ |
| u8 tx_dest_addr_high[2]; |
| /* Last 4 byte of destination MAC address */ |
| u8 tx_dest_addr_low[4]; |
| ); |
| /* Pkt Priority */ |
| u8 priority; |
| /* Pkt Trasnit Power control */ |
| u8 powermgmt; |
| /* Time the packet has been queued in the driver (units = 2ms) */ |
| u8 pktdelay_2ms; |
| /* reserved */ |
| u8 reserved1; |
| } __packed; |
| |
| /* RxPD Descriptor */ |
| struct rxpd { |
| /* Current Rx packet status */ |
| __le16 status; |
| |
| /* SNR */ |
| u8 snr; |
| |
| /* Tx control */ |
| u8 rx_control; |
| |
| /* Pkt length */ |
| __le16 pkt_len; |
| |
| /* Noise Floor */ |
| u8 nf; |
| |
| /* Rx Packet Rate */ |
| u8 rx_rate; |
| |
| /* Pkt addr */ |
| __le32 pkt_ptr; |
| |
| /* Next Rx RxPD addr */ |
| __le32 next_rxpd_ptr; |
| |
| /* Pkt Priority */ |
| u8 priority; |
| u8 reserved[3]; |
| } __packed; |
| |
| struct cmd_header { |
| __le16 command; |
| __le16 size; |
| __le16 seqnum; |
| __le16 result; |
| } __packed; |
| |
| struct cmd_ctrl_node { |
| struct list_head list; |
| int result; |
| /* command response */ |
| int (*callback)(struct lbtf_private *, |
| unsigned long, struct cmd_header *); |
| unsigned long callback_arg; |
| /* command data */ |
| struct cmd_header *cmdbuf; |
| /* wait queue */ |
| u16 cmdwaitqwoken; |
| wait_queue_head_t cmdwait_q; |
| }; |
| |
| /* |
| * Define data structure for CMD_GET_HW_SPEC |
| * This structure defines the response for the GET_HW_SPEC command |
| */ |
| struct cmd_ds_get_hw_spec { |
| struct cmd_header hdr; |
| |
| /* HW Interface version number */ |
| __le16 hwifversion; |
| /* HW version number */ |
| __le16 version; |
| /* Max number of TxPD FW can handle */ |
| __le16 nr_txpd; |
| /* Max no of Multicast address */ |
| __le16 nr_mcast_adr; |
| /* MAC address */ |
| u8 permanentaddr[6]; |
| |
| /* region Code */ |
| __le16 regioncode; |
| |
| /* Number of antenna used */ |
| __le16 nr_antenna; |
| |
| /* FW release number, example 0x01030304 = 2.3.4p1 */ |
| __le32 fwrelease; |
| |
| /* Base Address of TxPD queue */ |
| __le32 wcb_base; |
| /* Read Pointer of RxPd queue */ |
| __le32 rxpd_rdptr; |
| |
| /* Write Pointer of RxPd queue */ |
| __le32 rxpd_wrptr; |
| |
| /*FW/HW capability */ |
| __le32 fwcapinfo; |
| } __packed; |
| |
| struct cmd_ds_mac_control { |
| struct cmd_header hdr; |
| __le16 action; |
| u16 reserved; |
| } __packed; |
| |
| struct cmd_ds_802_11_mac_address { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| uint8_t macadd[ETH_ALEN]; |
| } __packed; |
| |
| struct cmd_ds_mac_multicast_addr { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| __le16 nr_of_adrs; |
| u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; |
| } __packed; |
| |
| struct cmd_ds_set_mode { |
| struct cmd_header hdr; |
| |
| __le16 mode; |
| } __packed; |
| |
| struct cmd_ds_set_bssid { |
| struct cmd_header hdr; |
| |
| u8 bssid[6]; |
| u8 activate; |
| } __packed; |
| |
| struct cmd_ds_802_11_radio_control { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| __le16 control; |
| } __packed; |
| |
| |
| struct cmd_ds_802_11_rf_channel { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| __le16 channel; |
| __le16 rftype; /* unused */ |
| __le16 reserved; /* unused */ |
| u8 channellist[32]; /* unused */ |
| } __packed; |
| |
| struct cmd_ds_set_boot2_ver { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| __le16 version; |
| } __packed; |
| |
| struct cmd_ds_802_11_reset { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| } __packed; |
| |
| struct cmd_ds_802_11_beacon_control { |
| struct cmd_header hdr; |
| |
| __le16 action; |
| __le16 beacon_enable; |
| __le16 beacon_period; |
| } __packed; |
| |
| struct cmd_ds_802_11_beacon_set { |
| struct cmd_header hdr; |
| |
| __le16 len; |
| u8 beacon[MRVL_MAX_BCN_SIZE]; |
| } __packed; |
| |
| struct cmd_ctrl_node; |
| |
| /** Function Prototype Declaration */ |
| void lbtf_set_mac_control(struct lbtf_private *priv); |
| |
| int lbtf_free_cmd_buffer(struct lbtf_private *priv); |
| |
| int lbtf_allocate_cmd_buffer(struct lbtf_private *priv); |
| int lbtf_execute_next_command(struct lbtf_private *priv); |
| int lbtf_set_radio_control(struct lbtf_private *priv); |
| int lbtf_update_hw_spec(struct lbtf_private *priv); |
| int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv); |
| void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode); |
| void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid); |
| int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr); |
| |
| int lbtf_set_channel(struct lbtf_private *priv, u8 channel); |
| |
| int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon); |
| int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable, |
| int beacon_int); |
| |
| |
| int lbtf_process_rx_command(struct lbtf_private *priv); |
| void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, |
| int result); |
| void lbtf_cmd_response_rx(struct lbtf_private *priv); |
| |
| /* main.c */ |
| struct chan_freq_power *lbtf_get_region_cfp_table(u8 region, |
| int *cfp_no); |
| struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, |
| const struct lbtf_ops *ops); |
| int lbtf_remove_card(struct lbtf_private *priv); |
| int lbtf_start_card(struct lbtf_private *priv); |
| int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb); |
| void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail); |
| void lbtf_bcn_sent(struct lbtf_private *priv); |
| |
| /* support functions for cmd.c */ |
| /* lbtf_cmd() infers the size of the buffer to copy data back into, from |
| the size of the target of the pointer. Since the command to be sent |
| may often be smaller, that size is set in cmd->size by the caller.*/ |
| #define lbtf_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ |
| uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ |
| (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \ |
| __lbtf_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \ |
| }) |
| |
| #define lbtf_cmd_with_response(priv, cmdnr, cmd) \ |
| lbtf_cmd(priv, cmdnr, cmd, lbtf_cmd_copyback, (unsigned long) (cmd)) |
| |
| void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command, |
| struct cmd_header *in_cmd, int in_cmd_size); |
| |
| int __lbtf_cmd(struct lbtf_private *priv, uint16_t command, |
| struct cmd_header *in_cmd, int in_cmd_size, |
| int (*callback)(struct lbtf_private *, unsigned long, |
| struct cmd_header *), |
| unsigned long callback_arg); |
| |
| int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra, |
| struct cmd_header *resp); |