📄 vlsi_ir.h
字号:
* * SIR-mode: BAUD = (115.2kHz / baudrate) - 1 * PLSWID = (pulsetime * freq / (BAUD+1)) - 1 * where pulsetime is the requested IrPHY pulse width * and freq is 8(16)MHz for 40(48)MHz primary input clock * PREAMB: don't care for SIR * * The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12 * fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz). * IrPHY also allows shorter pulses down to the nominal pulse duration * at 115.2kbaud (minus some tolerance) which is 1.41 usec. * Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz) * we get the minimum acceptable PLSWID values according to the VLSI * specification, which provides 1.5 usec pulse width for all speeds (except * for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and * reduces the transceiver power which drains the battery. At 9.6kbaud for * example this amounts to more than 90% battery power saving! * * MIR-mode: BAUD = 0 * PLSWID = 9(10) for 40(48) MHz input clock * to get nominal MIR pulse width * PREAMB = 1 * * FIR-mode: BAUD = 0 * PLSWID: don't care * PREAMB = 15 */#define PHYCTL_BAUD_SHIFT 10#define PHYCTL_BAUD_MASK 0xfc00#define PHYCTL_PLSWID_SHIFT 5#define PHYCTL_PLSWID_MASK 0x03e0#define PHYCTL_PREAMB_SHIFT 0#define PHYCTL_PREAMB_MASK 0x001f#define PHYCTL_TO_BAUD(bwp) (((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT)#define PHYCTL_TO_PLSWID(bwp) (((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT)#define PHYCTL_TO_PREAMB(bwp) (((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT)#define BWP_TO_PHYCTL(b,w,p) ((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \ | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \ | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK))#define BAUD_BITS(br) ((115200/(br))-1)static inline unsignedcalc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect){ unsigned tmp; if (widthselect) /* nominal 3/16 puls width */ return (clockselect) ? 12 : 24; tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1); /* intermediate result of integer division needed here */ return (tmp>0) ? (tmp-1) : 0;}#define PHYCTL_SIR(br,ws,cs) BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0)#define PHYCTL_MIR(cs) BWP_TO_PHYCTL(0,((cs)?9:10),1)#define PHYCTL_FIR BWP_TO_PHYCTL(0,0,15)/* quite ugly, I know. But implementing these calculations here avoids * having magic numbers in the code and allows some playing with pulsewidths * without risk to violate the standards. * FWIW, here is the table for reference: * * baudrate BAUD min-PLSWID nom-PLSWID PREAMB * 2400 47 0(0) 12(24) 0 * 9600 11 0(0) 12(24) 0 * 19200 5 1(2) 12(24) 0 * 38400 2 3(6) 12(24) 0 * 57600 1 5(10) 12(24) 0 * 115200 0 11(22) 12(24) 0 * MIR 0 - 9(10) 1 * FIR 0 - 0 15 * * note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock *//* ------------------------------------------ *//* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) *//* maximum acceptable length for received packets *//* hw imposed limitation - register uses only [11:0] */#define MAX_PACKET_LENGTH 0x0fff/* IrLAP I-field (apparently not defined elsewhere) */#define IRDA_MTU 2048/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */#define IRLAP_SKB_ALLOCSIZE (1+1+IRDA_MTU)/* the buffers we use to exchange frames with the hardware need to be * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS * appended and, in SIR mode, a lot of frame wrapping bytes. The worst * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes * requiring to be escaped to provide transparency. Furthermore, the peer * might ask for quite a number of additional XBOFs: * up to 115+48 XBOFS 163 * regular BOF 1 * A-field 1 * C-field 1 * I-field, IRDA_MTU, all escaped 4096 * FCS (16 bit at SIR, escaped) 4 * EOF 1 * AFAICS nothing in IrLAP guarantees A/C field not to need escaping * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the * worst case we have 4269 bytes total frame size. * However, the VLSI uses 12 bits only for all buffer length values, * which limits the maximum useable buffer size <= 4095. * Note this is not a limitation in the receive case because we use * the SIR filtering mode where the hw unwraps the frame and only the * bare packet+fcs is stored into the buffer - in contrast to the SIR * tx case where we have to pass frame-wrapped packets to the hw. * If this would ever become an issue in real life, the only workaround * I see would be using the legacy UART emulation in SIR mode. */#define XFER_BUF_SIZE MAX_PACKET_LENGTH/* ------------------------------------------ *//* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) *//* receive packet counter gets incremented on every non-filtered * byte which was put in the receive fifo and reset for each * new packet. Used to decide whether we are just in the middle * of receiving *//* better apply the [11:0] mask when reading, as some docs say the * reserved [15:12] would return 1 when reading - which is wrong AFAICS */#define RCVBCNT_MASK 0x0fff/******************************************************************//* descriptors for rx/tx ring * * accessed by hardware - don't change! * * the descriptor is owned by hardware, when the ACTIVE status bit * is set and nothing (besides reading status to test the bit) * shall be done. The bit gets cleared by hw, when the descriptor * gets closed. Premature reaping of descriptors owned be the chip * can be achieved by disabling IRCFG_MSTR * * Attention: Writing addr overwrites status! * * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-) */struct ring_descr_hw { volatile u16 rd_count; /* tx/rx count [11:0] */ u16 reserved; union { u32 addr; /* [23:0] of the buffer's busaddress */ struct { u8 addr_res[3]; volatile u8 status; /* descriptor status */ } __attribute__((packed)) rd_s; } __attribute((packed)) rd_u;} __attribute__ ((packed));#define rd_addr rd_u.addr#define rd_status rd_u.rd_s.status/* ring descriptor status bits */#define RD_ACTIVE 0x80 /* descriptor owned by hw (both TX,RX) *//* TX ring descriptor status */#define RD_TX_DISCRC 0x40 /* do not send CRC (for SIR) */#define RD_TX_BADCRC 0x20 /* force a bad CRC */#define RD_TX_PULSE 0x10 /* send indication pulse after this frame (MIR/FIR) */#define RD_TX_FRCEUND 0x08 /* force underrun */#define RD_TX_CLRENTX 0x04 /* clear ENTX after this frame */#define RD_TX_UNDRN 0x01 /* TX fifo underrun (probably PCI problem) *//* RX ring descriptor status */#define RD_RX_PHYERR 0x40 /* physical encoding error */#define RD_RX_CRCERR 0x20 /* CRC error (MIR/FIR) */#define RD_RX_LENGTH 0x10 /* frame exceeds buffer length */#define RD_RX_OVER 0x08 /* RX fifo overrun (probably PCI problem) */#define RD_RX_SIRBAD 0x04 /* EOF missing: BOF follows BOF (SIR, filtered) */#define RD_RX_ERROR 0x7c /* any error in received frame *//* the memory required to hold the 2 descriptor rings */#define HW_RING_AREA_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw))/******************************************************************//* sw-ring descriptors consists of a bus-mapped transfer buffer with * associated skb and a pointer to the hw entry descriptor */struct ring_descr { struct ring_descr_hw *hw; struct sk_buff *skb; void *buf;};/* wrappers for operations on hw-exposed ring descriptors * access to the hw-part of the descriptors must use these. */static inline int rd_is_active(struct ring_descr *rd){ return ((rd->hw->rd_status & RD_ACTIVE) != 0);}static inline void rd_activate(struct ring_descr *rd){ rd->hw->rd_status |= RD_ACTIVE;}static inline void rd_set_status(struct ring_descr *rd, u8 s){ rd->hw->rd_status = s; /* may pass ownership to the hardware */}static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s){ /* order is important for two reasons: * - overlayed: writing addr overwrites status * - we want to write status last so we have valid address in * case status has RD_ACTIVE set */ if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) { IRDA_ERROR("%s: pci busaddr inconsistency!\n", __FUNCTION__); dump_stack(); return; } a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write * to status - just in case MSTRPAGE_VALUE!=0 */ rd->hw->rd_addr = cpu_to_le32(a); wmb(); rd_set_status(rd, s); /* may pass ownership to the hardware */}static inline void rd_set_count(struct ring_descr *rd, u16 c){ rd->hw->rd_count = cpu_to_le16(c);}static inline u8 rd_get_status(struct ring_descr *rd){ return rd->hw->rd_status;}static inline dma_addr_t rd_get_addr(struct ring_descr *rd){ dma_addr_t a; a = le32_to_cpu(rd->hw->rd_addr); return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);}static inline u16 rd_get_count(struct ring_descr *rd){ return le16_to_cpu(rd->hw->rd_count);}/******************************************************************//* sw descriptor rings for rx, tx: * * operations follow producer-consumer paradigm, with the hw * in the middle doing the processing. * ring size must be power of two. * * producer advances r->tail after inserting for processing * consumer advances r->head after removing processed rd * ring is empty if head==tail / full if (tail+1)==head */struct vlsi_ring { struct pci_dev *pdev; int dir; unsigned len; unsigned size; unsigned mask; atomic_t head, tail; struct ring_descr *rd;};/* ring processing helpers */static inline struct ring_descr *ring_last(struct vlsi_ring *r){ int t; t = atomic_read(&r->tail) & r->mask; return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t];}static inline struct ring_descr *ring_put(struct vlsi_ring *r){ atomic_inc(&r->tail); return ring_last(r);}static inline struct ring_descr *ring_first(struct vlsi_ring *r){ int h; h = atomic_read(&r->head) & r->mask; return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h];}static inline struct ring_descr *ring_get(struct vlsi_ring *r){ atomic_inc(&r->head); return ring_first(r);}/******************************************************************//* our private compound VLSI-PCI-IRDA device information */typedef struct vlsi_irda_dev { struct pci_dev *pdev; struct net_device_stats stats; struct irlap_cb *irlap; struct qos_info qos; unsigned mode; int baud, new_baud; dma_addr_t busaddr; void *virtaddr; struct vlsi_ring *tx_ring, *rx_ring; struct timeval last_rx; spinlock_t lock; struct semaphore sem; u8 resume_ok; struct proc_dir_entry *proc_entry;} vlsi_irda_dev_t;/********************************************************//* the remapped error flags we use for returning from frame * post-processing in vlsi_process_tx/rx() after it was completed * by the hardware. These functions either return the >=0 number * of transfered bytes in case of success or the negative (-) * of the or'ed error flags. */#define VLSI_TX_DROP 0x0001#define VLSI_TX_FIFO 0x0002#define VLSI_RX_DROP 0x0100#define VLSI_RX_OVER 0x0200#define VLSI_RX_LENGTH 0x0400#define VLSI_RX_FRAME 0x0800#define VLSI_RX_CRC 0x1000/********************************************************/#endif /* IRDA_VLSI_FIR_H */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -