Commit 38171d07 authored by Jes Sorensen's avatar Jes Sorensen Committed by Jeff Garzik

acenic gige net driver fixes:

* fix Tigon I support
* fix memory leak
parent 6f005af3
......@@ -84,8 +84,10 @@
#ifdef CONFIG_ACENIC_OMIT_TIGON_I
#define ACE_IS_TIGON_I(ap) 0
#define ACE_TX_RING_ENTRIES(ap) MAX_TX_RING_ENTRIES
#else
#define ACE_IS_TIGON_I(ap) (ap->version == 1)
#define ACE_TX_RING_ENTRIES(ap) ap->tx_ring_entries
#endif
#ifndef PCI_VENDOR_ID_ALTEON
......@@ -554,7 +556,7 @@ static int tx_ratio[ACE_MAX_MOD_PARMS];
static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
static char version[] __initdata =
"acenic.c: v0.87 03/14/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
"acenic.c: v0.88 03/14/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
static struct net_device *root_dev;
......@@ -960,6 +962,13 @@ static void ace_free_descriptors(struct net_device *dev)
ap->evt_ring_dma);
ap->evt_ring = NULL;
}
if (ap->tx_ring != NULL && !ACE_IS_TIGON_I(ap)) {
size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
pci_free_consistent(ap->pdev, size, ap->tx_ring,
ap->tx_ring_dma);
}
ap->tx_ring = NULL;
if (ap->evt_prd != NULL) {
pci_free_consistent(ap->pdev, sizeof(u32),
(void *)ap->evt_prd, ap->evt_prd_dma);
......@@ -1006,12 +1015,19 @@ static int ace_allocate_descriptors(struct net_device *dev)
if (ap->evt_ring == NULL)
goto fail;
size = (sizeof(struct tx_desc) * TX_RING_ENTRIES);
/*
* Only allocate a host TX ring for the Tigon II, the Tigon I
* has to use PCI registers for this ;-(
*/
if (!ACE_IS_TIGON_I(ap)) {
size = (sizeof(struct tx_desc) * MAX_TX_RING_ENTRIES);
ap->tx_ring = pci_alloc_consistent(ap->pdev, size, &ap->tx_ring_dma);
ap->tx_ring = pci_alloc_consistent(ap->pdev, size,
&ap->tx_ring_dma);
if (ap->tx_ring == NULL)
goto fail;
}
ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32),
&ap->evt_prd_dma);
......@@ -1145,6 +1161,7 @@ static int __init ace_init(struct net_device *dev)
tigonFwReleaseFix);
writel(0, &regs->LocalCtrl);
ap->version = 1;
ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES;
break;
#endif
case 6:
......@@ -1160,6 +1177,7 @@ static int __init ace_init(struct net_device *dev)
writel(SRAM_BANK_512K, &regs->LocalCtrl);
writel(SYNC_SRAM_TIMING, &regs->MiscCfg);
ap->version = 2;
ap->tx_ring_entries = MAX_TX_RING_ENTRIES;
break;
default:
printk(KERN_WARNING " Unsupported Tigon version detected "
......@@ -1390,7 +1408,7 @@ static int __init ace_init(struct net_device *dev)
#ifdef INDEX_DEBUG
spin_lock_init(&ap->debug_lock);
ap->last_tx = TX_RING_ENTRIES - 1;
ap->last_tx = ACE_TX_RING_ENTRIES(ap) - 1;
ap->last_std_rx = 0;
ap->last_mini_rx = 0;
#endif
......@@ -1498,12 +1516,30 @@ static int __init ace_init(struct net_device *dev)
*(ap->rx_ret_prd) = 0;
writel(TX_RING_BASE, &regs->WinBase);
memset(ap->tx_ring, 0, TX_RING_ENTRIES * sizeof(struct tx_desc));
if (ACE_IS_TIGON_I(ap)) {
ap->tx_ring = (struct tx_desc *)regs->Window;
for (i = 0; i < (TIGON_I_TX_RING_ENTRIES *
sizeof(struct tx_desc) / 4); i++) {
writel(0, (unsigned long)ap->tx_ring + i * 4);
}
set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
} else {
memset(ap->tx_ring, 0,
MAX_TX_RING_ENTRIES * sizeof(struct tx_desc));
set_aceaddr(&info->tx_ctrl.rngptr, ap->tx_ring_dma);
}
info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
info->tx_ctrl.max_len = TX_RING_ENTRIES;
tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|RCB_FLG_TX_HOST_RING;
/*
* The Tigon I does not like having the TX ring in host memory ;-(
*/
if (!ACE_IS_TIGON_I(ap))
tmp |= RCB_FLG_TX_HOST_RING;
#if TX_COAL_INTS_ONLY
tmp |= RCB_FLG_COAL_INT_ONLY;
#endif
......@@ -2264,7 +2300,7 @@ static inline void ace_tx_int(struct net_device *dev,
info->skb = NULL;
}
idx = (idx + 1) % TX_RING_ENTRIES;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
} while (idx != txcsm);
if (netif_queue_stopped(dev))
......@@ -2357,7 +2393,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* update releases enough of space, otherwise we just
* wait for device to make more work.
*/
if (!tx_ring_full(txcsm, ap->tx_prd))
if (!tx_ring_full(ap, txcsm, ap->tx_prd))
ace_tx_int(dev, txcsm, idx);
}
......@@ -2531,7 +2567,7 @@ static int ace_close(struct net_device *dev)
save_flags(flags);
cli();
for (i = 0; i < TX_RING_ENTRIES; i++) {
for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
struct sk_buff *skb;
dma_addr_t mapping;
struct tx_ring_info *info;
......@@ -2541,7 +2577,13 @@ static int ace_close(struct net_device *dev)
mapping = pci_unmap_addr(info, mapping);
if (mapping) {
memset(ap->tx_ring + i, 0, sizeof(struct tx_desc));
if (ACE_IS_TIGON_I(ap)) {
writel(0, &ap->tx_ring[i].addr.addrhi);
writel(0, &ap->tx_ring[i].addr.addrlo);
writel(0, &ap->tx_ring[i].flagsize);
} else
memset(ap->tx_ring + i, 0,
sizeof(struct tx_desc));
pci_unmap_page(ap->pdev, mapping,
pci_unmap_len(info, maplen),
PCI_DMA_TODEVICE);
......@@ -2587,15 +2629,21 @@ ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
static inline void
ace_load_tx_bd(struct tx_desc *desc, u64 addr, u32 flagsize)
ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc,
u64 addr, u32 flagsize)
{
#if !USE_TX_COAL_NOW
flagsize &= ~BD_FLG_COAL_NOW;
#endif
if (!ACE_IS_TIGON_I(ap)) {
writel(addr >> 32, &desc->addr.addrhi);
writel(addr & 0xffffffff, &desc->addr.addrlo);
writel(flagsize, &desc->flagsize);
} else {
desc->addr.addrhi = addr >> 32;
desc->addr.addrlo = addr;
desc->flagsize = flagsize;
}
}
......@@ -2615,7 +2663,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
restart:
idx = ap->tx_prd;
if (tx_ring_full(ap->tx_ret_csm, idx))
if (tx_ring_full(ap, ap->tx_ret_csm, idx))
goto overflow;
#if MAX_SKB_FRAGS
......@@ -2629,13 +2677,13 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_HW)
flagsize |= BD_FLG_TCP_UDP_SUM;
desc = ap->tx_ring + idx;
idx = (idx + 1) % TX_RING_ENTRIES;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
/* Look at ace_tx_int for explanations. */
if (tx_ring_full(ap->tx_ret_csm, idx))
if (tx_ring_full(ap, ap->tx_ret_csm, idx))
flagsize |= BD_FLG_COAL_NOW;
ace_load_tx_bd(desc, mapping, flagsize);
ace_load_tx_bd(ap, desc, mapping, flagsize);
}
#if MAX_SKB_FRAGS
else {
......@@ -2647,9 +2695,9 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_HW)
flagsize |= BD_FLG_TCP_UDP_SUM;
ace_load_tx_bd(ap->tx_ring + idx, mapping, flagsize);
ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize);
idx = (idx + 1) % TX_RING_ENTRIES;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
......@@ -2666,11 +2714,11 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
flagsize = (frag->size << 16);
if (skb->ip_summed == CHECKSUM_HW)
flagsize |= BD_FLG_TCP_UDP_SUM;
idx = (idx + 1) % TX_RING_ENTRIES;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
if (i == skb_shinfo(skb)->nr_frags - 1) {
flagsize |= BD_FLG_END;
if (tx_ring_full(ap->tx_ret_csm, idx))
if (tx_ring_full(ap, ap->tx_ret_csm, idx))
flagsize |= BD_FLG_COAL_NOW;
/*
......@@ -2683,7 +2731,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
pci_unmap_addr_set(info, mapping, mapping);
pci_unmap_len_set(info, maplen, frag->size);
ace_load_tx_bd(desc, mapping, flagsize);
ace_load_tx_bd(ap, desc, mapping, flagsize);
}
}
#endif
......@@ -2701,7 +2749,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
* serialized, this is the only situation we have to
* re-test.
*/
if (!tx_ring_full(ap->tx_ret_csm, idx))
if (!tx_ring_full(ap, ap->tx_ret_csm, idx))
netif_wake_queue(dev);
}
......@@ -2781,7 +2829,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
return -EFAULT;
switch (ecmd.cmd) {
case ETHTOOL_GSET: {
case ETHTOOL_GSET:
ecmd.supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
......@@ -2829,8 +2877,8 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
case ETHTOOL_SSET: {
case ETHTOOL_SSET:
if(!capable(CAP_NET_ADMIN))
return -EPERM;
......@@ -2887,7 +2935,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
ace_issue_cmd(regs, &cmd);
}
return 0;
}
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, "acenic", sizeof(info.driver) - 1);
......
......@@ -437,10 +437,11 @@ struct cmd {
/*
* TX ring
* TX ring - maximum TX ring entries for Tigon I's is 128
*/
#define TX_RING_ENTRIES 256
#define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc))
#define MAX_TX_RING_ENTRIES 256
#define TIGON_I_TX_RING_ENTRIES 128
#define TX_RING_SIZE (MAX_TX_RING_ENTRIES * sizeof(struct tx_desc))
#define TX_RING_BASE 0x3800
struct tx_desc{
......@@ -608,7 +609,7 @@ struct tx_ring_info {
*/
struct ace_skb
{
struct tx_ring_info tx_skbuff[TX_RING_ENTRIES];
struct tx_ring_info tx_skbuff[MAX_TX_RING_ENTRIES];
struct ring_info rx_std_skbuff[RX_STD_RING_ENTRIES];
struct ring_info rx_mini_skbuff[RX_MINI_RING_ENTRIES];
struct ring_info rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
......@@ -642,6 +643,7 @@ struct ace_private
u32 tx_prd;
volatile u32 tx_ret_csm;
struct timer_list timer;
int tx_ring_entries;
/*
* RX elements
......@@ -692,15 +694,15 @@ struct ace_private
#define TX_RESERVED MAX_SKB_FRAGS
static inline int tx_space (u32 csm, u32 prd)
static inline int tx_space (struct ace_private *ap, u32 csm, u32 prd)
{
return (csm - prd - 1) & (TX_RING_ENTRIES - 1);
return (csm - prd - 1) & (ACE_TX_RING_ENTRIES(ap) - 1);
}
#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd)
#define tx_free(ap) tx_space((ap)->tx_ret_csm, (ap)->tx_prd, ap)
#if MAX_SKB_FRAGS
#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED)
#define tx_ring_full(ap, csm, prd) (tx_space(ap, csm, prd) <= TX_RESERVED)
#else
#define tx_ring_full 0
#endif
......@@ -711,7 +713,7 @@ static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr)
u64 baddr = (u64) addr;
aa->addrlo = baddr & 0xffffffff;
aa->addrhi = baddr >> 32;
mb();
wmb();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment