Messages in this thread Patch in this message |  | | Date | Thu, 4 Oct 2001 17:09:02 -0700 | Subject | [PATCH] : ir240_vlsi_v0.3.diff | From | Jean Tourrilhes <> |
| |
ir240_vlsi_v0.3.diff : -------------------- <From Martin Diehl, his changelog :> v0.3: * improve chip initialization which was insufficient in some rare cases without cold reboot * resync with v2.4.10 (irlap-hwname e.g.) * add MODULE_LICENSE * drop MOD_{INC|DEC}_USE_COUNT in favour of SET_MODULE_OWNER * rename mtt_bits to qos_mtt_bits parameter like other irda drivers use v0.2: * add Documentation/Configure.help entry * datasize=2048 issues fixed * major ring operation improvement and cleanup * improved mtt handling * few minor fixes <Note : I think this patch also enable MIR/FIR operation, i.e. higher speeds>
diff -u -p linux/Documentation/Configure.d0b.help linux/Documentation/Configure.help --- linux/Documentation/Configure.d0b.help Thu Oct 4 16:26:43 2001 +++ linux/Documentation/Configure.help Thu Oct 4 16:27:54 2001 @@ -18495,6 +18495,16 @@ CONFIG_SMC_IRCC_FIR here and read Documentation/modules.txt. The module will be called smc-ircc.o. +VLSI 82C147 PCI-IrDA Controller Driver +CONFIG_VLSI_FIR + Say Y here if you want to build support for the VLSI 82C147 + PCI-IrDA Controller. This controller is used by the HP OmniBook 800 + and 5500 notebooks. The driver provides support for SIR, MIR and + FIR (4Mbps) speeds. + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called vlsi_ir.o. + Serial dongle support CONFIG_DONGLE Say Y here if you have an infrared device that connects to your diff -u -p linux/include/net/irda/vlsi_ir.d0b.h linux/include/net/irda/vlsi_ir.h --- linux/include/net/irda/vlsi_ir.d0b.h Thu Oct 4 16:27:23 2001 +++ linux/include/net/irda/vlsi_ir.h Thu Oct 4 16:27:54 2001 @@ -3,7 +3,7 @@ * * vlsi_ir.h: VLSI82C147 PCI IrDA controller driver for Linux * - * Version: 0.1, Aug 6, 2001 + * Version: 0.3, Sep 30, 2001 * * Copyright (c) 2001 Martin Diehl * @@ -49,7 +49,7 @@ enum vlsi_pci_regs { * * On my HP OB-800 the BIOS sets external 40MHz clock as source * when IrDA enabled and I've never detected any PLL lock success. - * Apparently the 14.31818MHz OSC input required for the PLL to work + * Apparently the 14.3...MHz OSC input required for the PLL to work * is not connected and the 40MHz EXTCLK is provided externally. * At least this is what makes the driver working for me. */ @@ -59,7 +59,7 @@ enum vlsi_pci_clkctl { /* PLL control */ CLKCTL_NO_PD = 0x04, /* PD# (inverted power down) signal, - * i.e. PLL is powered, if PD_INV is set */ + * i.e. PLL is powered, if NO_PD set */ CLKCTL_LOCK = 0x40, /* (ro) set, if PLL is locked */ /* clock source selection */ @@ -71,7 +71,7 @@ enum vlsi_pci_clkctl { CLKCTL_CLKSTP = 0x80, /* set to disconnect from selected clock source */ CLKCTL_WAKE = 0x08 /* set to enable wakeup feature: whenever IR activity - * is detected, PD_INV gets set and CLKSTP cleared */ + * is detected, NO_PD gets set and CLKSTP cleared */ }; /* ------------------------------------------ */ @@ -105,8 +105,8 @@ enum vlsi_pci_clkctl { * restriction to the first 16MB of physical address range. * Hence the approach here is to enable PCI busmaster support using * the correct 32bit dma-mask used by the chip. Afterwards the device's - * dma-mask gets restricted to 24bit, which must be honoured by all - * allocations for memory areas to be exposed to the chip. + * dma-mask gets restricted to 24bit, which must be honoured somehow by + * all allocations for memory areas to be exposed to the chip ... * * Note: * Don't be surprised to get "Setting latency timer..." messages every @@ -119,7 +119,7 @@ enum vlsi_pci_clkctl { /* VLSI_PCIIRMISC: IR Miscellaneous Register (u8, rw) */ -/* leagcy UART emulation - not used by this driver - would require: +/* legacy UART emulation - not used by this driver - would require: * (see below for some register-value definitions) * * - IRMISC_UARTEN must be set to enable UART address decoding @@ -135,7 +135,7 @@ enum vlsi_pci_irmisc { IRMISC_IRRAIL = 0x40, /* (ro?) IR rail power indication (and control?) * 0=3.3V / 1=5V. Probably set during power-on? - * Not touched by driver */ + * unclear - not touched by driver */ IRMISC_IRPD = 0x08, /* transceiver power down, if set */ /* legacy UART control */ @@ -168,7 +168,7 @@ enum vlsi_pio_regs { VLSI_PIO_RINGBASE = 0x04, /* [23:10] of ring address (u16, rw) */ VLSI_PIO_RINGSIZE = 0x06, /* rx/tx ring size (u16, rw) */ VLSI_PIO_PROMPT = 0x08, /* triggers ring processing (u16, wo) */ - /* 0x0a-0x0f: reserved, duplicated UART regs */ + /* 0x0a-0x0f: reserved / duplicated UART regs */ VLSI_PIO_IRCFG = 0x10, /* configuration select (u16, rw) */ VLSI_PIO_SIRFLAG = 0x12, /* BOF/EOF for filtered SIR (u16, ro) */ VLSI_PIO_IRENABLE = 0x14, /* enable and status register (u16, rw/ro) */ @@ -176,7 +176,7 @@ enum vlsi_pio_regs { VLSI_PIO_NPHYCTL = 0x18, /* next physical layer select (u16, rw) */ VLSI_PIO_MAXPKT = 0x1a, /* [11:0] max len for packet receive (u16, rw) */ VLSI_PIO_RCVBCNT = 0x1c /* current receive-FIFO byte count (u16, ro) */ - /* 0x1e-0x1f: reserved, duplicated UART regs */ + /* 0x1e-0x1f: reserved / duplicated UART regs */ }; /* ------------------------------------------ */ @@ -188,7 +188,7 @@ enum vlsi_pio_regs { * interrupt condition bits: * set according to corresponding interrupt source * (regardless of the state of the enable bits) - * enable bit status indicated whether interrupt gets raised + * enable bit status indicates whether interrupt gets raised * write-to-clear * note: RPKTINT and TPKTINT behave different in legacy UART mode (which we don't use :-) */ @@ -212,16 +212,16 @@ enum vlsi_pio_irintr { /* VLSI_PIO_RINGPTR: Ring Pointer Read-Back Register (u16, ro) */ -#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */ - /* _both_ ring pointers are indices relative to the _entire_ rx,tx-ring! * i.e. the referenced descriptor is located * at RINGBASE + PTR * sizeof(descr) for rx and tx - * therefore, the tx-pointer has offset by MAX_RING_DESCR + * therefore, the tx-pointer has offset MAX_RING_DESCR */ +#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */ + #define RINGPTR_RX_MASK (MAX_RING_DESCR-1) -#define RINGPTR_TX_MASK ((MAX_RING_DESCR|(MAX_RING_DESCR-1))<<8) +#define RINGPTR_TX_MASK ((MAX_RING_DESCR-1)<<8) #define RINGPTR_GET_RX(p) ((p)&RINGPTR_RX_MASK) #define RINGPTR_GET_TX(p) (((p)&RINGPTR_TX_MASK)>>8) @@ -233,14 +233,14 @@ enum vlsi_pio_irintr { /* Contains [23:10] part of the ring base (bus-) address * which must be 1k-alinged. [31:24] is taken from * VLSI_PCI_MSTRPAGE above. - * The controler initiates non-burst PCI BM cycles to + * The controller initiates non-burst PCI BM cycles to * fetch and update the descriptors in the ring. * Once fetched, the descriptor remains cached onchip * until it gets closed and updated due to the ring * processing state machine. * The entire ring area is split in rx and tx areas with each * area consisting of 64 descriptors of 8 bytes each. - * The rx(tx) ring is located at ringbase+0 (ringbase+8*64). + * The rx(tx) ring is located at ringbase+0 (ringbase+64*8). */ #define BUS_TO_RINGBASE(p) (((p)>>10)&0x3fff) @@ -273,9 +273,7 @@ enum vlsi_pio_irintr { /* VLSI_PIO_PROMPT: Ring Prompting Register (u16, write-to-start) */ /* writing any value kicks the ring processing state machines - * for both tx, rx rings. - * currently enabled rings (according to IRENABLE_ENTXST, IRENABLE_ENRXST - * status reporting - see below) are considered as follows: + * for both tx, rx rings as follows: * - active rings (currently owning an active descriptor) * ignore the prompt and continue * - idle rings fetch the next descr from the ring and start @@ -289,7 +287,7 @@ enum vlsi_pio_irintr { /* notes: * - not more than one SIR/MIR/FIR bit must be set at any time * - SIR, MIR, FIR and CRC16 select the configuration which will - * be applied now/next time if/when IRENABLE_IREN is _cleared_ (see below) + * be applied on next 0->1 transition of IRENABLE_IREN (see below). * - besides allowing the PCI interface to execute busmaster cycles * and therefore the ring SM to operate, the MSTR bit has side-effects: * when MSTR is cleared, the RINGPTR's get reset and the legacy UART mode @@ -340,7 +338,7 @@ enum vlsi_pio_ircfg { */ enum vlsi_pio_irenable { - IRENABLE_IREN = 0x8000, /* enable IR phy and gate mode config (rw) */ + IRENABLE_IREN = 0x8000, /* enable IR phy and gate the mode config (rw) */ IRENABLE_CFGER = 0x4000, /* mode configuration error (ro) */ IRENABLE_FIR_ON = 0x2000, /* FIR on status (ro) */ IRENABLE_MIR_ON = 0x1000, /* MIR on status (ro) */ @@ -389,7 +387,7 @@ enum vlsi_pio_irenable { * specification, which provides 1.5 usec pulse width for all speeds (except * for 2.4kbaud getting 6usec). This is well inside IrPHY v1.3 specs and * reduces the transceiver power which drains the battery. At 9.6kbaud for - * example this makes more than 90% battery power saving! + * example this amounts to more than 90% battery power saving! * * MIR-mode: BAUD = 0 * PLSWID = 9(10) for 40(48) MHz input clock @@ -402,7 +400,7 @@ enum vlsi_pio_irenable { */ #define BWP_TO_PHYCTL(B,W,P) ((((B)&0x3f)<<10) | (((W)&0x1f)<<5) | (((P)&0x1f)<<0)) -#define BAUD_BITS(br) ((115200/br)-1) +#define BAUD_BITS(br) ((115200/(br))-1) static inline unsigned calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect) @@ -447,15 +445,25 @@ calc_width_bits(unsigned baudrate, unsig /* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */ -/* specifies the maximum legth (up to 4096 bytes), which a +/* specifies the maximum legth (up to 4k - or (4k-1)? - bytes), which a * received frame may have - i.e. the size of the corresponding * receive buffers. For simplicity we use the same length for - * receive and submit buffers. Therefore we use 3k to have - * enough space for a lot of XBOF's and escapes we may need at - * some point when wrapping MTU=2048 sized packets for transmission. - */ + * receive and submit buffers and increase transfer buffer size + * byond IrDA-MTU = 2048 so we have sufficient space left when + * packet size increases during wrapping due to XBOFs and CE's. + * Even for receiving unwrapped frames we need >MAX_PACKET_LEN + * space since the controller appends FCS/CRC (2 or 4 bytes) + * so we use 2*IrDA-MTU for both directions and cover even the + * worst case, where all data bytes have to be escaped when wrapping. + * well, this wastes some memory - anyway, later we will + * either map skb's directly or use pci_pool allocator... + */ + +#define IRDA_MTU 2048 /* seems to be undefined elsewhere */ + +#define XFER_BUF_SIZE (2*IRDA_MTU) -#define MAX_PACKET_LENGTH 3172 +#define MAX_PACKET_LENGTH (XFER_BUF_SIZE-1) /* register uses only [11:0] */ /* ------------------------------------------ */ @@ -466,7 +474,7 @@ calc_width_bits(unsigned baudrate, unsig /* recive 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 receiving + * of receiving */ #define RCVBCNT_MASK 0x0fff @@ -538,12 +546,21 @@ struct ring_descr { struct ring_entry { struct sk_buff *skb; - void *head; + void *data; +}; + + +struct vlsi_ring { + unsigned size; + unsigned mask; + unsigned head, tail; + struct ring_descr *hw; + struct ring_entry buf[MAX_RING_DESCR]; }; /* ------------------------------------------ */ -/* our compound VLSI-PCI-IRDA device information */ +/* our private compound VLSI-PCI-IRDA device information */ typedef struct vlsi_irda_dev { struct pci_dev *pdev; @@ -557,14 +574,10 @@ typedef struct vlsi_irda_dev { int baud, new_baud; dma_addr_t busaddr; + void *virtaddr; + struct vlsi_ring tx_ring, rx_ring; - struct ring_descr *ring_hw; - - struct ring_entry *ring_buf; - - unsigned tx_mask, rx_mask; - - unsigned tx_put, tx_get, rx_put, rx_get; + struct timeval last_rx; spinlock_t lock; diff -u -p linux/drivers/net/irda/vlsi_ir.d0b.c linux/drivers/net/irda/vlsi_ir.c --- linux/drivers/net/irda/vlsi_ir.d0b.c Thu Oct 4 16:25:23 2001 +++ linux/drivers/net/irda/vlsi_ir.c Thu Oct 4 16:27:54 2001 @@ -2,7 +2,7 @@ * * vlsi_ir.c: VLSI82C147 PCI IrDA controller driver for Linux * - * Version: 0.1, Aug 6, 2001 + * Version: 0.3, Sep 30, 2001 * * Copyright (c) 2001 Martin Diehl * @@ -32,6 +32,7 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <linux/delay.h> +#include <linux/time.h> #include <net/irda/irda.h> #include <net/irda/irda_device.h> @@ -49,15 +50,14 @@ MODULE_AUTHOR("Martin Diehl <info@mdiehl MODULE_LICENSE("GPL"); - static /* const */ char drivername[] = "vlsi_ir"; -#define PCI_CLASS_IRDA_GENERIC 0x0d00 +#define PCI_CLASS_WIRELESS_IRDA 0x0d00 static struct pci_device_id vlsi_irda_table [] __devinitdata = { { - class: PCI_CLASS_IRDA_GENERIC << 8, + class: PCI_CLASS_WIRELESS_IRDA << 8, vendor: PCI_VENDOR_ID_VLSI, device: PCI_DEVICE_ID_VLSI_82C147, }, { /* all zeroes */ } @@ -83,37 +83,45 @@ static int clksrc = 0; /* default is 0 MODULE_PARM(ringsize, "1-2i"); -MODULE_PARM_DESC(ringsize, "tx, rx ring descriptor size"); +MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size"); /* ringsize: size of the tx and rx descriptor rings * independent for tx and rx * specify as ringsize=tx[,rx] * allowed values: 4, 8, 16, 32, 64 + * Due to the IrDA 1.x max. allowed window size=7, + * there should be no gain when using rings larger than 8 */ -static int ringsize[] = {16,16}; /* default is tx=rx=16 */ +static int ringsize[] = {8,8}; /* default is tx=rx=8 */ MODULE_PARM(sirpulse, "i"); -MODULE_PARM_DESC(sirpulse, "sir pulse width tuning"); +MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning"); -/* sirpulse: tuning of the sir pulse width within IrPHY 1.3 limits - * 0: real short, 1.5us (exception 6us at 2.4kb/s) +/* sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits + * 0: very short, 1.5us (exception: 6us at 2.4 kbaud) * 1: nominal 3/16 bittime width + * note: IrDA compliant peer devices should be happy regardless + * which one is used. Primary goal is to save some power + * on the sender's side - at 9.6kbaud for example the short + * pulse width saves more than 90% of the transmitted IR power. */ static int sirpulse = 1; /* default is 3/16 bittime */ -MODULE_PARM(mtt_bits, "i"); -MODULE_PARM_DESC(mtt_bits, "IrLAP bitfield representing min-turn-time"); +MODULE_PARM(qos_mtt_bits, "i"); +MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time"); -/* mtt_bit: encoded min-turn-time values we accept for connections - * according to IrLAP definition (section 6.6.8) - * the widespreadly used HP HDLS-1100 requires 1 msec +/* qos_mtt_bits: encoded min-turn-time value we require the peer device + * to use before transmitting to us. "Type 1" (per-station) + * bitfield according to IrLAP definition (section 6.6.8) + * The HP HDLS-1100 requires 1 msec - don't even know + * if this is the one which is used by my OB800 */ -static int mtt_bits = 0x07; /* default is 1 ms or more */ +static int qos_mtt_bits = 0x04; /* default is 1 ms */ /********************************************************/ @@ -122,68 +130,81 @@ static int mtt_bits = 0x07; /* default /* some helpers for operations on ring descriptors */ -static inline int rd_is_active(struct ring_descr *rd) +static inline int rd_is_active(struct vlsi_ring *r, unsigned i) +{ + return ((r->hw[i].rd_status & RD_STAT_ACTIVE) != 0); +} + +static inline void rd_activate(struct vlsi_ring *r, unsigned i) { - return ((rd->rd_status & RD_STAT_ACTIVE) != 0); + r->hw[i].rd_status |= RD_STAT_ACTIVE; } -static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s) +static inline void rd_set_addr_status(struct vlsi_ring *r, unsigned i, dma_addr_t a, u8 s) { - /* overlayed - order is important! */ + struct ring_descr *rd = r->hw +i; + + /* ordering 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_STAT_ACTIVE set + */ + if ((a & ~DMA_MASK_MSTRPAGE) != MSTRPAGE_VALUE) + BUG(); + + a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write + * to status - just in case MSTRPAGE_VALUE!=0 + */ rd->rd_addr = a; - rd->rd_status = s; + wmb(); + rd->rd_status = s; /* potentially passes ownership to the hardware */ } -static inline void rd_set_status(struct ring_descr *rd, u8 s) +static inline void rd_set_status(struct vlsi_ring *r, unsigned i, u8 s) { - rd->rd_status = s; + r->hw[i].rd_status = s; } -static inline void rd_set_count(struct ring_descr *rd, u16 c) +static inline void rd_set_count(struct vlsi_ring *r, unsigned i, u16 c) { - rd->rd_count = c; + r->hw[i].rd_count = c; } -static inline u8 rd_get_status(struct ring_descr *rd) +static inline u8 rd_get_status(struct vlsi_ring *r, unsigned i) { - return rd->rd_status; + return r->hw[i].rd_status; } -static inline dma_addr_t rd_get_addr(struct ring_descr *rd) +static inline dma_addr_t rd_get_addr(struct vlsi_ring *r, unsigned i) { dma_addr_t a; - a = (rd->rd_addr & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24); + a = (r->hw[i].rd_addr & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24); return a; } -static inline u16 rd_get_count(struct ring_descr *rd) +static inline u16 rd_get_count(struct vlsi_ring *r, unsigned i) { - return rd->rd_count; + return r->hw[i].rd_count; } +/* producer advances r->head when descriptor was added for processing by hw */ -/* advancing indices pointing into descriptor rings */ - -static inline void ring_ptr_inc(unsigned *ptr, unsigned mask) +static inline void ring_put(struct vlsi_ring *r) { - *ptr = (*ptr + 1) & mask; + r->head = (r->head + 1) & r->mask; } +/* consumer advances r->tail when descriptor was removed after getting processed by hw */ -/********************************************************/ - - -#define MAX_PACKET_LEN 2048 /* IrDA MTU */ +static inline void ring_get(struct vlsi_ring *r) +{ + r->tail = (r->tail + 1) & r->mask; +} -/* increase transfer buffer size somewhat so we have enough space left - * when packet size increases during wrapping due to XBOFs and escapes. - * well, this wastes some memory - anyway, later we will - * either map skb's directly or use pci_pool allocator... - */ -#define XFER_BUF_SIZE (MAX_PACKET_LEN+512) +/********************************************************/ /* the memory required to hold the 2 descriptor rings */ @@ -193,12 +214,11 @@ static inline void ring_ptr_inc(unsigned #define RING_ENTRY_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_entry)) - /********************************************************/ /* just dump all registers */ -static void vlsi_reg_debug(int iobase, const char *s) +static void vlsi_reg_debug(unsigned iobase, const char *s) { int i; @@ -217,15 +237,14 @@ static int vlsi_set_clock(struct pci_dev u8 clkctl, lock; int i, count; - if (clksrc < 0 || clksrc > 3) { - printk(KERN_ERR "%s: invalid clksrc=%d\n", __FUNCTION__, clksrc); - return -1; - } if (clksrc < 2) { /* auto or PLL: try PLL */ clkctl = CLKCTL_NO_PD | CLKCTL_CLKSTP; pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - /* protocol to detect PLL lock synchronisation */ + /* procedure to detect PLL lock synchronisation: + * after 0.5 msec initial delay we expect to find 3 PLL lock + * indications within 10 msec for successful PLL detection. + */ udelay(500); count = 0; for (i = 500; i <= 10000; i += 50) { /* max 10 msec */ @@ -244,20 +263,20 @@ static int vlsi_set_clock(struct pci_dev pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); return -1; } - else /* was: clksrc=0(auto) */ - clksrc = 3; /* fallback to 40MHz XCLK (OB800) */ + else /* was: clksrc=0(auto) */ + clksrc = 3; /* fallback to 40MHz XCLK (OB800) */ printk(KERN_INFO "%s: PLL not locked, fallback to clksrc=%d\n", __FUNCTION__, clksrc); } - else { /* got succesful PLL lock */ + else { /* got successful PLL lock */ clksrc = 1; return 0; } } /* we get here if either no PLL detected in auto-mode or - the external clock source explicitly specified */ + the external clock source was explicitly specified */ clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP; if (clksrc == 3) @@ -310,80 +329,93 @@ static void vlsi_unset_clock(struct pci_ /* ### FIXME: don't use old virt_to_bus() anymore! */ -static int vlsi_alloc_buffers_init(vlsi_irda_dev_t *idev) + +static void vlsi_arm_rx(struct vlsi_ring *r) { - void *buf; - int i, j; + unsigned i; + dma_addr_t ba; - idev->ring_buf = kmalloc(RING_ENTRY_SIZE,GFP_KERNEL); - if (!idev->ring_buf) - return -ENOMEM; - memset(idev->ring_buf, 0, RING_ENTRY_SIZE); + for (i = 0; i < r->size; i++) { + if (r->buf[i].data == NULL) + BUG(); + ba = virt_to_bus(r->buf[i].data); + rd_set_addr_status(r, i, ba, RD_STAT_ACTIVE); + } +} + +static int vlsi_alloc_ringbuf(struct vlsi_ring *r) +{ + unsigned i, j; - for (i = MAX_RING_DESCR; i < MAX_RING_DESCR+ringsize[0]; i++) { - buf = kmalloc(XFER_BUF_SIZE, GFP_KERNEL|GFP_DMA); - if (!buf) { - for (j = MAX_RING_DESCR; j < i; j++) - kfree(idev->ring_buf[j].head); - kfree(idev->ring_buf); - idev->ring_buf = NULL; + r->head = r->tail = 0; + r->mask = r->size - 1; + for (i = 0; i < r->size; i++) { + r->buf[i].skb = NULL; + r->buf[i].data = kmalloc(XFER_BUF_SIZE, GFP_KERNEL|GFP_DMA); + if (r->buf[i].data == NULL) { + for (j = 0; j < i; j++) { + kfree(r->buf[j].data); + r->buf[j].data = NULL; + } return -ENOMEM; } - idev->ring_buf[i].head = buf; - idev->ring_buf[i].skb = NULL; - rd_set_addr_status(idev->ring_hw+i,virt_to_bus(buf), 0); } + return 0; +} - for (i = 0; i < ringsize[1]; i++) { - buf = kmalloc(XFER_BUF_SIZE, GFP_KERNEL|GFP_DMA); - if (!buf) { - for (j = 0; j < i; j++) - kfree(idev->ring_buf[j].head); - for (j = MAX_RING_DESCR; j < MAX_RING_DESCR+ringsize[0]; j++) - kfree(idev->ring_buf[j].head); - kfree(idev->ring_buf); - idev->ring_buf = NULL; - return -ENOMEM; +static void vlsi_free_ringbuf(struct vlsi_ring *r) +{ + unsigned i; + + for (i = 0; i < r->size; i++) { + if (r->buf[i].data == NULL) + continue; + if (r->buf[i].skb) { + dev_kfree_skb(r->buf[i].skb); + r->buf[i].skb = NULL; } - idev->ring_buf[i].head = buf; - idev->ring_buf[i].skb = NULL; - rd_set_addr_status(idev->ring_hw+i,virt_to_bus(buf), RD_STAT_ACTIVE); + else + kfree(r->buf[i].data); + r->buf[i].data = NULL; } - - return 0; } static int vlsi_init_ring(vlsi_irda_dev_t *idev) { + char *ringarea; - idev->tx_mask = MAX_RING_DESCR | (ringsize[0] - 1); - idev->rx_mask = ringsize[1] - 1; - - idev->ring_hw = pci_alloc_consistent(idev->pdev, - RING_AREA_SIZE, &idev->busaddr); - if (!idev->ring_hw) { + ringarea = pci_alloc_consistent(idev->pdev, RING_AREA_SIZE, &idev->busaddr); + if (!ringarea) { printk(KERN_ERR "%s: insufficient memory for descriptor rings\n", __FUNCTION__); return -ENOMEM; } + memset(ringarea, 0, RING_AREA_SIZE); + #if 0 printk(KERN_DEBUG "%s: (%d,%d)-ring %p / %p\n", __FUNCTION__, - ringsize[0], ringsize[1], idev->ring_hw, + ringsize[0], ringsize[1], ringarea, (void *)(unsigned)idev->busaddr); #endif - memset(idev->ring_hw, 0, RING_AREA_SIZE); - if (vlsi_alloc_buffers_init(idev)) { - - pci_free_consistent(idev->pdev, RING_AREA_SIZE, - idev->ring_hw, idev->busaddr); - printk(KERN_ERR "%s: insufficient memory for ring buffers\n", - __FUNCTION__); - return -1; + idev->rx_ring.size = ringsize[1]; + idev->rx_ring.hw = (struct ring_descr *)ringarea; + if (!vlsi_alloc_ringbuf(&idev->rx_ring)) { + idev->tx_ring.size = ringsize[0]; + idev->tx_ring.hw = idev->rx_ring.hw + MAX_RING_DESCR; + if (!vlsi_alloc_ringbuf(&idev->tx_ring)) { + idev->virtaddr = ringarea; + return 0; + } + vlsi_free_ringbuf(&idev->rx_ring); } - return 0; + pci_free_consistent(idev->pdev, RING_AREA_SIZE, + ringarea, idev->busaddr); + printk(KERN_ERR "%s: insufficient memory for ring buffers\n", + __FUNCTION__); + return -1; } @@ -397,7 +429,7 @@ static int vlsi_set_baud(struct net_devi vlsi_irda_dev_t *idev = ndev->priv; unsigned long flags; u16 nphyctl; - int iobase; + unsigned iobase; u16 config; unsigned mode; int ret; @@ -420,7 +452,7 @@ static int vlsi_set_baud(struct net_devi else if (baudrate == 1152000) { mode = IFF_MIR; config = IRCFG_MIR | IRCFG_CRC16; - nphyctl = PHYCTL_MIR(baudrate); + nphyctl = PHYCTL_MIR(clksrc==3); } else { mode = IFF_SIR; @@ -449,7 +481,8 @@ static int vlsi_set_baud(struct net_devi outw(nphyctl, iobase+VLSI_PIO_NPHYCTL); wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); - /* chip fetches IRCFG on next rising edge of its 8MHz clock */ + + /* chip fetches IRCFG on next rising edge of its 8MHz clock */ mb(); config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK; @@ -493,16 +526,15 @@ static int vlsi_set_baud(struct net_devi static int vlsi_init_chip(struct net_device *ndev) { vlsi_irda_dev_t *idev = ndev->priv; + unsigned iobase; u16 ptr; - unsigned iobase; - iobase = ndev->base_addr; - outw(0, iobase+VLSI_PIO_IRENABLE); - outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */ + outw(0, iobase+VLSI_PIO_IRENABLE); /* disable IrPHY-interface */ + /* disable everything, particularly IRCFG_MSTR - which resets the RING_PTR */ outw(0, iobase+VLSI_PIO_IRCFG); @@ -513,16 +545,16 @@ static int vlsi_init_chip(struct net_dev outw(0, iobase+VLSI_PIO_IRENABLE); - outw(MAX_PACKET_LEN, iobase+VLSI_PIO_MAXPKT); + outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT); /* max possible value=0x0fff */ outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE); - outw(TX_RX_TO_RINGSIZE(ringsize[0], ringsize[1]), iobase+VLSI_PIO_RINGSIZE); - + outw(TX_RX_TO_RINGSIZE(idev->tx_ring.size, idev->rx_ring.size), + iobase+VLSI_PIO_RINGSIZE); ptr = inw(iobase+VLSI_PIO_RINGPTR); - idev->rx_put = idev->rx_get = RINGPTR_GET_RX(ptr); - idev->tx_put = idev->tx_get = RINGPTR_GET_TX(ptr); + idev->rx_ring.head = idev->rx_ring.tail = RINGPTR_GET_RX(ptr); + idev->tx_ring.head = idev->tx_ring.tail = RINGPTR_GET_TX(ptr); outw(IRCFG_MSTR, iobase+VLSI_PIO_IRCFG); /* ready for memory access */ wmb(); @@ -533,12 +565,12 @@ static int vlsi_init_chip(struct net_dev idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ vlsi_set_baud(ndev); - outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); + outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* just in case - w/c pending IRQ's */ wmb(); /* DO NOT BLINDLY ENABLE IRINTR_ACTEN! * basically every received pulse fires an ACTIVITY-INT - * leading to >1000 INT's per second instead of few 10 + * leading to >>1000 INT's per second instead of few 10 */ outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR); @@ -551,97 +583,82 @@ static int vlsi_init_chip(struct net_dev /**************************************************************/ +static void vlsi_refill_rx(struct vlsi_ring *r) +{ + do { + if (rd_is_active(r, r->head)) + BUG(); + rd_activate(r, r->head); + ring_put(r); + } while (r->head != r->tail); +} + + static int vlsi_rx_interrupt(struct net_device *ndev) { vlsi_irda_dev_t *idev = ndev->priv; - int iobase; - int entry; + struct vlsi_ring *r; int len; u8 status; - u16 word; struct sk_buff *skb; int crclen; - iobase = ndev->base_addr; - - entry = idev->rx_get; - - while ( !rd_is_active(idev->ring_hw+idev->rx_get) ) { - - ring_ptr_inc(&idev->rx_get, idev->rx_mask); - - while (entry != idev->rx_get) { - - status = rd_get_status(idev->ring_hw+entry); + r = &idev->rx_ring; + while (!rd_is_active(r, r->tail)) { - if (status & RD_STAT_ACTIVE) { - printk(KERN_CRIT "%s: rx still active!!!\n", - __FUNCTION__); - break; - } - if (status & RX_STAT_ERROR) { - idev->stats.rx_errors++; - if (status & RX_STAT_OVER) - idev->stats.rx_over_errors++; - if (status & RX_STAT_LENGTH) - idev->stats.rx_length_errors++; - if (status & RX_STAT_PHYERR) - idev->stats.rx_frame_errors++; - if (status & RX_STAT_CRCERR) - idev->stats.rx_crc_errors++; + status = rd_get_status(r, r->tail); + if (status & RX_STAT_ERROR) { + idev->stats.rx_errors++; + if (status & RX_STAT_OVER) + idev->stats.rx_over_errors++; + if (status & RX_STAT_LENGTH) + idev->stats.rx_length_errors++; + if (status & RX_STAT_PHYERR) + idev->stats.rx_frame_errors++; + if (status & RX_STAT_CRCERR) + idev->stats.rx_crc_errors++; + } + else { + len = rd_get_count(r, r->tail); + crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); + if (len < crclen) + printk(KERN_ERR "%s: strange frame (len=%d)\n", + __FUNCTION__, len); + else + len -= crclen; /* remove trailing CRC */ + + skb = dev_alloc_skb(len+1); + if (skb) { + skb->dev = ndev; + skb_reserve(skb,1); + memcpy(skb_put(skb,len), r->buf[r->tail].data, len); + idev->stats.rx_packets++; + idev->stats.rx_bytes += len; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); } else { - len = rd_get_count(idev->ring_hw+entry); - crclen = (idev->mode==IFF_FIR) ? 4 : 2; - if (len < crclen) - printk(KERN_ERR "%s: strange frame (len=%d)\n", - __FUNCTION__, len); - else - len -= crclen; /* remove trailing CRC */ - - skb = dev_alloc_skb(len+1); - if (skb) { - skb->dev = ndev; - skb_reserve(skb,1); - memcpy(skb_put(skb,len), idev->ring_buf[entry].head, len); - idev->stats.rx_packets++; - idev->stats.rx_bytes += len; - skb->mac.raw = skb->data; - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - else { - idev->stats.rx_dropped++; - printk(KERN_ERR "%s: rx packet dropped\n", __FUNCTION__); - } + idev->stats.rx_dropped++; + printk(KERN_ERR "%s: rx packet dropped\n", __FUNCTION__); } - rd_set_count(idev->ring_hw+entry, 0); - rd_set_status(idev->ring_hw+entry, RD_STAT_ACTIVE); - ring_ptr_inc(&entry, idev->rx_mask); + } + rd_set_count(r, r->tail, 0); + rd_set_status(r, r->tail, 0); + ring_get(r); + if (r->tail == r->head) { + printk(KERN_WARNING "%s: rx ring exhausted\n", __FUNCTION__); + break; } } - idev->rx_put = idev->rx_get; - idev->rx_get = entry; - word = inw(iobase+VLSI_PIO_IRENABLE); - if (!(word & IRENABLE_ENTXST)) { + do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */ - /* only rewrite ENRX, if tx not running! - * rewriting ENRX during tx in progress wouldn't hurt - * but would be racy since we would also have to rewrite - * ENTX then (same register) - which might get disabled meanwhile. - */ + vlsi_refill_rx(r); - outw(0, iobase+VLSI_PIO_IRENABLE); - - word = inw(iobase+VLSI_PIO_IRCFG); - mb(); - outw(word | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); - wmb(); - outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); - } mb(); - outw(0, iobase+VLSI_PIO_PROMPT); + outw(0, ndev->base_addr+VLSI_PIO_PROMPT); + return 0; } @@ -649,64 +666,55 @@ static int vlsi_rx_interrupt(struct net_ static int vlsi_tx_interrupt(struct net_device *ndev) { vlsi_irda_dev_t *idev = ndev->priv; - int iobase; - int entry; + struct vlsi_ring *r; + unsigned iobase; int ret; u16 config; u16 status; - ret = 0; - iobase = ndev->base_addr; - - entry = idev->tx_get; - - while ( !rd_is_active(idev->ring_hw+idev->tx_get) ) { - - if (idev->tx_get == idev->tx_put) { /* tx ring empty */ - /* sth more to do here? */ - break; + r = &idev->tx_ring; + while (!rd_is_active(r, r->tail)) { + if (r->tail == r->head) + break; /* tx ring empty - nothing to send anymore */ + + status = rd_get_status(r, r->tail); + if (status & TX_STAT_UNDRN) { + idev->stats.tx_errors++; + idev->stats.tx_fifo_errors++; } - ring_ptr_inc(&idev->tx_get, idev->tx_mask); - while (entry != idev->tx_get) { - status = rd_get_status(idev->ring_hw+entry); - if (status & RD_STAT_ACTIVE) { - printk(KERN_CRIT "%s: tx still active!!!\n", - __FUNCTION__); - break; - } - if (status & TX_STAT_UNDRN) { - idev->stats.tx_errors++; - idev->stats.tx_fifo_errors++; - } - else { - idev->stats.tx_packets++; - idev->stats.tx_bytes += rd_get_count(idev->ring_hw+entry); - } - rd_set_count(idev->ring_hw+entry, 0); - rd_set_status(idev->ring_hw+entry, 0); - ring_ptr_inc(&entry, idev->tx_mask); + else { + idev->stats.tx_packets++; + idev->stats.tx_bytes += rd_get_count(r, r->tail); /* not correct for SIR */ } + rd_set_count(r, r->tail, 0); + rd_set_status(r, r->tail, 0); + if (r->buf[r->tail].skb) { + rd_set_addr_status(r, r->tail, 0, 0); + dev_kfree_skb(r->buf[r->tail].skb); + r->buf[r->tail].skb = NULL; + r->buf[r->tail].data = NULL; + } + ring_get(r); } - outw(0, iobase+VLSI_PIO_IRENABLE); - config = inw(iobase+VLSI_PIO_IRCFG); - mb(); + ret = 0; + iobase = ndev->base_addr; - if (idev->tx_get != idev->tx_put) { /* tx ring not empty */ - outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); - ret = 1; /* no speed-change-check */ + if (r->head == r->tail) { /* tx ring empty: re-enable rx */ + + outw(0, iobase+VLSI_PIO_IRENABLE); + config = inw(iobase+VLSI_PIO_IRCFG); + mb(); + outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); + wmb(); + outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); } else - outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); - wmb(); - outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); + ret = 1; /* no speed-change-check */ mb(); - outw(0, iobase+VLSI_PIO_PROMPT); - wmb(); - idev->tx_get = entry; if (netif_queue_stopped(ndev)) { netif_wake_queue(ndev); printk(KERN_DEBUG "%s: queue awoken\n", __FUNCTION__); @@ -715,24 +723,27 @@ static int vlsi_tx_interrupt(struct net_ } +#if 0 /* disable ACTIVITY handling for now */ + static int vlsi_act_interrupt(struct net_device *ndev) { printk(KERN_DEBUG "%s\n", __FUNCTION__); return 0; } - +#endif static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *ndev = dev_instance; vlsi_irda_dev_t *idev = ndev->priv; - int iobase; + unsigned iobase; u8 irintr; - int boguscount = 20; + int boguscount = 32; int no_speed_check = 0; + unsigned got_act; unsigned long flags; - + got_act = 0; iobase = ndev->base_addr; spin_lock_irqsave(&idev->lock,flags); do { @@ -752,9 +763,16 @@ static void vlsi_interrupt(int irq, void if (irintr&IRINTR_TPKTINT) no_speed_check |= vlsi_tx_interrupt(ndev); - if ((irintr&IRINTR_ACTIVITY) && !(irintr^IRINTR_ACTIVITY) ) - no_speed_check |= vlsi_act_interrupt(ndev); +#if 0 /* disable ACTIVITY handling for now */ + + if (got_act && irintr==IRINTR_ACTIVITY) /* nothing new */ + break; + if ((irintr&IRINTR_ACTIVITY) && !(irintr^IRINTR_ACTIVITY) ) { + no_speed_check |= vlsi_act_interrupt(ndev); + got_act = 1; + } +#endif if (irintr & ~(IRINTR_RPKTINT|IRINTR_TPKTINT|IRINTR_ACTIVITY)) printk(KERN_DEBUG "%s: IRINTR = %02x\n", __FUNCTION__, (unsigned)irintr); @@ -774,27 +792,51 @@ static void vlsi_interrupt(int irq, void /**************************************************************/ + +/* writing all-zero to the VLSI PCI IO register area seems to prevent + * some occasional situations where the hardware fails (symptoms are + * what appears as stalled tx/rx state machines, i.e. everything ok for + * receive or transmit but hw makes no progress or is unable to access + * the bus memory locations). + * Best place to call this is immediately after/before the internal clock + * gets started/stopped. + */ + +static inline void vlsi_clear_regs(unsigned iobase) +{ + unsigned i; + const unsigned chip_io_extent = 32; + + for (i = 0; i < chip_io_extent; i += sizeof(u16)) + outw(0, iobase + i); +} + + static int vlsi_open(struct net_device *ndev) { vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; - char hwname[32]; int err; - - MOD_INC_USE_COUNT; /* still needed? - we have SET_MODULE_OWNER! */ + char hwname[32]; if (pci_request_regions(pdev,drivername)) { printk(KERN_ERR "%s: io resource busy\n", __FUNCTION__); - MOD_DEC_USE_COUNT; return -EAGAIN; } - if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ|SA_INTERRUPT, + /* under some rare occasions the chip apparently comes up + * with IRQ's pending. So we get interrupts invoked much too early + * which will immediately kill us again :-( + * so we better w/c pending IRQ and disable them all + */ + + outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR); + + if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ, drivername, ndev)) { printk(KERN_ERR "%s: couldn't get IRQ: %d\n", __FUNCTION__, ndev->irq); pci_release_regions(pdev); - MOD_DEC_USE_COUNT; return -EAGAIN; } printk(KERN_INFO "%s: got resources for %s - irq=%d / io=%04lx\n", @@ -805,18 +847,18 @@ static int vlsi_open(struct net_device * __FUNCTION__); free_irq(ndev->irq,ndev); pci_release_regions(pdev); - MOD_DEC_USE_COUNT; return -EIO; } vlsi_start_clock(pdev); + vlsi_clear_regs(ndev->base_addr); + err = vlsi_init_ring(idev); if (err) { vlsi_unset_clock(pdev); free_irq(ndev->irq,ndev); pci_release_regions(pdev); - MOD_DEC_USE_COUNT; return err; } @@ -827,7 +869,11 @@ static int vlsi_open(struct net_device * (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"), (sirpulse)?"3/16 bittime":"short"); - sprintf(hwname, "VLSI-FIR"); + vlsi_arm_rx(&idev->rx_ring); + + do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */ + + sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr); idev->irlap = irlap_open(ndev,&idev->qos,hwname); netif_start_queue(ndev); @@ -843,7 +889,6 @@ static int vlsi_close(struct net_device { vlsi_irda_dev_t *idev = ndev->priv; struct pci_dev *pdev = idev->pdev; - int i; u8 cmd; unsigned iobase; @@ -861,30 +906,26 @@ static int vlsi_close(struct net_device outw(0, iobase+VLSI_PIO_IRCFG); /* disable everything */ wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); - mb(); /* from now on */ + mb(); /* ... from now on */ outw(0, iobase+VLSI_PIO_IRENABLE); wmb(); + vlsi_clear_regs(ndev->base_addr); + vlsi_stop_clock(pdev); vlsi_unset_clock(pdev); free_irq(ndev->irq,ndev); - if (idev->ring_buf) { - for (i = 0; i < 2*MAX_RING_DESCR; i++) { - if (idev->ring_buf[i].head) - kfree(idev->ring_buf[i].head); - } - kfree(idev->ring_buf); - } + vlsi_free_ringbuf(&idev->rx_ring); + vlsi_free_ringbuf(&idev->tx_ring); if (idev->busaddr) - pci_free_consistent(idev->pdev,RING_AREA_SIZE,idev->ring_hw,idev->busaddr); + pci_free_consistent(idev->pdev,RING_AREA_SIZE,idev->virtaddr,idev->busaddr); - idev->ring_buf = NULL; - idev->ring_hw = NULL; + idev->virtaddr = NULL; idev->busaddr = 0; pci_read_config_byte(pdev, PCI_COMMAND, &cmd); @@ -895,7 +936,6 @@ static int vlsi_close(struct net_device printk(KERN_INFO "%s: device %s stopped\n", __FUNCTION__, ndev->name); - MOD_DEC_USE_COUNT; return 0; } @@ -909,16 +949,17 @@ static struct net_device_stats * vlsi_ge static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { vlsi_irda_dev_t *idev = ndev->priv; + struct vlsi_ring *r; unsigned long flags; - int iobase; + unsigned iobase; u8 status; u16 config; int mtt; - int entry; int len, speed; + struct timeval now, ready; - iobase = ndev->base_addr; + status = 0; speed = irda_get_next_speed(skb); @@ -931,71 +972,88 @@ static int vlsi_hard_start_xmit(struct s } status = TX_STAT_CLRENTX; /* stop tx-ring after this frame */ } - else - status = 0; + if (skb->len == 0) { + printk(KERN_ERR "%s: blocking 0-size packet???\n", + __FUNCTION__); + dev_kfree_skb(skb); + return 0; + } - spin_lock_irqsave(&idev->lock,flags); + r = &idev->tx_ring; - entry = idev->tx_put; + if (rd_is_active(r, r->head)) + BUG(); if (idev->mode == IFF_SIR) { status |= TX_STAT_DISCRC; - len = async_wrap_skb(skb, idev->ring_buf[entry].head, - XFER_BUF_SIZE); + len = async_wrap_skb(skb, r->buf[r->head].data, XFER_BUF_SIZE); } else { /* hw deals with MIR/FIR mode */ len = skb->len; - memcpy(idev->ring_buf[entry].head, skb->data, len); + memcpy(r->buf[r->head].data, skb->data, len); } - if (len == 0) - printk(KERN_ERR "%s: sending 0-size packet???\n", - __FUNCTION__); - - status |= RD_STAT_ACTIVE; - - rd_set_count(idev->ring_hw+entry, len); - rd_set_status(idev->ring_hw+entry, status); - ring_ptr_inc(&idev->tx_put, idev->tx_mask); + rd_set_count(r, r->head, len); + rd_set_addr_status(r, r->head, virt_to_bus(r->buf[r->head].data), status); - dev_kfree_skb(skb); + /* new entry not yet activated! */ #if 0 printk(KERN_DEBUG "%s: dump entry %d: %u %02x %08x\n", - __FUNCTION__, entry, - idev->ring_hw[entry].rd_count, - (unsigned)idev->ring_hw[entry].rd_status, - idev->ring_hw[entry].rd_addr & 0xffffffff); + __FUNCTION__, r->head, + idev->ring_hw[r->head].rd_count, + (unsigned)idev->ring_hw[r->head].rd_status, + idev->ring_hw[r->head].rd_addr & 0xffffffff); vlsi_reg_debug(iobase,__FUNCTION__); #endif + + /* let mtt delay pass before we need to acquire the spinlock! */ + + if ((mtt = irda_get_mtt(skb)) > 0) { + + ready.tv_usec = idev->last_rx.tv_usec + mtt; + ready.tv_sec = idev->last_rx.tv_sec; + if (ready.tv_usec >= 1000000) { + ready.tv_usec -= 1000000; + ready.tv_sec++; /* IrLAP 1.1: mtt always < 1 sec */ + } + for(;;) { + do_gettimeofday(&now); + if (now.tv_sec > ready.tv_sec + || (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) + break; + udelay(100); + } + } + /* - * race window due to concurrent controller processing! + * race window ahead, due to concurrent controller processing! * - * we may loose ENTX at any time when the controller - * fetches an inactive descr or one with CLR_ENTX set. - * therefore we only rely on the controller telling us - * tx is already stopped because (cannot restart without PROMPT). - * instead we depend on the tx-complete-isr to detect the - * false negatives and retrigger the tx ring. - * that's why we need interrupts disabled till tx has been - * kicked, so the tx-complete-isr was either already finished - * before we've put the new active descriptor on the ring - or - * the isr will be called after the new active descr is on the - * ring _and_ the ring was prompted. Making these two steps - * atomic allows to resolve the race. + * We need to disable IR output in order to switch to TX mode. + * Better not do this blindly anytime we want to transmit something + * because TX may already run. However the controller may stop TX + * at any time when fetching an inactive descriptor or one with + * CLR_ENTX set. So we switch on TX only, if TX was not running + * _after_ the new descriptor was activated on the ring. This ensures + * we will either find TX already stopped or we can be sure, there + * will be a TX-complete interrupt even if the chip stopped doing + * TX just after we found it still running. The ISR will then find + * the non-empty ring and restart TX processing. The enclosing + * spinlock is required to get serialization with the ISR right. */ + iobase = ndev->base_addr; - if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { + spin_lock_irqsave(&idev->lock,flags); - mtt = irda_get_mtt(skb); - if (mtt) { - udelay(mtt); /* ### FIXME ... */ - } + rd_activate(r, r->head); + ring_put(r); + if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { + outw(0, iobase+VLSI_PIO_IRENABLE); config = inw(iobase+VLSI_PIO_IRCFG); @@ -1003,29 +1061,28 @@ static int vlsi_hard_start_xmit(struct s outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); wmb(); outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE); - mb(); - outw(0, iobase+VLSI_PIO_PROMPT); wmb(); } - spin_unlock_irqrestore(&idev->lock, flags); - - if (idev->tx_put == idev->tx_get) { + if (r->head == r->tail) { netif_stop_queue(ndev); printk(KERN_DEBUG "%s: tx ring full - queue stopped: %d/%d\n", - __FUNCTION__, idev->tx_put, idev->tx_get); - entry = idev->tx_get; + __FUNCTION__, r->head, r->tail); +#if 0 printk(KERN_INFO "%s: dump stalled entry %d: %u %02x %08x\n", - __FUNCTION__, entry, - idev->ring_hw[entry].rd_count, - (unsigned)idev->ring_hw[entry].rd_status, - idev->ring_hw[entry].rd_addr & 0xffffffff); + __FUNCTION__, r->tail, + r->hw[r->tail].rd_count, + (unsigned)r->hw[r->tail].rd_status, + r->hw[r->tail].rd_addr & 0xffffffff); +#endif vlsi_reg_debug(iobase,__FUNCTION__); } -// vlsi_reg_debug(iobase, __FUNCTION__); + spin_unlock_irqrestore(&idev->lock, flags); + + dev_kfree_skb(skb); return 0; } @@ -1056,6 +1113,10 @@ static int vlsi_ioctl(struct net_device irda_device_set_media_busy(ndev, TRUE); break; case SIOCGRECEIVING: + /* the best we can do: check whether there are any bytes in rx fifo. + * The trustable window (in case some data arrives just afterwards) + * may be as short as 1usec or so at 4Mbps - no way for future-telling. + */ fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; irq->ifr_receiving = (fifocnt!=0) ? 1 : 0; break; @@ -1091,7 +1152,6 @@ int vlsi_irda_init(struct net_device *nd return -1; } pci_set_master(pdev); - pdev->dma_mask = DMA_MASK_MSTRPAGE; pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE); @@ -1110,13 +1170,13 @@ int vlsi_irda_init(struct net_device *nd | IR_19200 | IR_38400 | IR_57600 | IR_115200 | IR_1152000 | (IR_4000000 << 8); - idev->qos.min_turn_time.bits = mtt_bits; + idev->qos.min_turn_time.bits = qos_mtt_bits; irda_qos_bits_to_value(&idev->qos); irda_device_setup(ndev); - /* currently no media definitions for SIR/MIR/FIR */ + /* currently no public media definitions for IrDA */ ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; ndev->if_port = IF_PORT_UNKNOWN; @@ -1139,15 +1199,18 @@ vlsi_irda_probe(struct pci_dev *pdev, co vlsi_irda_dev_t *idev; int alloc_size; - printk(KERN_INFO "%s: found IrDA PCI controler %s\n", drivername, pdev->name); + vlsi_reg_debug(0x3000, "vlsi initial state"); if (pci_enable_device(pdev)) goto out; + printk(KERN_INFO "%s: IrDA PCI controller %s detected\n", + drivername, pdev->name); + if ( !pci_resource_start(pdev,0) || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { printk(KERN_ERR "%s: bar 0 invalid", __FUNCTION__); - goto out; + goto out_disable; } alloc_size = sizeof(*ndev) + sizeof(*idev); @@ -1156,7 +1219,7 @@ vlsi_irda_probe(struct pci_dev *pdev, co if (ndev==NULL) { printk(KERN_ERR "%s: Unable to allocate device memory.\n", __FUNCTION__); - goto out; + goto out_disable; } memset(ndev, 0, alloc_size); @@ -1181,6 +1244,8 @@ vlsi_irda_probe(struct pci_dev *pdev, co out_freedev: kfree(ndev); +out_disable: + pci_disable_device(pdev); out: pdev->driver_data = NULL; return -ENODEV; @@ -1233,23 +1298,32 @@ static struct pci_driver vlsi_irda_drive static int __init vlsi_mod_init(void) { + int i; + if (clksrc < 0 || clksrc > 3) { - printk(KERN_ERR "%s: invalid clksrc=%d\n", __FUNCTION__, clksrc); + printk(KERN_ERR "%s: invalid clksrc=%d\n", drivername, clksrc); return -1; } - if ( ringsize[0]==0 || (ringsize[0] & ~(64|32|16|8|4)) - || ((ringsize[0]-1)&ringsize[0])) { - printk(KERN_INFO "%s: invalid tx ringsize %d - using default=16\n", - __FUNCTION__, ringsize[0]); - ringsize[0] = 16; + + for (i = 0; i < 2; i++) { + switch(ringsize[i]) { + case 4: + case 8: + case 16: + case 32: + case 64: + break; + default: + printk(KERN_WARNING "%s: invalid %s ringsize %d", + drivername, (i)?"rx":"tx", ringsize[i]); + printk(", using default=8\n"); + ringsize[i] = 8; + break; + } } - if ( ringsize[1]==0 || (ringsize[1] & ~(64|32|16|8|4)) - || ((ringsize[1]-1)&ringsize[1])) { - printk(KERN_INFO "%s: invalid rx ringsize %d - using default=16\n", - __FUNCTION__, ringsize[1]); - ringsize[1] = 16; - } + sirpulse = !!sirpulse; + return pci_module_init(&vlsi_irda_driver); } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
|  |