* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * Module options:
+ *
+ * debug:
+ * NOTE: only one poll value must be given for all cards
+ * See hfc_pci.h for debug flags.
+ *
+ * poll:
+ * NOTE: only one poll value must be given for all cards
+ * Give the number of samples for each fifo process.
+ * By default 128 is used. Decrease to reduce delay, increase to
+ * reduce cpu load. If unsure, don't mess with it!
+ * A value of 128 will use controller's interrupt. Other values will
+ * use kernel timer, because the controller will not allow lower values
+ * than 128.
+ * Also note that the value depends on the kernel timer frequency.
+ * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible.
+ * If the kernel uses 100 Hz, steps of 80 samples are possible.
+ * If the kernel uses 300 Hz, steps of about 26 samples are possible.
+ *
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/mISDNhw.h>
+#include <linux/slab.h>
#include "hfc_pci.h"
static int HFC_cnt;
static uint debug;
+static uint poll, tics;
+static struct timer_list hfc_tl;
+static unsigned long hfc_jiffies;
MODULE_AUTHOR("Karsten Keil");
MODULE_LICENSE("GPL");
-module_param(debug, uint, 0);
-
-static LIST_HEAD(HFClist);
-static DEFINE_RWLOCK(HFClock);
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(poll, uint, S_IRUGO | S_IWUSR);
enum {
HFC_CCD_2BD0,
struct hfc_pci {
- struct list_head list;
u_char subtype;
u_char chanlimit;
u_char initdone;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* Clear already pending ints */
- if (Read_hfc(hc, HFCPCI_INT_S1));
+ val = Read_hfc(hc, HFCPCI_INT_S1);
/* set NT/TE mode */
hfcpci_setmode(hc);
}
bz->za[new_f2].z2 = cpu_to_le16(new_z2);
bz->f2 = new_f2; /* next buffer */
- recv_Bchannel(bch);
+ recv_Bchannel(bch, MISDN_ID_ANY);
}
}
df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) |
(MAX_D_FRAMES + 1); /* next buffer */
df->za[df->f2 & D_FREG_MASK].z2 =
- cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1));
+ cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) &
+ (D_FIFO_SIZE - 1));
} else {
dch->rx_skb = mI_alloc_skb(rcnt - 3, GFP_ATOMIC);
if (!dch->rx_skb) {
}
/*
- * check for transparent receive data and read max one threshold size if avail
+ * check for transparent receive data and read max one 'poll' size if avail
*/
-static int
-hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
+static void
+hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
+ struct bzfifo *txbz, u_char *bdata)
{
- __le16 *z1r, *z2r;
- int new_z2, fcnt, maxlen;
- u_char *ptr, *ptr1;
+ __le16 *z1r, *z2r, *z1t, *z2t;
+ int new_z2, fcnt_rx, fcnt_tx, maxlen;
+ u_char *ptr, *ptr1;
- z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
+ z1r = &rxbz->za[MAX_B_FRAMES].z1; /* pointer to z reg */
z2r = z1r + 1;
+ z1t = &txbz->za[MAX_B_FRAMES].z1;
+ z2t = z1t + 1;
- fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
- if (!fcnt)
- return 0; /* no data avail */
+ fcnt_rx = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
+ if (!fcnt_rx)
+ return; /* no data avail */
- if (fcnt <= 0)
- fcnt += B_FIFO_SIZE; /* bytes actually buffered */
- if (fcnt > HFCPCI_BTRANS_THRESHOLD)
- fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
-
- new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */
+ if (fcnt_rx <= 0)
+ fcnt_rx += B_FIFO_SIZE; /* bytes actually buffered */
+ new_z2 = le16_to_cpu(*z2r) + fcnt_rx; /* new position in fifo */
if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
new_z2 -= B_FIFO_SIZE; /* buffer wrap */
- bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC);
+ if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */
+ *z2r = cpu_to_le16(new_z2); /* new position */
+ return;
+ }
+
+ fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
+ if (fcnt_tx <= 0)
+ fcnt_tx += B_FIFO_SIZE;
+ /* fcnt_tx contains available bytes in tx-fifo */
+ fcnt_tx = B_FIFO_SIZE - fcnt_tx;
+ /* remaining bytes to send (bytes in tx-fifo) */
+
+ bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC);
if (bch->rx_skb) {
- ptr = skb_put(bch->rx_skb, fcnt);
- if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL)
- maxlen = fcnt; /* complete transfer */
+ ptr = skb_put(bch->rx_skb, fcnt_rx);
+ if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL)
+ maxlen = fcnt_rx; /* complete transfer */
else
maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(*z2r);
/* maximum */
ptr1 = bdata + (le16_to_cpu(*z2r) - B_SUB_VAL);
/* start of data */
memcpy(ptr, ptr1, maxlen); /* copy data */
- fcnt -= maxlen;
+ fcnt_rx -= maxlen;
- if (fcnt) { /* rest remaining */
+ if (fcnt_rx) { /* rest remaining */
ptr += maxlen;
ptr1 = bdata; /* start of buffer */
- memcpy(ptr, ptr1, fcnt); /* rest */
+ memcpy(ptr, ptr1, fcnt_rx); /* rest */
}
- recv_Bchannel(bch);
+ recv_Bchannel(bch, fcnt_tx); /* bch, id */
} else
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
*z2r = cpu_to_le16(new_z2); /* new position */
- return 1;
}
/*
{
struct hfc_pci *hc = bch->hw;
int rcnt, real_fifo;
- int receive, count = 5;
- struct bzfifo *bz;
+ int receive = 0, count = 5;
+ struct bzfifo *txbz, *rxbz;
u_char *bdata;
struct zt *zp;
-
if ((bch->nr & 2) && (!hc->hw.bswapped)) {
- bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
+ rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
+ txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
real_fifo = 1;
} else {
- bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
+ rxbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b1;
+ txbz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b1;
bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b1;
real_fifo = 0;
}
Begin:
count--;
- if (bz->f1 != bz->f2) {
+ if (rxbz->f1 != rxbz->f2) {
if (bch->debug & DEBUG_HW_BCHANNEL)
printk(KERN_DEBUG "hfcpci rec ch(%x) f1(%d) f2(%d)\n",
- bch->nr, bz->f1, bz->f2);
- zp = &bz->za[bz->f2];
+ bch->nr, rxbz->f1, rxbz->f2);
+ zp = &rxbz->za[rxbz->f2];
rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2);
if (rcnt < 0)
"hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)\n",
bch->nr, le16_to_cpu(zp->z1),
le16_to_cpu(zp->z2), rcnt);
- hfcpci_empty_bfifo(bch, bz, bdata, rcnt);
- rcnt = bz->f1 - bz->f2;
+ hfcpci_empty_bfifo(bch, rxbz, bdata, rcnt);
+ rcnt = rxbz->f1 - rxbz->f2;
if (rcnt < 0)
rcnt += MAX_B_FRAMES + 1;
if (hc->hw.last_bfifo_cnt[real_fifo] > rcnt + 1) {
receive = 1;
else
receive = 0;
- } else if (test_bit(FLG_TRANSPARENT, &bch->Flags))
- receive = hfcpci_empty_fifo_trans(bch, bz, bdata);
- else
+ } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ hfcpci_empty_fifo_trans(bch, rxbz, txbz, bdata);
+ return;
+ } else
receive = 0;
if (count && receive)
goto Begin;
next_t_frame:
count = bch->tx_skb->len - bch->tx_idx;
- /* maximum fill shall be HFCPCI_BTRANS_MAX */
- if (count > HFCPCI_BTRANS_MAX - fcnt)
- count = HFCPCI_BTRANS_MAX - fcnt;
+ /* maximum fill shall be poll*2 */
+ if (count > (poll << 1) - fcnt)
+ count = (poll << 1) - fcnt;
if (count <= 0)
return;
/* data is suitable for fifo */
ph_state_nt(struct dchannel *dch)
{
struct hfc_pci *hc = dch->hw;
+ u_char val;
if (dch->debug)
printk(KERN_DEBUG "%s: NT newstate %x\n",
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* Clear already pending ints */
- if (Read_hfc(hc, HFCPCI_INT_S1));
+ val = Read_hfc(hc, HFCPCI_INT_S1);
Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
udelay(10);
Write_hfc(hc, HFCPCI_STATES, 4);
val &= ~0x80;
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
}
- if (val & 0x08) {
+ if (val & 0x08) { /* B1 rx */
bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
if (bch)
main_rec_hfcpci(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n");
}
- if (val & 0x10) {
+ if (val & 0x10) { /* B2 rx */
bch = Sel_BCS(hc, 2);
if (bch)
main_rec_hfcpci(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n");
}
- if (val & 0x01) {
+ if (val & 0x01) { /* B1 tx */
bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
if (bch)
tx_birq(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n");
}
- if (val & 0x02) {
+ if (val & 0x02) { /* B2 tx */
bch = Sel_BCS(hc, 2);
if (bch)
tx_birq(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n");
}
- if (val & 0x20)
+ if (val & 0x20) /* D rx */
receive_dmsg(hc);
- if (val & 0x04) { /* dframe transmitted */
+ if (val & 0x04) { /* D tx */
if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
del_timer(&hc->dch.timer);
tx_dirq(&hc->dch);
rx_slot = (bc>>8) & 0xff;
tx_slot = (bc>>16) & 0xff;
bc = bc & 0xff;
- } else if (test_bit(HFC_CFG_PCM, &hc->cfg) &&
- (protocol > ISDN_P_NONE))
+ } else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_P_NONE))
printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
__func__);
if (hc->chanlimit > 1) {
case (ISDN_P_B_RAW):
bch->state = protocol;
bch->nr = bc;
- hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
- hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+ hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
+ hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
if (bc & 2) {
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
}
if (fifo2 & 2) {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
- hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
- HFCPCI_INTS_B2REC);
+ if (!tics)
+ hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
+ HFCPCI_INTS_B2REC);
hc->hw.ctmt |= 2;
hc->hw.conn &= ~0x18;
} else {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
- hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
- HFCPCI_INTS_B1REC);
+ if (!tics)
+ hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
+ HFCPCI_INTS_B1REC);
hc->hw.ctmt |= 1;
hc->hw.conn &= ~0x03;
}
case (ISDN_P_B_HDLC):
bch->state = protocol;
bch->nr = bc;
- hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0);
- hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0);
+ hfcpci_clear_fifo_rx(hc, (fifo2 & 2) ? 1 : 0);
+ hfcpci_clear_fifo_tx(hc, (fifo2 & 2) ? 1 : 0);
if (bc & 2) {
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
switch (protocol) {
case (ISDN_P_B_RAW):
bch->state = protocol;
- hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0);
+ hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
if (chan & 2) {
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
+ if (!tics)
+ hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
hc->hw.ctmt |= 2;
hc->hw.conn &= ~0x18;
#ifdef REVERSE_BITORDER
} else {
hc->hw.sctrl_r |= SCTRL_B1_ENA;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
+ if (!tics)
+ hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
hc->hw.ctmt |= 1;
hc->hw.conn &= ~0x03;
#ifdef REVERSE_BITORDER
break;
case (ISDN_P_B_HDLC):
bch->state = protocol;
- hfcpci_clear_fifo_rx(hc, (chan & 2)?1:0);
+ hfcpci_clear_fifo_rx(hc, (chan & 2) ? 1 : 0);
if (chan & 2) {
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.last_bfifo_cnt[1] = 0;
u_long flags;
spin_lock_irqsave(&hc->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
+ mISDN_clear_bchannel(bch);
mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
spin_unlock_irqrestore(&hc->lock, flags);
}
printk(KERN_WARNING
"HFC PCI: IRQ(%d) getting no interrupts "
"during init %d\n", hc->irq, 4 - cnt);
- if (cnt == 1) {
- spin_unlock_irqrestore(&hc->lock, flags);
- return -EIO;
- } else {
+ if (cnt == 1)
+ break;
+ else {
reset_hfcpci(hc);
cnt--;
}
if (rq->protocol != ch->protocol) {
if (hc->hw.protocol == ISDN_P_TE_S0)
l1_event(hc->dch.l1, CLOSE_CHANNEL);
+ if (rq->protocol == ISDN_P_TE_S0) {
+ err = create_l1(&hc->dch, hfc_l1callback);
+ if (err)
+ return err;
+ }
hc->hw.protocol = rq->protocol;
ch->protocol = rq->protocol;
hfcpci_setmode(hc);
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return 1;
}
- hc->hw.pci_io = (char __iomem *)(unsigned long)hc->pdev->resource[1].start;
+ hc->hw.pci_io =
+ (char __iomem *)(unsigned long)hc->pdev->resource[1].start;
if (!hc->hw.pci_io) {
printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
mISDN_freebchannel(&hc->bch[1]);
mISDN_freebchannel(&hc->bch[0]);
mISDN_freedchannel(&hc->dch);
- list_del(&hc->list);
pci_set_drvdata(hc->pdev, NULL);
kfree(hc);
}
{
int err = -EINVAL;
u_int i;
- u_long flags;
char name[MISDN_MAX_IDLEN];
card->dch.debug = debug;
if (err)
goto error;
snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1);
- err = mISDN_register_device(&card->dch.dev, name);
+ err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name);
if (err)
goto error;
HFC_cnt++;
- write_lock_irqsave(&HFClock, flags);
- list_add_tail(&card->list, &HFClist);
- write_unlock_irqrestore(&HFClock, flags);
printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
return 0;
error:
hfc_remove_pci(struct pci_dev *pdev)
{
struct hfc_pci *card = pci_get_drvdata(pdev);
- u_long flags;
- if (card) {
- write_lock_irqsave(&HFClock, flags);
+ if (card)
release_card(card);
- write_unlock_irqrestore(&HFClock, flags);
- } else
+ else
if (debug)
- printk(KERN_WARNING "%s: drvdata allready removed\n",
+ printk(KERN_DEBUG "%s: drvdata already removed\n",
__func__);
}
.id_table = hfc_ids,
};
+static int
+_hfcpci_softirq(struct device *dev, void *arg)
+{
+ struct hfc_pci *hc = dev_get_drvdata(dev);
+ struct bchannel *bch;
+ if (hc == NULL)
+ return 0;
+
+ if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
+ spin_lock(&hc->lock);
+ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
+ if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
+ main_rec_hfcpci(bch);
+ tx_birq(bch);
+ }
+ bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2);
+ if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */
+ main_rec_hfcpci(bch);
+ tx_birq(bch);
+ }
+ spin_unlock(&hc->lock);
+ }
+ return 0;
+}
+
+static void
+hfcpci_softirq(void *arg)
+{
+ (void) driver_for_each_device(&hfc_driver.driver, NULL, arg,
+ _hfcpci_softirq);
+
+ /* if next event would be in the past ... */
+ if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
+ hfc_jiffies = jiffies + 1;
+ else
+ hfc_jiffies += tics;
+ hfc_tl.expires = hfc_jiffies;
+ add_timer(&hfc_tl);
+}
+
static int __init
HFC_init(void)
{
int err;
+ if (!poll)
+ poll = HFCPCI_BTRANS_THRESHOLD;
+
+ if (poll != HFCPCI_BTRANS_THRESHOLD) {
+ tics = (poll * HZ) / 8000;
+ if (tics < 1)
+ tics = 1;
+ poll = (tics * 8000) / HZ;
+ if (poll > 256 || poll < 8) {
+ printk(KERN_ERR "%s: Wrong poll value %d not in range "
+ "of 8..256.\n", __func__, poll);
+ err = -EINVAL;
+ return err;
+ }
+ }
+ if (poll != HFCPCI_BTRANS_THRESHOLD) {
+ printk(KERN_INFO "%s: Using alternative poll value of %d\n",
+ __func__, poll);
+ hfc_tl.function = (void *)hfcpci_softirq;
+ hfc_tl.data = 0;
+ init_timer(&hfc_tl);
+ hfc_tl.expires = jiffies + tics;
+ hfc_jiffies = hfc_tl.expires;
+ add_timer(&hfc_tl);
+ } else
+ tics = 0; /* indicate the use of controller's timer */
+
err = pci_register_driver(&hfc_driver);
+ if (err) {
+ if (timer_pending(&hfc_tl))
+ del_timer(&hfc_tl);
+ }
+
return err;
}
static void __exit
HFC_cleanup(void)
{
- struct hfc_pci *card, *next;
+ if (timer_pending(&hfc_tl))
+ del_timer(&hfc_tl);
- list_for_each_entry_safe(card, next, &HFClist, list) {
- release_card(card);
- }
pci_unregister_driver(&hfc_driver);
}
module_init(HFC_init);
module_exit(HFC_cleanup);
+
+MODULE_DEVICE_TABLE(pci, hfc_ids);