bf3fe05dfb
This needs some more testing before it's on by default. If the card is otherwise functioning, these messages may be confusing to the user. If the card is not functioning, the driver can be reloaded with debug to check for this condition. Signed-off-by: Shaun Ruffell <sruffell@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9205 a0bf4364-ded3-4de4-8d8a-66a801d63aff
357 lines
9.3 KiB
C
357 lines
9.3 KiB
C
/*
|
|
* Written by Oron Peled <oron@actcom.co.il>
|
|
* Copyright (C) 2004-2006, Xorcom
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
#ifndef XBUS_CORE_H
|
|
#define XBUS_CORE_H
|
|
|
|
#include <linux/wait.h>
|
|
#include <linux/interrupt.h> /* for tasklets */
|
|
#include <linux/kref.h>
|
|
#include "xpd.h"
|
|
#include "xframe_queue.h"
|
|
#include "xbus-pcm.h"
|
|
|
|
#define MAX_BUSES 32
|
|
#define XFRAME_DATASIZE 512
|
|
|
|
/* forward declarations */
|
|
struct xbus_workqueue;
|
|
#ifdef XPP_DEBUGFS
|
|
struct debugfs_data;
|
|
#endif
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
struct xbus_ops {
|
|
int (*xframe_send_pcm)(xbus_t *xbus, xframe_t *xframe);
|
|
int (*xframe_send_cmd)(xbus_t *xbus, xframe_t *xframe);
|
|
xframe_t *(*alloc_xframe)(xbus_t *xbus, gfp_t gfp_flags);
|
|
void (*free_xframe)(xbus_t *xbus, xframe_t *xframe);
|
|
};
|
|
|
|
/*
|
|
* XBUS statistics counters
|
|
*/
|
|
enum {
|
|
XBUS_N_UNITS,
|
|
XBUS_N_TX_XFRAME_PCM,
|
|
XBUS_N_RX_XFRAME_PCM,
|
|
XBUS_N_TX_PACK_PCM,
|
|
XBUS_N_RX_PACK_PCM,
|
|
XBUS_N_TX_BYTES,
|
|
XBUS_N_RX_BYTES,
|
|
XBUS_N_TX_PCM_FRAG,
|
|
XBUS_N_RX_CMD,
|
|
XBUS_N_TX_CMD,
|
|
};
|
|
|
|
#define XBUS_COUNTER(xbus, counter) ((xbus)->counters[XBUS_N_ ## counter])
|
|
|
|
#define C_(x) [ XBUS_N_ ## x ] = { #x }
|
|
|
|
/* yucky, make an instance so we can size it... */
|
|
static struct xbus_counters {
|
|
char *name;
|
|
} xbus_counters[] = {
|
|
C_(UNITS),
|
|
C_(TX_XFRAME_PCM),
|
|
C_(RX_XFRAME_PCM),
|
|
C_(TX_PACK_PCM),
|
|
C_(RX_PACK_PCM),
|
|
C_(TX_BYTES),
|
|
C_(RX_BYTES),
|
|
C_(TX_PCM_FRAG),
|
|
C_(RX_CMD),
|
|
C_(TX_CMD),
|
|
};
|
|
|
|
#undef C_
|
|
|
|
#define XBUS_COUNTER_MAX ARRAY_SIZE(xbus_counters)
|
|
|
|
enum xbus_state {
|
|
XBUS_STATE_START,
|
|
XBUS_STATE_IDLE,
|
|
XBUS_STATE_SENT_REQUEST,
|
|
XBUS_STATE_RECVD_DESC,
|
|
XBUS_STATE_READY,
|
|
XBUS_STATE_DEACTIVATING,
|
|
XBUS_STATE_DEACTIVATED,
|
|
XBUS_STATE_FAIL,
|
|
};
|
|
|
|
const char *xbus_statename(enum xbus_state st);
|
|
|
|
struct xbus_transport {
|
|
struct xbus_ops *ops;
|
|
void *priv;
|
|
struct device *transport_device;
|
|
ushort max_send_size;
|
|
enum xbus_state xbus_state;
|
|
unsigned long transport_flags;
|
|
spinlock_t state_lock;
|
|
atomic_t transport_refcount;
|
|
wait_queue_head_t transport_unused;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
#define MAX_SEND_SIZE(xbus) ((xbus)->transport.max_send_size)
|
|
#define XBUS_STATE(xbus) ((xbus)->transport.xbus_state)
|
|
#define XBUS_IS(xbus, st) (XBUS_STATE(xbus) == XBUS_STATE_ ## st)
|
|
#define TRANSPORT_EXIST(xbus) ((xbus)->transport.ops != NULL)
|
|
|
|
#define XBUS_FLAG_CONNECTED 0
|
|
#define XBUS_FLAGS(xbus, flg) test_bit(XBUS_FLAG_ ## flg, &((xbus)->transport.transport_flags))
|
|
|
|
struct xbus_ops *transportops_get(xbus_t *xbus);
|
|
void transportops_put(xbus_t *xbus);
|
|
|
|
/*
|
|
* Encapsulate all poll related data of a single xbus.
|
|
*/
|
|
struct xbus_workqueue {
|
|
struct workqueue_struct *wq;
|
|
struct work_struct xpds_init_work;
|
|
bool xpds_init_done;
|
|
struct list_head card_list;
|
|
int num_units;
|
|
int num_units_initialized;
|
|
wait_queue_head_t wait_for_xpd_initialization;
|
|
#ifdef CONFIG_PROC_FS
|
|
#ifdef OLD_PROC
|
|
struct proc_dir_entry *proc_xbus_waitfor_xpds;
|
|
#endif
|
|
#endif
|
|
spinlock_t worker_lock;
|
|
struct semaphore running_initialization;
|
|
};
|
|
|
|
/*
|
|
* Allocate/Free an xframe from pools of empty xframes.
|
|
* Calls to {get,put}_xframe are wrapped in
|
|
* the macros bellow, so we take/return it
|
|
* to the correct pool.
|
|
*/
|
|
xframe_t *get_xframe(struct xframe_queue *q);
|
|
void put_xframe(struct xframe_queue *q, xframe_t *xframe);
|
|
|
|
#define ALLOC_SEND_XFRAME(xbus) get_xframe(&(xbus)->send_pool)
|
|
#define ALLOC_RECV_XFRAME(xbus) get_xframe(&(xbus)->receive_pool)
|
|
#define FREE_SEND_XFRAME(xbus, xframe) put_xframe(&(xbus)->send_pool, (xframe))
|
|
#define FREE_RECV_XFRAME(xbus, xframe) put_xframe(&(xbus)->receive_pool, (xframe))
|
|
|
|
xbus_t *xbus_num(uint num);
|
|
xbus_t *get_xbus(const char *msg, uint num);
|
|
void put_xbus(const char *msg, xbus_t *xbus);
|
|
int refcount_xbus(xbus_t *xbus);
|
|
|
|
/*
|
|
* An xbus is a transport layer for Xorcom Protocol commands
|
|
*/
|
|
struct xbus {
|
|
char busname[XBUS_NAMELEN]; /* set by xbus_new() */
|
|
|
|
/* low-level bus drivers set these 2 fields */
|
|
char connector[XBUS_DESCLEN];
|
|
char label[LABEL_SIZE];
|
|
byte revision; /* Protocol revision */
|
|
struct xbus_transport transport;
|
|
|
|
int num;
|
|
struct xpd *xpds[MAX_XPDS];
|
|
|
|
int command_tick_counter;
|
|
int usec_nosend; /* Firmware flow control */
|
|
struct xframe_queue command_queue;
|
|
wait_queue_head_t command_queue_empty;
|
|
|
|
struct xframe_queue send_pool; /* empty xframes for send */
|
|
struct xframe_queue receive_pool; /* empty xframes for receive */
|
|
|
|
/* tasklet processing */
|
|
struct xframe_queue receive_queue;
|
|
struct tasklet_struct receive_tasklet;
|
|
int cpu_rcv_intr[NR_CPUS];
|
|
int cpu_rcv_tasklet[NR_CPUS];
|
|
|
|
bool self_ticking;
|
|
enum sync_mode sync_mode;
|
|
/* Managed by low-level drivers: */
|
|
enum sync_mode sync_mode_default;
|
|
struct timer_list command_timer;
|
|
unsigned int xbus_frag_count;
|
|
struct xframe_queue pcm_tospan;
|
|
|
|
struct xpp_ticker ticker; /* for tick rate */
|
|
struct xpp_drift drift; /* for tick offset */
|
|
|
|
atomic_t pcm_rx_counter;
|
|
unsigned int global_counter;
|
|
|
|
/* Device-Model */
|
|
struct device astribank;
|
|
#define dev_to_xbus(dev) container_of(dev, struct xbus, astribank)
|
|
struct kref kref;
|
|
#define kref_to_xbus(k) container_of(k, struct xbus, kref)
|
|
|
|
spinlock_t lock;
|
|
|
|
/* PCM metrics */
|
|
struct timeval last_tx_sync;
|
|
struct timeval last_rx_sync;
|
|
unsigned long max_tx_sync;
|
|
unsigned long min_tx_sync;
|
|
unsigned long max_rx_sync;
|
|
unsigned long min_rx_sync;
|
|
unsigned long max_rx_process; /* packet processing time (usec) */
|
|
#ifdef SAMPLE_TICKS
|
|
#define SAMPLE_SIZE 1000
|
|
int sample_ticks[SAMPLE_SIZE];
|
|
bool sample_running;
|
|
int sample_pos;
|
|
#endif
|
|
|
|
struct xbus_workqueue worker;
|
|
|
|
/*
|
|
* Sync adjustment
|
|
*/
|
|
int sync_adjustment;
|
|
int sync_adjustment_offset;
|
|
long pll_updated_at;
|
|
|
|
atomic_t num_xpds;
|
|
|
|
#ifdef XPP_DEBUGFS
|
|
struct dentry *debugfs_dir;
|
|
struct dentry *debugfs_file;
|
|
struct debugfs_data *debugfs_data;
|
|
#endif
|
|
#ifdef CONFIG_PROC_FS
|
|
struct proc_dir_entry *proc_xbus_dir;
|
|
struct proc_dir_entry *proc_xbus_summary;
|
|
#ifdef PROTOCOL_DEBUG
|
|
struct proc_dir_entry *proc_xbus_command;
|
|
#endif
|
|
#endif
|
|
|
|
/* statistics */
|
|
int counters[XBUS_COUNTER_MAX];
|
|
};
|
|
#endif
|
|
|
|
#define XFRAME_MAGIC 123456L
|
|
|
|
struct xframe {
|
|
unsigned long xframe_magic;
|
|
struct list_head frame_list;
|
|
atomic_t frame_len;
|
|
xbus_t *xbus;
|
|
struct timeval tv_created;
|
|
struct timeval tv_queued;
|
|
struct timeval tv_submitted;
|
|
struct timeval tv_received;
|
|
/* filled by transport layer */
|
|
size_t frame_maxlen;
|
|
byte *packets; /* max XFRAME_DATASIZE */
|
|
byte *first_free;
|
|
int usec_towait; /* prevent overflowing AB */
|
|
void *priv;
|
|
};
|
|
|
|
void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv);
|
|
|
|
#define XFRAME_LEN(frame) atomic_read(&(frame)->frame_len)
|
|
|
|
int xbus_core_init(void); /* Initializer */
|
|
void xbus_core_shutdown(void); /* Terminator */
|
|
|
|
#ifdef XPP_DEBUGFS
|
|
/* Debugfs handling */
|
|
int xbus_log(xbus_t *xbus, xpd_t *xpd, int direction, const void *buf, unsigned long len);
|
|
#endif
|
|
|
|
/* Frame handling */
|
|
void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug);
|
|
int send_cmd_frame(xbus_t *xbus, xframe_t *xframe);
|
|
|
|
/*
|
|
* Return pointer to next packet slot in the frame
|
|
* or NULL if the frame is full.
|
|
*/
|
|
xpacket_t *xframe_next_packet(xframe_t *xframe, int len);
|
|
|
|
/* XBUS handling */
|
|
|
|
/*
|
|
* Map: unit+subunit <--> index in xbus->xpds[]
|
|
*/
|
|
#define XPD_IDX(unit,subunit) ((unit) * MAX_SUBUNIT + (subunit))
|
|
#define XBUS_UNIT(idx) ((idx) / MAX_SUBUNIT)
|
|
#define XBUS_SUBUNIT(idx) ((idx) % MAX_SUBUNIT)
|
|
|
|
xpd_t *xpd_of(const xbus_t *xbus, int xpd_num);
|
|
xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit);
|
|
int xbus_check_unique(xbus_t *xbus);
|
|
bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate);
|
|
bool xbus_setflags(xbus_t *xbus, int flagbit, bool on);
|
|
xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv);
|
|
void xbus_free(xbus_t *xbus);
|
|
int xbus_connect(xbus_t *xbus);
|
|
int xbus_activate(xbus_t *xbus);
|
|
void xbus_deactivate(xbus_t *xbus);
|
|
void xbus_disconnect(xbus_t *xbus);
|
|
void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe);
|
|
int xbus_process_worker(xbus_t *xbus);
|
|
int waitfor_xpds(xbus_t *xbus, char *buf);
|
|
|
|
int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit);
|
|
int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd);
|
|
|
|
/* sysfs */
|
|
int xpd_device_register(xbus_t *xbus, xpd_t *xpd);
|
|
void xpd_device_unregister(xpd_t *xpd);
|
|
|
|
int xpp_driver_init(void);
|
|
void xpp_driver_exit(void);
|
|
int xbus_sysfs_transport_create(xbus_t *xbus);
|
|
void xbus_sysfs_transport_remove(xbus_t *xbus);
|
|
int xbus_sysfs_create(xbus_t *xbus);
|
|
void xbus_sysfs_remove(xbus_t *xbus);
|
|
|
|
#ifdef OLD_HOTPLUG_SUPPORT_269
|
|
/* Copy from new kernels lib/kobject_uevent.c */
|
|
enum kobject_action {
|
|
KOBJ_ADD,
|
|
KOBJ_REMOVE,
|
|
KOBJ_CHANGE,
|
|
KOBJ_MOUNT,
|
|
KOBJ_UMOUNT,
|
|
KOBJ_OFFLINE,
|
|
KOBJ_ONLINE,
|
|
};
|
|
#endif
|
|
|
|
void astribank_uevent_send(xbus_t *xbus, enum kobject_action act);
|
|
|
|
#endif /* XBUS_CORE_H */
|
|
|