/* * Written by Oron Peled * 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 #include /* for tasklets */ #include #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 */