Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 090bf621 authored by Jeff Garzik's avatar Jeff Garzik Committed by Jeff Garzik
Browse files

Merge branch 'sis190' of...

parents 8ceee660 697c2696
Loading
Loading
Loading
Loading
+81 −55
Original line number Diff line number Diff line
@@ -212,6 +212,12 @@ enum _DescStatusBit {
	THOL2		= 0x20000000,
	THOL1		= 0x10000000,
	THOL0		= 0x00000000,

	WND		= 0x00080000,
	TABRT		= 0x00040000,
	FIFO		= 0x00020000,
	LINK		= 0x00010000,
	ColCountMask	= 0x0000ffff,
	/* RxDesc.status */
	IPON		= 0x20000000,
	TCPON		= 0x10000000,
@@ -480,30 +486,23 @@ static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
	desc->status = 0x0;
}

static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
			       struct RxDesc *desc, u32 rx_buf_sz)
static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
					   struct RxDesc *desc)
{
	u32 rx_buf_sz = tp->rx_buf_sz;
	struct sk_buff *skb;
	dma_addr_t mapping;
	int ret = 0;

	skb = dev_alloc_skb(rx_buf_sz);
	if (!skb)
		goto err_out;

	*sk_buff = skb;
	skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
	if (likely(skb)) {
		dma_addr_t mapping;

	mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
		mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
					 PCI_DMA_FROMDEVICE);

		sis190_map_to_asic(desc, mapping, rx_buf_sz);
out:
	return ret;

err_out:
	ret = -ENOMEM;
	} else
		sis190_make_unusable_by_asic(desc);
	goto out;

	return skb;
}

static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@@ -512,37 +511,41 @@ static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
	u32 cur;

	for (cur = start; cur < end; cur++) {
		int ret, i = cur % NUM_RX_DESC;
		unsigned int i = cur % NUM_RX_DESC;

		if (tp->Rx_skbuff[i])
			continue;

		ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
					  tp->RxDescRing + i, tp->rx_buf_sz);
		if (ret < 0)
		tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);

		if (!tp->Rx_skbuff[i])
			break;
	}
	return cur - start;
}

static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
				     struct RxDesc *desc, int rx_buf_sz)
static bool sis190_try_rx_copy(struct sis190_private *tp,
			       struct sk_buff **sk_buff, int pkt_size,
			       dma_addr_t addr)
{
	int ret = -1;

	if (pkt_size < rx_copybreak) {
	struct sk_buff *skb;
	bool done = false;

		skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
		if (skb) {
			skb_reserve(skb, NET_IP_ALIGN);
	if (pkt_size >= rx_copybreak)
		goto out;

	skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
	if (!skb)
		goto out;

	pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
				       PCI_DMA_FROMDEVICE);
	skb_reserve(skb, 2);
	skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
	*sk_buff = skb;
			sis190_give_to_asic(desc, rx_buf_sz);
			ret = 0;
		}
	}
	return ret;
	done = true;
out:
	return done;
}

static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
@@ -592,9 +595,9 @@ static int sis190_rx_interrupt(struct net_device *dev,
			sis190_give_to_asic(desc, tp->rx_buf_sz);
		else {
			struct sk_buff *skb = tp->Rx_skbuff[entry];
			dma_addr_t addr = le32_to_cpu(desc->addr);
			int pkt_size = (status & RxSizeMask) - 4;
			void (*pci_action)(struct pci_dev *, dma_addr_t,
				size_t, int) = pci_dma_sync_single_for_device;
			struct pci_dev *pdev = tp->pci_dev;

			if (unlikely(pkt_size > tp->rx_buf_sz)) {
				net_intr(tp, KERN_INFO
@@ -606,20 +609,18 @@ static int sis190_rx_interrupt(struct net_device *dev,
				continue;
			}

			pci_dma_sync_single_for_cpu(tp->pci_dev,
				le32_to_cpu(desc->addr), tp->rx_buf_sz,
				PCI_DMA_FROMDEVICE);

			if (sis190_try_rx_copy(&skb, pkt_size, desc,
					       tp->rx_buf_sz)) {
				pci_action = pci_unmap_single;
			if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
				pci_dma_sync_single_for_device(pdev, addr,
					tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
				sis190_give_to_asic(desc, tp->rx_buf_sz);
			} else {
				pci_unmap_single(pdev, addr, tp->rx_buf_sz,
						 PCI_DMA_FROMDEVICE);
				tp->Rx_skbuff[entry] = NULL;
				sis190_make_unusable_by_asic(desc);
			}

			pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
				   tp->rx_buf_sz, PCI_DMA_FROMDEVICE);

			skb_put(skb, pkt_size);
			skb->protocol = eth_type_trans(skb, dev);

@@ -658,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
	memset(desc, 0x00, sizeof(*desc));
}

static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
{
#define TxErrMask	(WND | TABRT | FIFO | LINK)

	if (!unlikely(status & TxErrMask))
		return 0;

	if (status & WND)
		stats->tx_window_errors++;
	if (status & TABRT)
		stats->tx_aborted_errors++;
	if (status & FIFO)
		stats->tx_fifo_errors++;
	if (status & LINK)
		stats->tx_carrier_errors++;

	stats->tx_errors++;

	return -1;
}

static void sis190_tx_interrupt(struct net_device *dev,
				struct sis190_private *tp, void __iomem *ioaddr)
{
	struct net_device_stats *stats = &dev->stats;
	u32 pending, dirty_tx = tp->dirty_tx;
	/*
	 * It would not be needed if queueing was allowed to be enabled
@@ -675,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev,
	for (; pending; pending--, dirty_tx++) {
		unsigned int entry = dirty_tx % NUM_TX_DESC;
		struct TxDesc *txd = tp->TxDescRing + entry;
		u32 status = le32_to_cpu(txd->status);
		struct sk_buff *skb;

		if (le32_to_cpu(txd->status) & OWNbit)
		if (status & OWNbit)
			break;

		skb = tp->Tx_skbuff[entry];

		dev->stats.tx_packets++;
		dev->stats.tx_bytes += skb->len;
		if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
			stats->tx_packets++;
			stats->tx_bytes += skb->len;
			stats->collisions += ((status & ColCountMask) - 1);
		}

		sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
		tp->Tx_skbuff[entry] = NULL;
@@ -904,10 +931,9 @@ static void sis190_phy_task(struct work_struct *work)
		mod_timer(&tp->timer, jiffies + HZ/10);
	} else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
		     BMSR_ANEGCOMPLETE)) {
		net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n",
			 dev->name);
		netif_carrier_off(dev);
		mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
		net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
			 dev->name);
		mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
	} else {
		/* Rejoice ! */