lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 13 Jun 2007 16:27:32 -0400
From:	Jeff Garzik <jeff@...zik.org>
To:	MOKUNO Masakazu <mokuno@...sony.co.jp>
CC:	netdev@...r.kernel.org, Geoff Levand <geoffrey.levand@...sony.com>,
	Geert Uytterhoeven <Geert.Uytterhoeven@...ycom.com>
Subject: Re: [PATCH]: ps3: gigabit ethernet driver for PS3

MOKUNO Masakazu wrote:
> Hi Jeff,
> 
> The following patch adds support for the gigabit ethernet device of PS3. 
> It was sent out before as RFC, now I submit it for 2.6.23.
> 
> Signed-off-by: Masakazu Mokuno <mokuno@...sony.co.jp>
> Signed-off-by: Geoff Levand <geoffrey.levand@...sony.com>
> ---
>  drivers/net/Kconfig     |   10 
>  drivers/net/Makefile    |    2 
>  drivers/net/gelic_net.c | 1564 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/gelic_net.h |  233 +++++++
>  4 files changed, 1809 insertions(+)

a MAINTAINERS entry would be nice


> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2264,6 +2264,16 @@ config TSI108_ETH
>  	     To compile this driver as a module, choose M here: the module
>  	     will be called tsi108_eth.
>  
> +config GELIC_NET
> +	tristate "PS3 Gigabit Ethernet driver"
> +	depends on PPC_PS3
> +	help
> +	  This driver supports the Gigabit Ethernet device on the
> +	  PS3 game console.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called ps3_gelic.
> +
>  config GIANFAR
>  	tristate "Gianfar Ethernet"
>  	depends on 85xx || 83xx || PPC_86xx
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -60,6 +60,8 @@ obj-$(CONFIG_TIGON3) += tg3.o
>  obj-$(CONFIG_BNX2) += bnx2.o
>  spidernet-y += spider_net.o spider_net_ethtool.o
>  obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
> +obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
> +ps3_gelic-objs += gelic_net.o
>  obj-$(CONFIG_TC35815) += tc35815.o
>  obj-$(CONFIG_SKGE) += skge.o
>  obj-$(CONFIG_SKY2) += sky2.o

How about ps3_gige for the driver name.  Ditto DaveM's comments about 
cleanups here.



> --- /dev/null
> +++ b/drivers/net/gelic_net.c
> @@ -0,0 +1,1564 @@
> +/*
> + *  PS3 Platfom gelic network driver.
> + *
> + * Copyright (C) 2007 Sony Computer Entertainment Inc.
> + * Copyright 2007 Sony Corporation
> + *
> + *  this file is based on: spider_net.c
> + *
> + * Network device driver for Cell Processor-Based Blade
> + *
> + * (C) Copyright IBM Corp. 2005
> + *
> + * Authors : Utz Bacher <utz.bacher@...ibm.com>
> + *           Jens Osterkamp <Jens.Osterkamp@...ibm.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#undef DEBUG
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/if_vlan.h>
> +
> +#include <linux/in.h>
> +#include <linux/ip.h>
> +#include <linux/tcp.h>
> +
> +#include <linux/dma-mapping.h>
> +#include <net/checksum.h>
> +#include <asm/firmware.h>
> +#include <asm/ps3.h>
> +#include <asm/lv1call.h>
> +
> +#include "gelic_net.h"

Please run this patch through scripts/checkpatch.pl (newly added in 
latest 2.6.22-rcX-gitY)


> +#define GELIC_NET_DRV_NAME "Gelic Network Driver"
> +#define GELIC_NET_DRV_VERSION "1.0"

please follow other net drivers and use the more simple DRV_NAME and 
DRV_VERSION


> +MODULE_AUTHOR("SCE Inc.");
> +MODULE_DESCRIPTION("Gelic Network driver");
> +MODULE_LICENSE("GPL");
> +
> +static inline struct device * ctodev(struct gelic_net_card * card)
> +{
> +	return &card->dev->core;
> +}
> +static inline unsigned int bus_id(struct gelic_net_card *card)
> +{
> +	return card->dev->bus_id;
> +}
> +static inline unsigned int dev_id(struct gelic_net_card *card)
> +{
> +	return card->dev->dev_id;
> +}
> +
> +/* set irq_mask */
> +static int gelic_net_set_irq_mask(struct gelic_net_card *card, u64 mask)
> +{
> +	int status;
> +
> +	status = lv1_net_set_interrupt_mask(bus_id(card), dev_id(card),
> +					    mask, 0);
> +	if (status)
> +		dev_info(ctodev(card),
> +			 "lv1_net_set_interrupt_mask failed %d\n", status);
> +	return status;
> +}
> +static inline void gelic_net_rx_irq_on(struct gelic_net_card *card)
> +{
> +	gelic_net_set_irq_mask(card, card->ghiintmask | GELIC_NET_RXINT);
> +}
> +static inline void gelic_net_rx_irq_off(struct gelic_net_card *card)
> +{
> +	gelic_net_set_irq_mask(card, card->ghiintmask & ~GELIC_NET_RXINT);
> +}
> +/**
> + * gelic_net_get_descr_status -- returns the status of a descriptor
> + * @descr: descriptor to look at
> + *
> + * returns the status as in the dmac_cmd_status field of the descriptor
> + */
> +static enum gelic_net_descr_status
> +gelic_net_get_descr_status(struct gelic_net_descr *descr)
> +{
> +	u32 cmd_status;
> +
> +	cmd_status = descr->dmac_cmd_status;
> +	cmd_status >>= GELIC_NET_DESCR_IND_PROC_SHIFT;
> +	return cmd_status;
> +}
> +
> +/**
> + * gelic_net_set_descr_status -- sets the status of a descriptor
> + * @descr: descriptor to change
> + * @status: status to set in the descriptor
> + *
> + * changes the status to the specified value. Doesn't change other bits
> + * in the status
> + */
> +static void gelic_net_set_descr_status(struct gelic_net_descr *descr,
> +				       enum gelic_net_descr_status status)
> +{
> +	u32 cmd_status;
> +
> +	/* read the status */
> +	cmd_status = descr->dmac_cmd_status;
> +	/* clean the upper 4 bits */
> +	cmd_status &= GELIC_NET_DESCR_IND_PROC_MASKO;
> +	/* add the status to it */
> +	cmd_status |= ((u32)status) << GELIC_NET_DESCR_IND_PROC_SHIFT;
> +	/* and write it back */
> +	descr->dmac_cmd_status = cmd_status;
> +	wmb();

does the wmb() actually do anything useful here?


> + * gelic_net_free_chain - free descriptor chain
> + * @card: card structure
> + * @descr_in: address of desc
> + */
> +static void gelic_net_free_chain(struct gelic_net_card *card,
> +				 struct gelic_net_descr *descr_in)
> +{
> +	struct gelic_net_descr *descr;
> +
> +	for (descr = descr_in; descr && descr->bus_addr; descr = descr->next) {
> +		dma_unmap_single(ctodev(card), descr->bus_addr,
> +				 GELIC_NET_DESCR_SIZE, DMA_BIDIRECTIONAL);
> +		descr->bus_addr = 0;
> +	}
> +}
> +
> +/**
> + * gelic_net_init_chain - links descriptor chain
> + * @card: card structure
> + * @chain: address of chain
> + * @start_descr: address of descriptor array
> + * @no: number of descriptors
> + *
> + * we manage a circular list that mirrors the hardware structure,
> + * except that the hardware uses bus addresses.
> + *
> + * returns 0 on success, <0 on failure
> + */
> +static int gelic_net_init_chain(struct gelic_net_card *card,
> +				struct gelic_net_descr_chain *chain,
> +				struct gelic_net_descr *start_descr, int no)
> +{
> +	int i;
> +	struct gelic_net_descr *descr;
> +
> +	descr = start_descr;
> +	memset(descr, 0, sizeof(*descr) * no);
> +
> +	/* set up the hardware pointers in each descriptor */
> +	for (i = 0; i < no; i++, descr++) {
> +		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
> +		descr->bus_addr =
> +			dma_map_single(ctodev(card), descr,
> +				       GELIC_NET_DESCR_SIZE,
> +				       DMA_BIDIRECTIONAL);
> +
> +		if (!descr->bus_addr)
> +			goto iommu_error;
> +
> +		descr->next = descr + 1;
> +		descr->prev = descr - 1;
> +	}
> +	/* make them as ring */
> +	(descr - 1)->next = start_descr;
> +	start_descr->prev = (descr - 1);
> +
> +	/* chain bus addr of hw descriptor */
> +	descr = start_descr;
> +	for (i = 0; i < no; i++, descr++) {
> +		descr->next_descr_addr = descr->next->bus_addr;
> +	}
> +
> +	chain->head = start_descr;
> +	chain->tail = start_descr;
> +
> +	/* do not chain last hw descriptor */
> +	(descr - 1)->next_descr_addr = 0;
> +
> +	return 0;
> +
> +iommu_error:
> +	for (i--, descr--; 0 <= i; i--, descr--)
> +		if (descr->bus_addr)
> +			dma_unmap_single(ctodev(card), descr->bus_addr,
> +					 GELIC_NET_DESCR_SIZE,
> +					 DMA_BIDIRECTIONAL);
> +	return -ENOMEM;
> +}
> +
> +/**
> + * gelic_net_prepare_rx_descr - reinitializes a rx descriptor
> + * @card: card structure
> + * @descr: descriptor to re-init
> + *
> + * return 0 on succes, <0 on failure
> + *
> + * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
> + * Activate the descriptor state-wise
> + */
> +static int gelic_net_prepare_rx_descr(struct gelic_net_card *card,
> +				      struct gelic_net_descr *descr)
> +{
> +	int offset;
> +	unsigned int bufsize;
> +
> +	if (gelic_net_get_descr_status(descr) !=  GELIC_NET_DESCR_NOT_IN_USE) {
> +		dev_info(ctodev(card), "%s: ERROR status \n", __func__);
> +	}
> +	/* we need to round up the buffer size to a multiple of 128 */
> +	bufsize = (GELIC_NET_MAX_MTU + GELIC_NET_RXBUF_ALIGN - 1) &
> +		(~(GELIC_NET_RXBUF_ALIGN - 1));

use ALIGN()?


> +	/* and we need to have it 128 byte aligned, therefore we allocate a
> +	 * bit more */
> +	descr->skb = netdev_alloc_skb(card->netdev,
> +		bufsize + GELIC_NET_RXBUF_ALIGN - 1);

net_device allocation is already rounded.  and combined with the above 
code snippet, it appears you're aligning twice


> +	if (!descr->skb) {
> +		descr->buf_addr = 0; /* tell DMAC don't touch memory */
> +		dev_info(ctodev(card),
> +			 "%s:allocate skb failed !!\n", __func__);
> +		return -ENOMEM;
> +	}
> +	descr->buf_size = bufsize;
> +	descr->dmac_cmd_status = 0;
> +	descr->result_size = 0;
> +	descr->valid_size = 0;
> +	descr->data_error = 0;
> +
> +	offset = ((unsigned long)descr->skb->data) &
> +		(GELIC_NET_RXBUF_ALIGN - 1);
> +	if (offset)
> +		skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
> +	/* io-mmu-map the skb */
> +	descr->buf_addr = dma_map_single(ctodev(card), descr->skb->data,
> +					 GELIC_NET_MAX_MTU,
> +					 DMA_BIDIRECTIONAL);
> +	wmb();
> +	if (!descr->buf_addr) {
> +		dev_kfree_skb_any(descr->skb);
> +		descr->skb = NULL;
> +		dev_info(ctodev(card),
> +			 "%s:Could not iommu-map rx buffer\n", __func__);
> +		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
> +		return -ENOMEM;
> +	} else {
> +		gelic_net_set_descr_status(descr, GELIC_NET_DESCR_CARDOWNED);
> +		return 0;
> +	}
> +}
> +
> +/**
> + * gelic_net_release_rx_chain - free all skb of rx descr
> + * @card: card structure
> + *
> + */
> +static void gelic_net_release_rx_chain(struct gelic_net_card *card)
> +{
> +	struct gelic_net_descr * descr = card->rx_chain.head;
> +
> +	do {
> +		if (descr->skb) {
> +			dma_unmap_single(ctodev(card),
> +					 descr->buf_addr,
> +					 descr->skb->len,
> +					 DMA_BIDIRECTIONAL);
> +			descr->buf_addr = 0;
> +			dev_kfree_skb_any(descr->skb);
> +			descr->skb = NULL;
> +			descr->dmac_cmd_status = GELIC_NET_DESCR_NOT_IN_USE;
> +		}
> +		descr = descr->next;
> +	} while (descr != card->rx_chain.head);
> +}
> +
> +/**
> + * gelic_net_fill_rx_chain - fills descriptors/skbs in the rx chains
> + * @card: card structure
> + *
> + * fills all descriptors in the rx chain: allocates skbs
> + * and iommu-maps them.
> + * returns 0 on success, <0 on failure
> + */
> +static int gelic_net_fill_rx_chain(struct gelic_net_card *card)
> +{
> +	struct gelic_net_descr *descr = card->rx_chain.head;
> +	int ret;
> +
> +	do {
> +		if (!descr->skb)
> +			if ((ret = gelic_net_prepare_rx_descr(card, descr)))
> +				goto rewind;

please avoid combining two C statements into a single line.

	ret = gelic_net_...()
	if (ret)
		goto rewind

is more readable


> +		descr = descr->next;
> +	} while (descr != card->rx_chain.head);
> +
> +	return 0;
> +rewind:
> +	gelic_net_release_rx_chain(card);
> +	return ret;
> +}
> +
> +/**
> + * gelic_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
> + * @card: card structure
> + *
> + * returns 0 on success, <0 on failure
> + */
> +static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card)
> +{
> +	struct gelic_net_descr_chain *chain;
> +	int ret;
> +	chain = &card->rx_chain;
> +	ret = gelic_net_fill_rx_chain(card);
> +	chain->head = card->rx_top->prev; /* point to the last */
> +	return ret;
> +}
> +
> +/**
> + * gelic_net_release_tx_descr - processes a used tx descriptor
> + * @card: card structure
> + * @descr: descriptor to release
> + *
> + * releases a used tx descriptor (unmapping, freeing of skb)
> + */
> +static void gelic_net_release_tx_descr(struct gelic_net_card *card,
> +			    struct gelic_net_descr *descr)
> +{
> +	struct sk_buff *skb;
> +
> +
> +	if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) {
> +		/* 2nd descriptor */
> +		skb = descr->skb;
> +		dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
> +				 DMA_BIDIRECTIONAL);
> +		dev_kfree_skb_any(skb);
> +	} else {
> +		dma_unmap_single(ctodev(card), descr->buf_addr,
> +				 descr->buf_size, DMA_BIDIRECTIONAL);
> +	}
> +
> +	descr->buf_addr = 0;
> +	descr->buf_size = 0;
> +	descr->next_descr_addr = 0;
> +	descr->result_size = 0;
> +	descr->valid_size = 0;
> +	descr->data_status = 0;
> +	descr->data_error = 0;
> +	descr->skb = NULL;
> +
> +	/* set descr status */
> +	descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE;
> +}
> +
> +/**
> + * gelic_net_release_tx_chain - processes sent tx descriptors
> + * @card: adapter structure
> + * @stop: net_stop sequence
> + *
> + * releases the tx descriptors that gelic has finished with
> + */
> +static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop)
> +{
> +	struct gelic_net_descr_chain *tx_chain;
> +	enum gelic_net_descr_status status;
> +	int release = 0;
> +
> +	for (tx_chain = &card->tx_chain;
> +	     tx_chain->head != tx_chain->tail && tx_chain->tail;
> +	     tx_chain->tail = tx_chain->tail->next) {
> +		status = gelic_net_get_descr_status(tx_chain->tail);
> +		switch (status) {
> +		case GELIC_NET_DESCR_RESPONSE_ERROR:
> +		case GELIC_NET_DESCR_PROTECTION_ERROR:
> +		case GELIC_NET_DESCR_FORCE_END:
> +			if (printk_ratelimit())
> +				dev_info(ctodev(card),
> +					 "%s: forcing end of tx descriptor " \
> +					 "with status %x\n",
> +					 __func__, status);
> +			card->netdev_stats.tx_dropped++;
> +			break;
> +
> +		case GELIC_NET_DESCR_COMPLETE:
> +			card->netdev_stats.tx_packets++;
> +			card->netdev_stats.tx_bytes +=
> +				tx_chain->tail->skb->len;
> +			break;
> +
> +		case GELIC_NET_DESCR_CARDOWNED:
> +			/* pending tx request */
> +		default:
> +			/* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */
> +			goto out;
> +		}
> +		gelic_net_release_tx_descr(card, tx_chain->tail);
> +		release = 1;
> +	}
> +out:
> +	if (!stop && release && netif_queue_stopped(card->netdev))
> +		netif_wake_queue(card->netdev);

shouldn't need to test netif_queued_stopped() before calling 
netif_wake_queue(), as netif_wake_queue() essentially already does this



> + * gelic_net_set_multi - sets multicast addresses and promisc flags
> + * @netdev: interface device structure
> + *
> + * gelic_net_set_multi configures multicast addresses as needed for the
> + * netdev interface. It also sets up multicast, allmulti and promisc
> + * flags appropriately
> + */
> +static void gelic_net_set_multi(struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +	struct dev_mc_list *mc;
> +	unsigned int i;
> +	uint8_t *p;
> +	u64 addr;
> +	int status;
> +
> +	/* clear all multicast address */
> +	status = lv1_net_remove_multicast_address(bus_id(card), dev_id(card),
> +						  0, 1);
> +	if (status)
> +		dev_err(ctodev(card),
> +			"lv1_net_remove_multicast_address failed %d\n",
> +			status);
> +	/* set broadcast address */
> +	status = lv1_net_add_multicast_address(bus_id(card), dev_id(card),
> +					       GELIC_NET_BROADCAST_ADDR, 0);
> +	if (status)
> +		dev_err(ctodev(card),
> +			"lv1_net_add_multicast_address failed, %d\n",
> +			status);
> +
> +	if (netdev->flags & IFF_ALLMULTI
> +		|| netdev->mc_count > GELIC_NET_MC_COUNT_MAX) { /* list max */
> +		status = lv1_net_add_multicast_address(bus_id(card), dev_id(card),
> +						       0, 1);
> +		if (status)
> +			dev_err(ctodev(card),
> +				"lv1_net_add_multicast_address failed, %d\n",
> +				status);
> +		return;
> +	}
> +
> +	/* set multicast address */
> +	for (mc = netdev->mc_list; mc; mc = mc->next) {
> +		addr = 0;
> +		p = mc->dmi_addr;
> +		for (i = 0; i < ETH_ALEN; i++) {
> +			addr <<= 8;
> +			addr |= *p++;
> +		}
> +		status = lv1_net_add_multicast_address(bus_id(card), dev_id(card),
> +				addr, 0);
> +		if (status)
> +			dev_err(ctodev(card),
> +				"lv1_net_add_multicast_address failed, %d\n",
> +				status);
> +	}

this seems not to handle the promisc case



> +/**
> + * gelic_net_enable_rxdmac - enables the receive DMA controller
> + * @card: card structure
> + *
> + * gelic_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
> + * in the GDADMACCNTR register
> + */
> +static void gelic_net_enable_rxdmac(struct gelic_net_card *card)
> +{
> +	int status;
> +
> +	status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
> +				card->rx_chain.tail->bus_addr, 0);
> +	if (status)
> +		printk("lv1_net_start_rx_dma failed, status=%d\n", status);
> +}
> +
> +/**
> + * gelic_net_disable_rxdmac - disables the receive DMA controller
> + * @card: card structure
> + *
> + * gelic_net_disable_rxdmac terminates processing on the DMA controller by
> + * turing off DMA and issueing a force end
> + */
> +static void gelic_net_disable_rxdmac(struct gelic_net_card *card)
> +{
> +	int status;
> +
> +	/* this hvc blocks until the DMA in progress really stopped */
> +	status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card), 0);
> +	if (status)
> +		dev_err(ctodev(card),
> +			"lv1_net_stop_rx_dma faild, %d\n", status);
> +}
> +
> +/**
> + * gelic_net_disable_txdmac - disables the transmit DMA controller
> + * @card: card structure
> + *
> + * gelic_net_disable_txdmac terminates processing on the DMA controller by
> + * turing off DMA and issueing a force end
> + */
> +static void gelic_net_disable_txdmac(struct gelic_net_card *card)
> +{
> +	int status;
> +
> +	/* this hvc blocks until the DMA in progress really stopped */
> +	status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0);
> +	if (status)
> +		dev_err(ctodev(card),
> +			"lv1_net_stop_tx_dma faild, status=%d\n", status);
> +}

do we really need all these three-C-statement functions?


> +/**
> + * gelic_net_stop - called upon ifconfig down
> + * @netdev: interface device structure
> + *
> + * always returns 0
> + */
> +static int gelic_net_stop(struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +
> +	netif_poll_disable(netdev);
> +	netif_stop_queue(netdev);
> +
> +	/* turn off DMA, force end */
> +	gelic_net_disable_rxdmac(card);
> +	gelic_net_disable_txdmac(card);
> +
> +	gelic_net_set_irq_mask(card, 0);
> +
> +	/* disconnect event port */
> +	free_irq(card->netdev->irq, card->netdev);
> +	ps3_sb_event_receive_port_destroy(card->dev, card->netdev->irq);
> +	card->netdev->irq = NO_IRQ;
> +
> +	netif_carrier_off(netdev);
> +
> +	/* release chains */
> +	gelic_net_release_tx_chain(card, 1);
> +	gelic_net_release_rx_chain(card);
> +
> +	gelic_net_free_chain(card, card->tx_top);
> +	gelic_net_free_chain(card, card->rx_top);
> +
> +	return 0;
> +}
> +
> +/**
> + * gelic_net_get_next_tx_descr - returns the next available tx descriptor
> + * @card: device structure to get descriptor from
> + *
> + * returns the address of the next descriptor, or NULL if not available.
> + */
> +static struct gelic_net_descr *
> +gelic_net_get_next_tx_descr(struct gelic_net_card *card)
> +{
> +	if (!card->tx_chain.head)
> +		return NULL;
> +	/*  see if we can two consecutive free descrs */
> +	if (card->tx_chain.tail != card->tx_chain.head->next &&
> +	    gelic_net_get_descr_status(card->tx_chain.head) ==
> +	    GELIC_NET_DESCR_NOT_IN_USE &&
> +	    card->tx_chain.tail != card->tx_chain.head->next->next &&
> +	    gelic_net_get_descr_status(card->tx_chain.head->next) ==
> +	     GELIC_NET_DESCR_NOT_IN_USE )
> +		return card->tx_chain.head;
> +	else
> +		return NULL;
> +
> +}
> +
> +/**
> + * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
> + * @descr: descriptor structure to fill out
> + * @skb: packet to consider
> + * @middle: middle of frame
> + *
> + * fills out the command and status field of the descriptor structure,
> + * depending on hardware checksum settings. This function assumes a wmb()
> + * has executed before.
> + */
> +static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
> +					  struct sk_buff *skb, int middle)
> +{
> +	u32 eofr;
> +
> +	if (middle)
> +		eofr = 0;
> +	else
> +		eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME;
> +
> +	if (skb->ip_summed != CHECKSUM_PARTIAL)
> +		descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
> +	else {
> +		/* is packet ip?
> +		 * if yes: tcp? udp? */
> +		if (skb->protocol == htons(ETH_P_IP)) {
> +			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
> +				descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr;
> +			else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
> +				descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr;
> +			else	/*
> +				 * the stack should checksum non-tcp and non-udp
> +				 * packets on his own: NETIF_F_IP_CSUM
> +				 */
> +				descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
> +		}
> +	}
> +}
> +
> +/**
> + * gelic_net_prepare_tx_descr_v - get dma address of skb_data
> + * @card: card structure
> + * @descr: descriptor structure
> + * @skb: packet to use
> + *
> + * returns 0 on success, <0 on failure.
> + *
> + */
> +static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
> +					struct gelic_net_descr *descr,
> +					struct sk_buff *skb)
> +{
> +	dma_addr_t buf[2];
> +	unsigned int vlan_len;
> +
> +	if (skb->len < GELIC_NET_VLAN_POS)
> +		return -EINVAL;
> +
> +	memcpy(&descr->vlan, skb->data, GELIC_NET_VLAN_POS);
> +	if (card->vlan_index != -1) {
> +		descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
> +		descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
> +		vlan_len = GELIC_NET_VLAN_POS + VLAN_HLEN; /* VLAN_HLEN=4 */
> +	} else
> +		vlan_len = GELIC_NET_VLAN_POS; /* no vlan tag */
> +
> +	/* first descr */
> +	buf[0] = dma_map_single(ctodev(card), &descr->vlan,
> +			     vlan_len, DMA_BIDIRECTIONAL);
> +
> +	if (!buf[0]) {
> +		dev_err(ctodev(card),
> +			"dma map 1 failed (%p, %i). Dropping packet\n",
> +			skb->data, vlan_len);
> +		return -ENOMEM;
> +	}
> +
> +	descr->buf_addr = buf[0];
> +	descr->buf_size = vlan_len;
> +	descr->skb = skb; /* not used */
> +	descr->data_status = 0;
> +	gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
> +
> +	/* second descr */
> +	card->tx_chain.head = card->tx_chain.head->next;
> +	descr->next_descr_addr = descr->next->bus_addr;
> +	descr = descr->next;
> +	if (gelic_net_get_descr_status(descr) != GELIC_NET_DESCR_NOT_IN_USE)
> +		dev_err(ctodev(card),"descr is not free!\n"); /* XXX will be removed */
> +
> +	buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
> +			     skb->len - GELIC_NET_VLAN_POS,
> +			     DMA_BIDIRECTIONAL);
> +
> +	if (!buf[1]) {
> +		dev_err(ctodev(card),
> +			"dma map 2 failed (%p, %i). Dropping packet\n",
> +			skb->data + GELIC_NET_VLAN_POS,
> +			skb->len - GELIC_NET_VLAN_POS);
> +		dma_unmap_single(ctodev(card), buf[0], vlan_len,
> +				 DMA_BIDIRECTIONAL);
> +		return -ENOMEM;
> +	}
> +
> +	descr->buf_addr = buf[1];
> +	descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
> +	descr->skb = skb;
> +	descr->data_status = 0;
> +	descr->next_descr_addr= 0; /* terminate hw descr */
> +	gelic_net_set_txdescr_cmdstat(descr,skb, 0);
> +
> +	return 0;
> +}
> +
> +/**
> + * gelic_net_kick_txdma - enables TX DMA processing
> + * @card: card structure
> + * @descr: descriptor address to enable TX processing at
> + *
> + */
> +static int gelic_net_kick_txdma(struct gelic_net_card *card,
> +				struct gelic_net_descr *descr)
> +{
> +	int status = -ENXIO;
> +	int count = 10;
> +
> +	if (card->tx_dma_progress)
> +		return 0;
> +
> +	if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) {
> +		card->tx_dma_progress = 1;
> +		/* sometimes we need retry here */
> +		while (count--) {
> +			status = lv1_net_start_tx_dma(bus_id(card),
> +						      dev_id(card),
> +						      descr->bus_addr, 0);
> +			if (!status)
> +				break;
> +		}
> +		if (!count)
> +			dev_info(ctodev(card), "lv1_net_start_txdma failed," \
> +				"status=%d %#lx\n",
> +				 status, card->irq_status);
> +	}
> +	return status;
> +}
> +
> +/**
> + * gelic_net_xmit - transmits a frame over the device
> + * @skb: packet to send out
> + * @netdev: interface device structure
> + *
> + * returns 0 on success, <0 on failure
> + */
> +static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +	struct gelic_net_descr *descr = NULL;
> +	int result;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&card->tx_dma_lock, flags);
> +
> +	gelic_net_release_tx_chain(card, 0);
> +	if (!skb)
> +		goto kick;

skb will never be NULL here


> +	descr = gelic_net_get_next_tx_descr(card);
> +	if (!descr) {
> +		netif_stop_queue(netdev);
> +		spin_unlock_irqrestore(&card->tx_dma_lock, flags);
> +		return NETDEV_TX_BUSY;
> +	}
> +	result = gelic_net_prepare_tx_descr_v(card, descr, skb);
> +
> +	if (result)
> +		goto error;
> +
> +	card->tx_chain.head = card->tx_chain.head->next;
> +
> +	if (descr->prev)
> +		descr->prev->next_descr_addr = descr->bus_addr;
> +kick:
> +	wmb();
> +	if (gelic_net_kick_txdma(card, card->tx_chain.tail))
> +		goto error;
> +
> +	netdev->trans_start = jiffies;
> +	spin_unlock_irqrestore(&card->tx_dma_lock, flags);
> +	return NETDEV_TX_OK;
> +
> +error:
> +	card->netdev_stats.tx_dropped++;
> +	spin_unlock_irqrestore(&card->tx_dma_lock, flags);
> +	return NETDEV_TX_LOCKED;
> +}
> +
> +/**
> + * gelic_net_pass_skb_up - takes an skb from a descriptor and passes it on
> + * @descr: descriptor to process
> + * @card: card structure
> + *
> + * iommu-unmaps the skb, fills out skb structure and passes the data to the
> + * stack. The descriptor state is not changed.
> + */
> +static void gelic_net_pass_skb_up(struct gelic_net_descr *descr,
> +				 struct gelic_net_card *card)
> +{
> +	struct sk_buff *skb;
> +	struct net_device *netdev;
> +	u32 data_status, data_error;
> +
> +	data_status = descr->data_status;
> +	data_error = descr->data_error;
> +	netdev = card->netdev;
> +	/* unmap skb buffer */
> +	skb = descr->skb;
> +	dma_unmap_single(ctodev(card), descr->buf_addr, GELIC_NET_MAX_MTU,
> +			 DMA_BIDIRECTIONAL);

why BIDIRECTIONAL?


> +	skb->dev = netdev;

shouldn't be needed anymore with netdev_alloc_skb()


> +	skb_put(skb, descr->valid_size? descr->valid_size : descr->result_size);
> +	if (!descr->valid_size)
> +		dev_info(ctodev(card), "buffer full %x %x %x\n",
> +			 descr->result_size, descr->buf_size, descr->dmac_cmd_status);
> +
> +	descr->skb = NULL;
> +	/*
> +	 * the card put 2 bytes vlan tag in front
> +	 * of the ethernet frame
> +	 */
> +	skb_pull(skb, 2);
> +	skb->protocol = eth_type_trans(skb, netdev);
> +
> +	/* checksum offload */
> +	if (card->rx_csum) {
> +		if ((data_status & GELIC_NET_DATA_STATUS_CHK_MASK) &&
> +		    (!(data_error & GELIC_NET_DATA_ERROR_CHK_MASK)))
> +			skb->ip_summed = CHECKSUM_UNNECESSARY;
> +		else
> +			skb->ip_summed = CHECKSUM_NONE;
> +	} else
> +		skb->ip_summed = CHECKSUM_NONE;
> +
> +	/* update netdevice statistics */
> +	card->netdev_stats.rx_packets++;
> +	card->netdev_stats.rx_bytes += skb->len;
> +
> +	/* pass skb up to stack */
> +	netif_receive_skb(skb);
> +}
> +
> +/**
> + * gelic_net_decode_one_descr - processes an rx descriptor
> + * @card: card structure
> + *
> + * returns 1 if a packet has been sent to the stack, otherwise 0
> + *
> + * processes an rx descriptor by iommu-unmapping the data buffer and passing
> + * the packet up to the stack
> + */
> +static int gelic_net_decode_one_descr(struct gelic_net_card *card)
> +{
> +	enum gelic_net_descr_status status;
> +	struct gelic_net_descr_chain *chain = &card->rx_chain;
> +	struct gelic_net_descr *descr = chain->tail;
> +	int dmac_chain_ended;
> +
> +	status = gelic_net_get_descr_status(descr);
> +	/* is this descriptor terminated with next_descr == NULL? */
> +	dmac_chain_ended = descr->dmac_cmd_status & GELIC_NET_DMAC_CMDSTAT_RXDCEIS;
> +
> +	if (status == GELIC_NET_DESCR_CARDOWNED) {
> +		return 0;
> +	}

remove all braces around single-line C statements


> +	if (status == GELIC_NET_DESCR_NOT_IN_USE) {
> +		dev_dbg(ctodev(card), "dormant descr? %p\n", descr);
> +		return 0;
> +	}
> +
> +	if ((status == GELIC_NET_DESCR_RESPONSE_ERROR) ||
> +	    (status == GELIC_NET_DESCR_PROTECTION_ERROR) ||
> +	    (status == GELIC_NET_DESCR_FORCE_END)) {
> +		dev_info(ctodev(card), "dropping RX descriptor with state %x\n",
> +			 status);
> +		card->netdev_stats.rx_dropped++;
> +		goto refill;
> +	}
> +
> +	if ((status != GELIC_NET_DESCR_COMPLETE) &&
> +	    (status != GELIC_NET_DESCR_FRAME_END)) {
> +		dev_dbg(ctodev(card), "RX descriptor with state %x\n",
> +			status);
> +		goto refill;
> +	}
> +
> +	/* ok, we've got a packet in descr */
> +	gelic_net_pass_skb_up(descr, card); /* 1: skb_up sccess */
> +
> +refill:
> +	descr->next_descr_addr = 0; /* unlink the descr */
> +
> +	/* change the descriptor state: */
> +	gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
> +
> +	/* refill one desc
> +	 * FIXME: this can fail, but for now, just leave this
> +	 * descriptor without skb
> +	 */
> +	gelic_net_prepare_rx_descr(card, descr);
> +	chain->head = descr;
> +	chain->tail = descr->next;
> +	descr->prev->next_descr_addr = descr->bus_addr;
> +
> +	if (dmac_chain_ended) {
> +		gelic_net_enable_rxdmac(card);
> +		dev_dbg(ctodev(card), "reenable rx dma\n");
> +	}
> +
> +	return 1;
> +}
> +
> +/**
> + * gelic_net_poll - NAPI poll function called by the stack to return packets
> + * @netdev: interface device structure
> + * @budget: number of packets we can pass to the stack at most
> + *
> + * returns 0 if no more packets available to the driver/stack. Returns 1,
> + * if the quota is exceeded, but the driver has still packets.
> + *
> + */
> +static int gelic_net_poll(struct net_device *netdev, int *budget)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +	int packets_to_do, packets_done = 0;
> +	int no_more_packets = 0;
> +
> +	packets_to_do = min(*budget, netdev->quota);
> +
> +	while (packets_to_do) {
> +		if (gelic_net_decode_one_descr(card)) {
> +			packets_done++;
> +			packets_to_do--;
> +		} else {
> +			/* no more packets for the stack */
> +			no_more_packets = 1;
> +			break;
> +		}
> +	}
> +	netdev->quota -= packets_done;
> +	*budget -= packets_done;
> +	if (no_more_packets) {
> +		netif_rx_complete(netdev);
> +		gelic_net_rx_irq_on(card);
> +		return 0;
> +	} else
> +		return 1;
> +}
> +
> +/**
> + * gelic_net_get_stats - get interface statistics
> + * @netdev: interface device structure
> + *
> + * returns the interface statistics residing in the gelic_net_card struct
> + */
> +static struct net_device_stats * gelic_net_get_stats(struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +
> +	return &card->netdev_stats;
> +}
> +
> +/**
> + * gelic_net_change_mtu - changes the MTU of an interface
> + * @netdev: interface device structure
> + * @new_mtu: new MTU value
> + *
> + * returns 0 on success, <0 on failure
> + */
> +static int gelic_net_change_mtu(struct net_device *netdev, int new_mtu)
> +{
> +	/* no need to re-alloc skbs or so -- the max mtu is about 2.3k
> +	 * and mtu is outbound only anyway */
> +	if ((new_mtu < GELIC_NET_MIN_MTU) ||
> +	    (new_mtu > GELIC_NET_MAX_MTU)) {
> +		return -EINVAL;
> +	}
> +	netdev->mtu = new_mtu;

no RX filter to change?


> +/**
> + * gelic_net_interrupt - event handler for gelic_net
> + */
> +static irqreturn_t gelic_net_interrupt(int irq, void *ptr)
> +{
> +	unsigned long flags;
> +	struct net_device *netdev = ptr;
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +	u64 status;
> +
> +	status = card->irq_status;
> +
> +	if (!status)
> +		return IRQ_NONE;
> +
> +	if (status & GELIC_NET_RXINT) {
> +		gelic_net_rx_irq_off(card);
> +		netif_rx_schedule(netdev);
> +	}
> +
> +	if (status & GELIC_NET_TXINT) {
> +		spin_lock_irqsave(&card->tx_dma_lock, flags);
> +		card->tx_dma_progress = 0;
> +		spin_unlock_irqrestore(&card->tx_dma_lock, flags);
> +		/* start pending DMA */
> +		gelic_net_xmit(NULL, netdev);
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> +/**
> + * gelic_net_poll_controller - artificial interrupt for netconsole etc.
> + * @netdev: interface device structure
> + *
> + * see Documentation/networking/netconsole.txt
> + */
> +static void gelic_net_poll_controller(struct net_device *netdev)
> +{
> +	struct gelic_net_card *card = netdev_priv(netdev);
> +
> +	gelic_net_set_irq_mask(card, 0);
> +	gelic_net_interrupt(netdev->irq, netdev);
> +	gelic_net_set_irq_mask(card, card->ghiintmask);
> +}
> +#endif /* CONFIG_NET_POLL_CONTROLLER */
> +
> +/**
> + * gelic_net_open_device - open device and map dma region
> + * @card: card structure
> + */
> +static int gelic_net_open_device(struct gelic_net_card *card)
> +{
> +	int result;
> +
> +	result = ps3_sb_event_receive_port_setup(card->dev, PS3_BINDING_CPU_ANY,
> +		&card->netdev->irq);
> +
> +	if (result) {
> +		dev_info(ctodev(card),
> +			 "%s:%d: gelic_net_open_device failed (%d)\n",
> +			 __func__, __LINE__, result);
> +		result = -EPERM;
> +		goto fail_alloc_irq;
> +	}
> +
> +	result = request_irq(card->netdev->irq, gelic_net_interrupt, IRQF_DISABLED,
> +		"gelic network", card->netdev);
> +
> +	if (result) {
> +		dev_info(ctodev(card), "%s:%d: request_irq failed (%d)\n",
> +			__func__, __LINE__, result);
> +		goto fail_request_irq;
> +	}
> +
> +	return 0;
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ