blob: 521e12ae28c6d1247d8031d719069aca554e6844 [file] [log] [blame]
/*
* Copyright (c) 2018 The Fuchsia Authors
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef BRCMF_DEVICE_H
#define BRCMF_DEVICE_H
#include <assert.h>
#include <ddk/driver.h>
#include <ddk/protocol/pci.h>
#include <ddk/protocol/pci-lib.h>
#include <ddk/protocol/usb.h>
#include <lib/async-loop/loop.h> // to start the worker thread
#include <lib/async/default.h> // for async_get_default_dispatcher()
#include <lib/async/task.h> // for async_post_task()
#include <lib/async/time.h> // for async_now()
#include <pthread.h>
#include <string.h>
#include <lib/sync/completion.h>
#include <threads.h>
#include <wlan/protocol/if-impl.h>
#include <zircon/listnode.h>
#include <zircon/types.h>
#include "debug.h"
#include "usb.h"
#define BACKPLANE_ID_HIGH_REVCODE_HIGH 0x7000
#define BACKPLANE_ID_HIGH_REVCODE_HIGH_SHIFT 8
#define BACKPLANE_ID_HIGH_REVCODE_LOW 0xf
#define BACKPLANE_ID_LOW_INITIATOR 0x80
#define BACKPLANE_TARGET_STATE_LOW_RESET 0x00001
#define BACKPLANE_TARGET_STATE_LOW_REJECT 0x00002
#define BACKPLANE_TARGET_STATE_LOW_CLOCK 0x10000
#define BACKPLANE_TARGET_STATE_LOW_GATED_CLOCKS 0x20000
#define BACKPLANE_TARGET_STATE_HIGH_S_ERROR 0x00001
#define BACKPLANE_TARGET_STATE_HIGH_BUSY 0x00004
#define BACKPLANE_INITIATOR_STATE_REJECT 0x2000000
#define BACKPLANE_INITIATOR_STATE_BUSY 0x1800000
#define BACKPLANE_INITIATOR_STATE_IN_BAND_ERROR 0x0020000
#define BACKPLANE_INITIATOR_STATE_TIMEOUT 0x0040000
#define BC_CORE_CONTROL 0x0408
#define BC_CORE_CONTROL_FGC 0x2
#define BC_CORE_CONTROL_CLOCK 0x1
#define BC_CORE_RESET_CONTROL 0x800
#define BC_CORE_RESET_CONTROL_RESET 0x1
#define BC_CORE_ASYNC_BACKOFF_CAPABILITY_PRESENT 0x40
#define BC_CORE_POWER_CONTROL_RELOAD 0x2
#define BC_CORE_POWER_CONTROL_SHIFT 13
#define BRCMF_ERR_FIRMWARE_UNSUPPORTED (-23)
#define max(a, b) ((a)>(b)?(a):(b))
extern async_dispatcher_t* default_dispatcher;
// This is the function that timer users write to receive callbacks.
typedef void (brcmf_timer_callback_t)(void* data);
typedef struct brcmf_timer_info {
async_task_t task;
void* data;
brcmf_timer_callback_t* callback_function;
bool scheduled;
sync_completion_t finished;
mtx_t lock;
} brcmf_timer_info_t;
void brcmf_timer_init(brcmf_timer_info_t* timer, brcmf_timer_callback_t* callback, void* data);
void brcmf_timer_set(brcmf_timer_info_t* timer, zx_duration_t delay);
void brcmf_timer_stop(brcmf_timer_info_t* timer);
static inline bool address_is_multicast(const uint8_t* address) {
return 1 & *address;
}
static inline bool address_is_broadcast(const uint8_t* address) {
static uint8_t all_ones[] = {255, 255, 255, 255, 255, 255};
static_assert(ETH_ALEN == 6, "Oops");
return !memcmp(address, all_ones, ETH_ALEN);
}
static inline bool address_is_zero(const uint8_t* address) {
static uint8_t all_zeros[] = {0, 0, 0, 0, 0, 0};
static_assert(ETH_ALEN == 6, "Oops");
return !memcmp(address, all_zeros, ETH_ALEN);
}
static inline void fill_with_broadcast_addr(uint8_t* address) {
memset(address, 0xff, ETH_ALEN);
}
static inline void fill_with_zero_addr(uint8_t* address) {
memset(address, 0, ETH_ALEN);
}
enum {ADDRESSED_TO_MULTICAST = 1, ADDRESSED_TO_BROADCAST, ADDRESSED_TO_OTHER_HOST};
struct brcmf_bus;
struct brcmf_device {
void* of_node;
void* parent;
struct brcmf_bus* bus;
zx_device_t* zxdev;
zx_device_t* phy_zxdev;
zx_device_t* if_zxdev;
};
static inline struct brcmf_bus* dev_to_bus(struct brcmf_device* dev) {
return dev->bus;
}
struct brcmf_usb_interface_descriptor {
int bInterfaceClass;
int bInterfaceSubClass;
int bInterfaceProtocol;
int bInterfaceNumber;
int bNumEndpoints;
};
struct brcmf_usb_device {
usb_speed_t speed;
struct brcmf_device dev;
struct {
int bNumConfigurations;
int bDeviceClass;
} descriptor;
size_t parent_req_size;
};
struct brcmf_endpoint_container {
usb_endpoint_descriptor_t desc;
};
struct brcmf_usb_altsetting {
struct brcmf_usb_interface_descriptor desc;
struct brcmf_endpoint_container* endpoint;
};
struct brcmf_usb_interface {
struct brcmf_usb_altsetting* altsetting;
struct brcmf_usb_device* usb_device;
void* intfdata;
};
struct brcmf_usb_device_id {
int idVendor;
int idProduct;
};
struct brcmf_firmware {
size_t size;
void* data;
};
// Used in net_device.flags to indicate interface is up.
#define IFF_UP 1
struct net_device {
struct wireless_dev* ieee80211_ptr;
bool initialized_for_ap;
bool scan_busy;
uint64_t scan_txn_id;
wlanif_impl_ifc_t* if_callbacks;
void* if_callback_cookie;
uint8_t dev_addr[ETH_ALEN];
char name[123];
void* priv;
uint32_t flags;
struct {
int tx_dropped;
int tx_packets;
int tx_bytes;
int rx_packets;
int rx_bytes;
int multicast;
int rx_errors;
int tx_errors;
} stats;
uint32_t features;
uint32_t needed_headroom;
void* priv_destructor;
int reg_state;
int needs_free_net_device;
};
struct brcmf_bus* dev_to_bus(struct brcmf_device* dev);
// TODO(cphoenix): Wrap around whatever completion functions exist in PCIE and SDIO.
// TODO(cphoenix): To improve efficiency, analyze which spinlocks only need to protect small
// critical subsections of the completion functions. For those, bring back the individual spinlock.
// Note: This is a pthread_mutex_t instead of mtx_t because mtx_t doesn't implement recursive.
extern pthread_mutex_t irq_callback_lock;
struct net_device* brcmf_allocate_net_device(size_t priv_size, const char* name);
void brcmf_free_net_device(struct net_device* dev);
void brcmf_enable_tx(struct net_device* dev);
static inline struct brcmf_usb_device* intf_to_usbdev(const struct brcmf_usb_interface* intf) {
return intf->usb_device;
}
// TODO(cphoenix): Fix this hack
#define ieee80211_frequency_to_channel(freq) (freq)
bool brcmf_test_and_set_bit_in_array(size_t bit_number, atomic_ulong* addr);
bool brcmf_test_and_clear_bit_in_array(size_t bit_number, atomic_ulong* addr);
bool brcmf_test_bit_in_array(size_t bit_number, atomic_ulong* addr);
void brcmf_clear_bit_in_array(size_t bit_number, atomic_ulong* addr);
void brcmf_set_bit_in_array(size_t bit_number, atomic_ulong* addr);
zx_status_t brcmf_debugfs_create_directory(const char *name, zx_handle_t parent,
zx_handle_t* new_directory_out);
zx_status_t brcmf_debugfs_create_sequential_file(void* dev, const char* fn, zx_handle_t parent,
zx_status_t (*read_fn)(struct seq_file* seq,
void* data),
zx_handle_t* new_file_out);
zx_status_t brcmf_debugfs_rm_recursive(zx_handle_t dir);
zx_status_t brcmf_debugfs_create_u32_file(const char* name, uint32_t permissions,
zx_handle_t parent, uint32_t* data_to_access);
#endif /* BRCMF_DEVICE_H */