Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _FIREWIRE_FWSERIAL_H #define _FIREWIRE_FWSERIAL_H #include <linux/kernel.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/list.h> #include <linux/firewire.h> #include <linux/firewire-constants.h> #include <linux/spinlock.h> #include <linux/rcupdate.h> #include <linux/mutex.h> #include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/module.h> #include <linux/seq_file.h> #include <linux/debugfs.h> #include "dma_fifo.h" #ifdef FWTTY_PROFILING #define DISTRIBUTION_MAX_SIZE 8192 #define DISTRIBUTION_MAX_INDEX (ilog2(DISTRIBUTION_MAX_SIZE) + 1) static inline void fwtty_profile_data(unsigned int stat[], unsigned int val) { int n = (val) ? min(ilog2(val) + 1, DISTRIBUTION_MAX_INDEX) : 0; ++stat[n]; } #else #define DISTRIBUTION_MAX_INDEX 0 #define fwtty_profile_data(st, n) #endif /* Parameters for both VIRT_CABLE_PLUG & VIRT_CABLE_PLUG_RSP mgmt codes */ struct virt_plug_params { __be32 status_hi; __be32 status_lo; __be32 fifo_hi; __be32 fifo_lo; __be32 fifo_len; }; struct peer_work_params { union { struct virt_plug_params plug_req; }; }; /** * fwtty_peer: structure representing local & remote unit devices * @unit: unit child device of fw_device node * @serial: back pointer to associated fw_serial aggregate * @guid: unique 64-bit guid for this unit device * @generation: most recent bus generation * @node_id: most recent node_id * @speed: link speed of peer (0 = S100, 2 = S400, ... 5 = S3200) * @mgmt_addr: bus addr region to write mgmt packets to * @status_addr: bus addr register to write line status to * @fifo_addr: bus addr region to write serial output to * @fifo_len: max length for single write to fifo_addr * @list: link for insertion into fw_serial's peer_list * @rcu: for deferring peer reclamation * @lock: spinlock to synchonize changes to state & port fields * @work: only one work item can be queued at any one time * Note: pending work is canceled prior to removal, so this * peer is valid for at least the lifetime of the work function * @work_params: parameter block for work functions * @timer: timer for resetting peer state if remote request times out * @state: current state * @connect: work item for auto-connecting * @connect_retries: # of connections already attempted * @port: associated tty_port (usable if state == FWSC_ATTACHED) */ struct fwtty_peer { struct fw_unit *unit; struct fw_serial *serial; u64 guid; int generation; int node_id; unsigned int speed; int max_payload; u64 mgmt_addr; /* these are usable only if state == FWSC_ATTACHED */ u64 status_addr; u64 fifo_addr; int fifo_len; struct list_head list; struct rcu_head rcu; spinlock_t lock; work_func_t workfn; struct work_struct work; struct peer_work_params work_params; struct timer_list timer; int state; struct delayed_work connect; int connect_retries; struct fwtty_port *port; }; #define to_peer(ptr, field) (container_of(ptr, struct fwtty_peer, field)) /* state values for fwtty_peer.state field */ enum fwtty_peer_state { FWPS_GONE, FWPS_NOT_ATTACHED, FWPS_ATTACHED, FWPS_PLUG_PENDING, FWPS_PLUG_RESPONDING, FWPS_UNPLUG_PENDING, FWPS_UNPLUG_RESPONDING, FWPS_NO_MGMT_ADDR = -1, }; #define CONNECT_RETRY_DELAY HZ #define MAX_CONNECT_RETRIES 10 /* must be holding peer lock for these state funclets */ static inline void peer_set_state(struct fwtty_peer *peer, int new) { peer->state = new; } static inline struct fwtty_port *peer_revert_state(struct fwtty_peer *peer) { struct fwtty_port *port = peer->port; peer->port = NULL; peer_set_state(peer, FWPS_NOT_ATTACHED); return port; } struct fwserial_mgmt_pkt { struct { __be16 len; __be16 code; } hdr; union { struct virt_plug_params plug_req; struct virt_plug_params plug_rsp; }; } __packed; /* fwserial_mgmt_packet codes */ #define FWSC_RSP_OK 0x0000 #define FWSC_RSP_NACK 0x8000 #define FWSC_CODE_MASK 0x0fff #define FWSC_VIRT_CABLE_PLUG 1 #define FWSC_VIRT_CABLE_UNPLUG 2 #define FWSC_VIRT_CABLE_PLUG_RSP 3 #define FWSC_VIRT_CABLE_UNPLUG_RSP 4 /* 1 min. plug timeout -- suitable for userland authorization */ #define VIRT_CABLE_PLUG_TIMEOUT (60 * HZ) struct stats { unsigned int xchars; unsigned int dropped; unsigned int tx_stall; unsigned int fifo_errs; unsigned int sent; unsigned int lost; unsigned int throttled; unsigned int reads[DISTRIBUTION_MAX_INDEX + 1]; unsigned int writes[DISTRIBUTION_MAX_INDEX + 1]; unsigned int txns[DISTRIBUTION_MAX_INDEX + 1]; unsigned int unthrottle[DISTRIBUTION_MAX_INDEX + 1]; }; struct fwconsole_ops { void (*notify)(int code, void *data); void (*stats)(struct stats *stats, void *data); void (*proc_show)(struct seq_file *m, void *data); }; /* codes for console ops notify */ #define FWCON_NOTIFY_ATTACH 1 #define FWCON_NOTIFY_DETACH 2 /** * fwtty_port: structure used to track/represent underlying tty_port * @port: underlying tty_port * @device: tty device * @index: index into port_table for this particular port * note: minor = index + minor_start assigned by tty_alloc_driver() * @serial: back pointer to the containing fw_serial * @rx_handler: bus address handler for unique addr region used by remotes * to communicate with this port. Every port uses * fwtty_port_handler() for per port transactions. * @fwcon_ops: ops for attached fw_console (if any) * @con_data: private data for fw_console * @wait_tx: waitqueue for sleeping until writer/drain completes tx * @emit_breaks: delayed work responsible for generating breaks when the * break line status is active * @cps : characters per second computed from the termios settings * @break_last: timestamp in jiffies from last emit_breaks * @hangup: work responsible for HUPing when carrier is dropped/lost * @mstatus: loose virtualization of LSR/MSR * bits 15..0 correspond to TIOCM_* bits * bits 19..16 reserved for mctrl * bit 20 OOB_TX_THROTTLE * bits 23..21 reserved * bits 31..24 correspond to UART_LSR_* bits * @lock: spinlock for protecting concurrent access to fields below it * @mctrl: loose virtualization of MCR * bits 15..0 correspond to TIOCM_* bits * bit 16 OOB_RX_THROTTLE * bits 19..17 reserved * bits 31..20 reserved for mstatus * @drain: delayed work scheduled to ensure that writes are flushed. * The work can race with the writer but concurrent sending is * prevented with the IN_TX flag. Scheduled under lock to * limit scheduling when fifo has just been drained. * @tx_fifo: fifo used to store & block-up writes for dma to remote * @max_payload: max bytes transmissible per dma (based on peer's max_payload) * @status_mask: UART_LSR_* bitmask significant to rx (based on termios) * @ignore_mask: UART_LSR_* bitmask of states to ignore (also based on termios) * @break_ctl: if set, port is 'sending break' to remote * @write_only: self-explanatory * @overrun: previous rx was lost (partially or completely) * @loopback: if set, port is in loopback mode * @flags: atomic bit flags * bit 0: IN_TX - gate to allow only one cpu to send from the dma fifo * at a time. * bit 1: STOP_TX - force tx to exit while sending * @peer: rcu-pointer to associated fwtty_peer (if attached) * NULL if no peer attached * @icount: predefined statistics reported by the TIOCGICOUNT ioctl * @stats: additional statistics reported in /proc/tty/driver/firewire_serial */ struct fwtty_port { struct tty_port port; struct device *device; unsigned int index; struct fw_serial *serial; struct fw_address_handler rx_handler; struct fwconsole_ops *fwcon_ops; void *con_data; wait_queue_head_t wait_tx; struct delayed_work emit_breaks; unsigned int cps; unsigned long break_last; struct work_struct hangup; unsigned int mstatus; spinlock_t lock; unsigned int mctrl; struct delayed_work drain; struct dma_fifo tx_fifo; int max_payload; unsigned int status_mask; unsigned int ignore_mask; unsigned int break_ctl:1, write_only:1, overrun:1, loopback:1; unsigned long flags; struct fwtty_peer __rcu *peer; struct async_icount icount; struct stats stats; }; #define to_port(ptr, field) (container_of(ptr, struct fwtty_port, field)) /* bit #s for flags field */ #define IN_TX 0 #define STOP_TX 1 /* bitmasks for special mctrl/mstatus bits */ #define OOB_RX_THROTTLE 0x00010000 #define MCTRL_RSRVD 0x000e0000 #define OOB_TX_THROTTLE 0x00100000 #define MSTATUS_RSRVD 0x00e00000 #define MCTRL_MASK (TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 | TIOCM_OUT2 | \ TIOCM_LOOP | OOB_RX_THROTTLE | MCTRL_RSRVD) /* XXX even every 1/50th secs. may be unnecessarily accurate */ /* delay in jiffies between brk emits */ #define FREQ_BREAKS (HZ / 50) /* Ports are allocated in blocks of num_ports for each fw_card */ #define MAX_CARD_PORTS CONFIG_FWTTY_MAX_CARD_PORTS #define MAX_TOTAL_PORTS CONFIG_FWTTY_MAX_TOTAL_PORTS /* tuning parameters */ #define FWTTY_PORT_TXFIFO_LEN 4096 #define FWTTY_PORT_MAX_PEND_DMA 8 /* costs a cache line per pend */ #define DRAIN_THRESHOLD 1024 #define MAX_ASYNC_PAYLOAD 4096 /* ohci-defined limit */ #define WRITER_MINIMUM 128 /* TODO: how to set watermark to AR context size? see fwtty_rx() */ #define HIGH_WATERMARK 32768 /* AR context is 32K */ /* * Size of bus addr region above 4GB used per port as the recv addr * - must be at least as big as the MAX_ASYNC_PAYLOAD */ #define FWTTY_PORT_RXFIFO_LEN MAX_ASYNC_PAYLOAD /** * fw_serial: aggregate used to associate tty ports with specific fw_card * @card: fw_card associated with this fw_serial device (1:1 association) * @kref: reference-counted multi-port management allows delayed destroy * @self: local unit device as 'peer'. Not valid until local unit device * is enumerated. * @list: link for insertion into fwserial_list * @peer_list: list of local & remote unit devices attached to this card * @ports: fixed array of tty_ports provided by this serial device */ struct fw_serial { struct fw_card *card; struct kref kref; struct dentry *debugfs; struct fwtty_peer *self; struct list_head list; struct list_head peer_list; struct fwtty_port *ports[MAX_CARD_PORTS]; }; #define to_serial(ptr, field) (container_of(ptr, struct fw_serial, field)) #define TTY_DEV_NAME "fwtty" /* ttyFW was taken */ static const char tty_dev_name[] = TTY_DEV_NAME; static const char loop_dev_name[] = "fwloop"; extern struct tty_driver *fwtty_driver; /* * Returns the max send async payload size in bytes based on the unit device * link speed. Self-limiting asynchronous bandwidth (via reducing the payload) * is not necessary and does not work, because * 1) asynchronous traffic will absorb all available bandwidth (less that * being used for isochronous traffic) * 2) isochronous arbitration always wins. */ static inline int link_speed_to_max_payload(unsigned int speed) { /* Max async payload is 4096 - see IEEE 1394-2008 tables 6-4, 16-18 */ return min(512 << speed, 4096); } #endif /* _FIREWIRE_FWSERIAL_H */ |