* Re: [PATCH 1/9] NetXen 1G/10G ethernet driver patch with corrections
From: Pradeep Dalvi @ 2006-06-08 14:55 UTC (permalink / raw)
To: Andi Kleen
Cc: Linsys Contractor Amit S. Kale, Kernel Netdev Mailing List,
Sanjeev Jorapur, UNM Project Staff
In-Reply-To: <200606071149.51879.ak@suse.de>
diff -u linux-2.6.16.20/drivers/net/netxen/netxen_nic_ethtool.c
linux-2.6.16.20/drivers/net/netxen/netxen_nic_ethtool.c
--- linux-2.6.16.20/drivers/net/netxen/netxen_nic_ethtool.c 2006-06-06
06:58:11.000000000 -0700
+++ linux-2.6.16.20/drivers/net/netxen/netxen_nic_ethtool.c 2006-06-08
06:52:09.000000000 -0700
@@ -240,6 +240,95 @@
return NETXEN_NIC_REGS_LEN;
}
+struct netxen_niu_regs {
+ netxen_crbword_t reg[NETXEN_NIC_REGS_COUNT];
+};
+
+static struct netxen_niu_regs niu_registers[] = {
+ {
+ /* GB Mode */
+ {
+ NETXEN_NIU_GB_SERDES_RESET,
+ NETXEN_NIU_GB0_MII_MODE,
+ NETXEN_NIU_GB1_MII_MODE,
+ NETXEN_NIU_GB2_MII_MODE,
+ NETXEN_NIU_GB3_MII_MODE,
+ NETXEN_NIU_GB0_GMII_MODE,
+ NETXEN_NIU_GB1_GMII_MODE,
+ NETXEN_NIU_GB2_GMII_MODE,
+ NETXEN_NIU_GB3_GMII_MODE,
+ NETXEN_NIU_REMOTE_LOOPBACK,
+ NETXEN_NIU_GB0_HALF_DUPLEX,
+ NETXEN_NIU_GB1_HALF_DUPLEX,
+ NETXEN_NIU_RESET_SYS_FIFOS,
+ NETXEN_NIU_GB_CRC_DROP,
+ NETXEN_NIU_GB_DROP_WRONGADDR,
+ NETXEN_NIU_TEST_MUX_CTL,
+
+ NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ NETXEN_NIU_GB_MAC_CONFIG_1(0),
+ NETXEN_NIU_GB_HALF_DUPLEX_CTRL(0),
+ NETXEN_NIU_GB_MAX_FRAME_SIZE(0),
+ NETXEN_NIU_GB_TEST_REG(0),
+ NETXEN_NIU_GB_MII_MGMT_CONFIG(0),
+ NETXEN_NIU_GB_MII_MGMT_COMMAND(0),
+ NETXEN_NIU_GB_MII_MGMT_ADDR(0),
+ NETXEN_NIU_GB_MII_MGMT_CTRL(0),
+ NETXEN_NIU_GB_MII_MGMT_STATUS(0),
+ NETXEN_NIU_GB_MII_MGMT_INDICATE(0),
+ NETXEN_NIU_GB_INTERFACE_CTRL(0),
+ NETXEN_NIU_GB_INTERFACE_STATUS(0),
+ NETXEN_NIU_GB_STATION_ADDR_0(0),
+ NETXEN_NIU_GB_STATION_ADDR_1(0),
+ -1,
+ }
+ },
+ {
+ /* XG Mode */
+ {
+ NETXEN_NIU_XG_SINGLE_TERM,
+ NETXEN_NIU_XG_DRIVE_HI,
+ NETXEN_NIU_XG_DRIVE_LO,
+ NETXEN_NIU_XG_DTX,
+ NETXEN_NIU_XG_DEQ,
+ NETXEN_NIU_XG_WORD_ALIGN,
+ NETXEN_NIU_XG_RESET,
+ NETXEN_NIU_XG_POWER_DOWN,
+ NETXEN_NIU_XG_RESET_PLL,
+ NETXEN_NIU_XG_SERDES_LOOPBACK,
+ NETXEN_NIU_XG_DO_BYTE_ALIGN,
+ NETXEN_NIU_XG_TX_ENABLE,
+ NETXEN_NIU_XG_RX_ENABLE,
+ NETXEN_NIU_XG_STATUS,
+ NETXEN_NIU_XG_PAUSE_THRESHOLD,
+ NETXEN_NIU_XGE_CONFIG_0,
+ NETXEN_NIU_XGE_CONFIG_1,
+ NETXEN_NIU_XGE_IPG,
+ NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+ NETXEN_NIU_XGE_STATION_ADDR_0_1,
+ NETXEN_NIU_XGE_STATION_ADDR_1_LO,
+ NETXEN_NIU_XGE_STATUS,
+ NETXEN_NIU_XGE_MAX_FRAME_SIZE,
+ NETXEN_NIU_XGE_PAUSE_FRAME_VALUE,
+ NETXEN_NIU_XGE_TX_BYTE_CNT,
+ NETXEN_NIU_XGE_TX_FRAME_CNT,
+ NETXEN_NIU_XGE_RX_BYTE_CNT,
+ NETXEN_NIU_XGE_RX_FRAME_CNT,
+ NETXEN_NIU_XGE_AGGR_ERROR_CNT,
+ NETXEN_NIU_XGE_MULTICAST_FRAME_CNT,
+ NETXEN_NIU_XGE_UNICAST_FRAME_CNT,
+ NETXEN_NIU_XGE_CRC_ERROR_CNT,
+ NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR,
+ NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR,
+ NETXEN_NIU_XGE_LOCAL_ERROR_CNT,
+ NETXEN_NIU_XGE_REMOTE_ERROR_CNT,
+ NETXEN_NIU_XGE_CONTROL_CHAR_CNT,
+ NETXEN_NIU_XGE_PAUSE_FRAME_CNT,
+ -1,
+ }
+ }
+};
+
static void
netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *p)
{
@@ -248,6 +337,7 @@
netxen_crbword_t mode, *regs_buff = p;
unsigned long flags;
void *addr;
+ int i, window;
memset(p, 0, NETXEN_NIC_REGS_LEN);
regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
@@ -260,176 +350,18 @@
/* Common registers to all the modes */
NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_STRAP_VALUE_SAVE_HIGHER,
®s_buff[2]);
- switch (mode) {
- case 4:{ /* XGB Mode */
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_SINGLE_TERM,
- ®s_buff[3]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_DRIVE_HI,
- ®s_buff[4]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_DRIVE_LO,
- ®s_buff[5]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_DTX,
- ®s_buff[6]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_DEQ,
- ®s_buff[7]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_WORD_ALIGN,
- ®s_buff[8]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_RESET,
- ®s_buff[9]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_POWER_DOWN,
- ®s_buff[10]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_RESET_PLL,
- ®s_buff[11]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XG_SERDES_LOOPBACK, ®s_buff[12]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_DO_BYTE_ALIGN,
- ®s_buff[13]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_TX_ENABLE,
- ®s_buff[14]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_RX_ENABLE,
- ®s_buff[15]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_STATUS,
- ®s_buff[16]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XG_PAUSE_THRESHOLD, ®s_buff[17]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CONFIG_0,
- ®s_buff[18]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CONFIG_1,
- ®s_buff[19]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_IPG,
- ®s_buff[20]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_STATION_ADDR_0_HI, ®s_buff[21]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_STATION_ADDR_0_1, ®s_buff[22]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_STATION_ADDR_1_LO, ®s_buff[23]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_STATUS,
- ®s_buff[24]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_MAX_FRAME_SIZE, ®s_buff[25]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_PAUSE_FRAME_VALUE, ®s_buff[26]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_BYTE_CNT,
- ®s_buff[27]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_TX_FRAME_CNT,
- ®s_buff[28]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_BYTE_CNT,
- ®s_buff[29]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_RX_FRAME_CNT,
- ®s_buff[30]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_AGGR_ERROR_CNT, ®s_buff[31]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_MULTICAST_FRAME_CNT,
- ®s_buff[32]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_UNICAST_FRAME_CNT, ®s_buff[33]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XGE_CRC_ERROR_CNT,
- ®s_buff[34]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_OVERSIZE_FRAME_ERR, ®s_buff[35]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_UNDERSIZE_FRAME_ERR,
- ®s_buff[36]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_LOCAL_ERROR_CNT, ®s_buff[37]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_REMOTE_ERROR_CNT, ®s_buff[38]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_CONTROL_CHAR_CNT, ®s_buff[39]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_XGE_PAUSE_FRAME_CNT, ®s_buff[40]);
- break;
- }
+ /* GB/XGB Mode */
+ mode = (mode/2) - 1;
+ window = 0;
+ if(mode <= 1) {
+ for ( i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
+ /* GB: port specific registers */
+ if(mode == 0 && i >= 19)
+ window = port->portnum * 0x10000;
- case 2:{ /* GB Mode */
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_SERDES_RESET,
- ®s_buff[3]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB0_MII_MODE,
- ®s_buff[4]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB1_MII_MODE,
- ®s_buff[5]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB2_MII_MODE,
- ®s_buff[6]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB3_MII_MODE,
- ®s_buff[7]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB0_GMII_MODE,
- ®s_buff[8]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB1_GMII_MODE,
- ®s_buff[9]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB2_GMII_MODE,
- ®s_buff[10]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB3_GMII_MODE,
- ®s_buff[11]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_REMOTE_LOOPBACK,
- ®s_buff[12]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB0_HALF_DUPLEX,
- ®s_buff[13]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB1_HALF_DUPLEX,
- ®s_buff[14]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_RESET_SYS_FIFOS,
- ®s_buff[15]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_CRC_DROP,
- ®s_buff[16]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_DROP_WRONGADDR,
- ®s_buff[17]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_TEST_MUX_CTL,
- ®s_buff[18]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MAC_CONFIG_0
- (port->portnum),
- ®s_buff[19]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MAC_CONFIG_1
- (port->portnum),
- ®s_buff[20]);
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_GB_HALF_DUPLEX_CTRL(port->portnum),
- ®s_buff[21]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MAX_FRAME_SIZE
- (port->portnum),
- ®s_buff[22]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_TEST_REG
- (port->portnum),
- ®s_buff[23]);
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MII_MGMT_CONFIG
- (port->portnum),
- ®s_buff[24]);
NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_GB_MII_MGMT_COMMAND(port->portnum),
- ®s_buff[25]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MII_MGMT_ADDR
- (port->portnum),
- ®s_buff[26]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MII_MGMT_CTRL
- (port->portnum),
- ®s_buff[27]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_MII_MGMT_STATUS
- (port->portnum),
- ®s_buff[28]);
-
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_GB_MII_MGMT_INDICATE(port->portnum),
- ®s_buff[29]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_INTERFACE_CTRL
- (port->portnum),
- ®s_buff[30]);
-
- NETXEN_NIC_LOCKED_READ_REG
- (NETXEN_NIU_GB_INTERFACE_STATUS(port->portnum),
- ®s_buff[31]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_STATION_ADDR_0
- (port->portnum),
- ®s_buff[32]);
-
- NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_GB_STATION_ADDR_1
- (port->portnum),
- ®s_buff[33]);
- break;
+ (niu_registers[mode].reg[i - 3] + window,
+ ®s_buff[i]);
}
}
write_unlock_irqrestore(&adapter->adapter_lock, flags);
On Wed, 2006-06-07 at 11:49 +0200, Andi Kleen wrote:
> On Wednesday 07 June 2006 11:39, Linsys Contractor Amit S. Kale wrote:
>
> > + switch (mode) {
>
> ... You could save a lot of code by using a table and a loop over the registers.
>
>
> > + case 4:{ /* XGB Mode */
> > + NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_XG_SINGLE_TERM,
> > + ®s_buff[3]);
>
>
> -Andi
>
>
--
pradeep
^ permalink raw reply
* Re: [PATCH 2/2] PHYLIB/gianfar: Use phy_ethtool_get_link() for get_link op
From: Jeff Garzik @ 2006-06-08 14:58 UTC (permalink / raw)
To: Nathaniel Case; +Cc: Andy Fleming, netdev, galak
In-Reply-To: <1149551334.10700.48.camel@localhost.localdomain>
Nathaniel Case wrote:
> This patch makes the gianfar ethtool code use phy_ethtool_get_link() instead of
> ethtool_op_get_link().
>
> Patch depends on previous one (1/2).
>
> Signed-off-by: Nate Case <ncase@xes-inc.com>
>
> ---
>
> --- a/drivers/net/gianfar_ethtool.c 2006-06-05 11:27:19.000000000 -0500
> +++ b/drivers/net/gianfar_ethtool.c 2006-06-04 19:31:01.000000000 -0500
> @@ -228,6 +228,18 @@
> buf[i] = gfar_read(&theregs[i]);
> }
>
> +static u32 gfar_get_link(struct net_device *dev)
> +{
> + struct gfar_private *priv = netdev_priv(dev);
> + struct phy_device *phydev = priv->phydev;
> +
> + if (NULL == phydev)
> + return -ENODEV;
NAK, return code obviously wrong
^ permalink raw reply
* Re: EHEA: Is there a size limit below 80K for patches?
From: Jeff Garzik @ 2006-06-08 14:48 UTC (permalink / raw)
To: Christoph Raisch
Cc: Heiko J Schick, Jan-Bernd Themann, Marcus Eder, netdev, ossthema,
Thomas OS Klein
In-Reply-To: <OF56CA8BB9.67AC7182-ONC1257187.003F6F35-C1257187.00430AFF@de.ibm.com>
Christoph Raisch wrote:
> well, now I'm confused...
> 2 People, two opinions....
>
>
> Here's a URL for a complete tarball, "sharing" the download location with
> our other driver.
> http://prdownloads.sourceforge.net/ibmehcad/ehea_EHEA_0002.tgz
>
> We're waiting for a sourceforge project now since 9 days to put out a tgz,
> and it looks like many other people get upset right now by their response
> time.
>
> So what's the "right"/preferred way to proceed?
Patches and new drivers should always go to the mailing list......
except for the case where they are too big to be posted to the mailing
list. For that special case, a URL to a patch should be posted.
Jeff
^ permalink raw reply
* PATCH to correct dump of WPA IE
From: Larry Finger @ 2006-06-08 14:47 UTC (permalink / raw)
To: netdev, John Linville
In net/ieee80211/softmac/ieee80211softmac_wx.c, there is a bug that prints extended sign information
whenever the byte value exceeds 0x7f. The following patch changes the printk to use a u8 cast to
limit the output to 2 digits. This bug was first noticed by Dan Williams <dcbw@redhat.com>. This
patch applies to the current master branch of the Linville tree.
Signed-Off-By: Larry Finger <Larry.Finger@lwfinger.net>
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 27edb2b..55c5c26 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -388,7 +388,7 @@ ieee80211softmac_wx_set_genie(struct net
memcpy(mac->wpa.IE, extra, wrqu->data.length);
dprintk(KERN_INFO PFX "generic IE set to ");
for (i=0;i<wrqu->data.length;i++)
- dprintk("%.2x", mac->wpa.IE[i]);
+ dprintk("%.2x", (u8)mac->wpa.IE[i]);
dprintk("\n");
mac->wpa.IElen = wrqu->data.length;
} else {
^ permalink raw reply related
* Re: PATCH 2.6.17-rc5 tulip free_irq() called too late
From: Jeff Garzik @ 2006-06-08 14:43 UTC (permalink / raw)
To: Grant Grundler, Andrew Morton; +Cc: netdev, Val Henson
In-Reply-To: <20060531195234.GA4967@colo.lackof.org>
(CC'ing our newly minted tulip maintainer, Val)
Grant Grundler wrote:
> Jeff,
> SLES10 testing exposed an MCA that was confirmed to be a DMA IO TLB miss.
> This means tulip device was attempting to DMA to memory that was already
> unmapped. The test was crashing in the "ifconfig down" step when a 4-port
> tulip card was under this work load:
>
> while :
> do
> ifconfig eth24 up
> ifconfig eth25 up
> ifconfig eth26 up
> ifconfig eth27 up
> # Pound both interfaces with ethtool
> for i in `seq 1000`
> do
> ethtool eth24 &>/dev/null
> ethtool eth25 &>/dev/null
> ethtool eth26 &>/dev/null
> ethtool eth27 &>/dev/null
> done
>
> # Bring interfaces down
> echo ifconfig $nic1 down
> ifconfig eth24 down
> ifconfig eth25 down
> ifconfig eth26 down
> ifconfig eth27 down
>
> sleep 5
> done
>
>
> [ And yes, I know tulip doesn't support ethtool. Don't ask.
> It's still a sore point at the moment. Just consider it
> a delay loop or use "sleep 5" instead. ]
>
> The real "network load" comes from another box(en) running 4 instances
> of "ping -f -s 1450 192.168.x.y" where "x.y" is the subnet/IP of eth24-27.
> The parisc and ia64 machines will crash in minutes.
>
> I believe the problem is a race condition between an interrupt coming
> in and the tulip_down() code path. Moving the "free_irq()" to before
> tulip_down() call fixes the problem. I've been able to run the above
> test for several hours now.
NAK. This is a band-aid, and one that creates new problems even as it
attempts to solve problems.
Calling free_irq() while the chip is still active is just a bad idea,
because the chip could raise an interrupt, creating a
screaming-interrupts situation. Consider especially the case of shared
interrupts here, as a concrete example of how this won't work.
Perhaps cp_close() in 8139cp.c could be an example of a good ordering?
It stops the chip, syncs irqs, frees irq, then frees [thus unmapping]
the rings.
Jeff
^ permalink raw reply
* Re: [PATCH 2.6.17-rc6-mm1 ] net: RFC 3828-compliant UDP-Lite support
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-06-08 14:38 UTC (permalink / raw)
To: alan
Cc: gerrit, davem, kuznet, pekkas, jmorris, kaber, linux-kernel,
netdev, yoshfuji
In-Reply-To: <1149778072.22124.6.camel@localhost.localdomain>
In article <1149778072.22124.6.camel@localhost.localdomain> (at Thu, 08 Jun 2006 15:47:52 +0100), Alan Cox <alan@lxorguk.ukuu.org.uk> says:
> Ar Iau, 2006-06-08 am 11:50 +0100, ysgrifennodd Gerrit Renker:
> > + UDP-Lite introduces a new socket type, the SOCK_LDGRAM (note the L) for
> > + lightweight, connection-less services. These are the socket options:
:
> s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);
>
> is probably the right way to do this, keeping 0 "default" as before
> meaning IPPROTO_UDP
I do think so, too.
--yoshfuji
^ permalink raw reply
* Re: [PATCH 2.6.17-rc6-mm1 ] net: RFC 3828-compliant UDP-Lite support
From: Alan Cox @ 2006-06-08 14:47 UTC (permalink / raw)
To: Gerrit Renker
Cc: davem, kuznet, pekkas, jmorris, yoshfuji, kaber, linux-kernel,
netdev
In-Reply-To: <200606081150.34018@this-message-has-been-logged>
Ar Iau, 2006-06-08 am 11:50 +0100, ysgrifennodd Gerrit Renker:
> + UDP-Lite introduces a new socket type, the SOCK_LDGRAM (note the L) for
> + lightweight, connection-less services. These are the socket options:
This is not the intended use of the socket API when distinguishing
between services. The socket() call has a protocol field that is usually
unused and it exists precisely to disambiguate multiple protocols with
the same generic behaviour but different properties.
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);
is probably the right way to do this, keeping 0 "default" as before
meaning IPPROTO_UDP
^ permalink raw reply
* [PATCH] myri10ge update
From: Brice Goglin @ 2006-06-08 14:25 UTC (permalink / raw)
To: netdev; +Cc: akpm
The following patch updates the myri10ge to 1.0.0, with the following changes:
* Switch to dma_alloc_coherent API.
* Avoid PCI burst when writing the firmware on chipset with unaligned completions.
* Use ethtool_op_set_tx_hw_csum instead of ethtool_op_set_tx_csum.
* Include linux/dma-mapping.h to bring DMA_32/64BIT_MASK on all architectures
(was missing at least on alpha).
* Some typo and warning fixes.
Please apply.
Note that Andrew's myri10ge-alpha-build-fix.patch would conflict,
but it does not seem to have been merged in netdev-2.6 anyway.
Thanks.
Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Andrew J. Gallatin <gallatin@myri.com>
drivers/net/myri10ge/myri10ge.c | 57 +++++++++++++++++++-----------
1 file changed, 37 insertions(+), 20 deletions(-)
diff -urNp linux-mm.old/drivers/net/myri10ge/myri10ge.c linux-mm/drivers/net/myri10ge/myri10ge.c
--- linux-mm.old/drivers/net/myri10ge/myri10ge.c 2006-06-04 08:51:00.000000000 -0400
+++ linux-mm/drivers/net/myri10ge/myri10ge.c 2006-06-07 11:28:20.000000000 -0400
@@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
@@ -62,7 +63,6 @@
#include <net/checksum.h>
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/pci.h>
#include <asm/processor.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
@@ -71,7 +71,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "0.9.0"
+#define MYRI10GE_VERSION_STR "1.0.0"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -480,7 +478,19 @@ static int myri10ge_load_hotplug_firmwar
goto abort_with_fw;
crc = crc32(~0, fw->data, fw->size);
- memcpy_toio(mgp->sram + MYRI10GE_FW_OFFSET, fw->data, fw->size);
+ if (mgp->tx.boundary == 2048) {
+ /* Avoid PCI burst on chipset with unaligned completions. */
+ int i;
+ __iomem u32 *ptr = (__iomem u32 *) (mgp->sram +
+ MYRI10GE_FW_OFFSET);
+ for (i = 0; i < fw->size / 4; i++) {
+ __raw_writel(((u32 *) fw->data)[i], ptr + i);
+ wmb();
+ }
+ } else {
+ myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET, fw->data,
+ fw->size);
+ }
/* corruption checking is good for parity recovery and buggy chipset */
memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
reread_crc = crc32(~0, fw->data, fw->size);
@@ -536,6 +548,7 @@ static int myri10ge_load_firmware(struct
u32 dma_low, dma_high, size;
int status, i;
+ size = 0;
status = myri10ge_load_hotplug_firmware(mgp, &size);
if (status) {
dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
@@ -778,7 +791,7 @@ myri10ge_submit_8rx(struct mcp_kreq_ethe
}
/*
- * Set of routunes to get a new receive buffer. Any buffer which
+ * Set of routines to get a new receive buffer. Any buffer which
* crosses a 4KB boundary must start on a 4KB boundary due to PCIe
* wdma restrictions. We also try to align any smaller allocation to
* at least a 16 byte boundary for efficiency. We assume the linux
@@ -1349,7 +1362,7 @@ static struct ethtool_ops myri10ge_ethto
.get_rx_csum = myri10ge_get_rx_csum,
.set_rx_csum = myri10ge_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
#ifdef NETIF_F_TSO
@@ -2615,12 +2628,13 @@ static int myri10ge_probe(struct pci_dev
dev_err(&pdev->dev, "Error %d setting DMA mask\n", status);
goto abort_with_netdev;
}
- mgp->cmd = pci_alloc_consistent(pdev, sizeof(*mgp->cmd), &mgp->cmd_bus);
+ mgp->cmd = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ &mgp->cmd_bus, GFP_KERNEL);
if (mgp->cmd == NULL)
goto abort_with_netdev;
- mgp->fw_stats = pci_alloc_consistent(pdev, sizeof(*mgp->fw_stats),
- &mgp->fw_stats_bus);
+ mgp->fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ &mgp->fw_stats_bus, GFP_KERNEL);
if (mgp->fw_stats == NULL)
goto abort_with_cmd;
@@ -2659,8 +2673,8 @@ static int myri10ge_probe(struct pci_dev
/* allocate rx done ring */
bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
- mgp->rx_done.entry =
- pci_alloc_consistent(pdev, bytes, &mgp->rx_done.bus);
+ mgp->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+ &mgp->rx_done.bus, GFP_KERNEL);
if (mgp->rx_done.entry == NULL)
goto abort_with_ioremap;
memset(mgp->rx_done.entry, 0, bytes);
@@ -2750,7 +2762,8 @@ abort_with_firmware:
abort_with_rx_done:
bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
- pci_free_consistent(pdev, bytes, mgp->rx_done.entry, mgp->rx_done.bus);
+ dma_free_coherent(&pdev->dev, bytes,
+ mgp->rx_done.entry, mgp->rx_done.bus);
abort_with_ioremap:
iounmap(mgp->sram);
@@ -2760,11 +2775,12 @@ abort_with_wc:
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- pci_free_consistent(pdev, sizeof(*mgp->fw_stats),
- mgp->fw_stats, mgp->fw_stats_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ mgp->fw_stats, mgp->fw_stats_bus);
abort_with_cmd:
- pci_free_consistent(pdev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ mgp->cmd, mgp->cmd_bus);
abort_with_netdev:
@@ -2799,7 +2815,8 @@ static void myri10ge_remove(struct pci_d
myri10ge_dummy_rdma(mgp, 0);
bytes = myri10ge_max_intr_slots * sizeof(*mgp->rx_done.entry);
- pci_free_consistent(pdev, bytes, mgp->rx_done.entry, mgp->rx_done.bus);
+ dma_free_coherent(&pdev->dev, bytes,
+ mgp->rx_done.entry, mgp->rx_done.bus);
iounmap(mgp->sram);
@@ -2807,19 +2824,20 @@ static void myri10ge_remove(struct pci_d
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- pci_free_consistent(pdev, sizeof(*mgp->fw_stats),
- mgp->fw_stats, mgp->fw_stats_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->fw_stats),
+ mgp->fw_stats, mgp->fw_stats_bus);
- pci_free_consistent(pdev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus);
+ dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
+ mgp->cmd, mgp->cmd_bus);
free_netdev(netdev);
pci_set_drvdata(pdev, NULL);
}
-#define PCI_DEVICE_ID_MYIRCOM_MYRI10GE_Z8E 0x0008
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008
static struct pci_device_id myri10ge_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYIRCOM_MYRI10GE_Z8E)},
+ {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
{0},
};
^ permalink raw reply
* Re: EHEA: Is there a size limit below 80K for patches?
From: Christoph Raisch @ 2006-06-08 12:17 UTC (permalink / raw)
To: Jeff Garzik
Cc: Heiko J Schick, Jan-Bernd Themann, Marcus Eder, netdev, ossthema,
Thomas OS Klein
In-Reply-To: <44880B4C.3020403@garzik.org>
well, now I'm confused...
2 People, two opinions....
Here's a URL for a complete tarball, "sharing" the download location with
our other driver.
http://prdownloads.sourceforge.net/ibmehcad/ehea_EHEA_0002.tgz
We're waiting for a sourceforge project now since 9 days to put out a tgz,
and it looks like many other people get upset right now by their response
time.
So what's the "right"/preferred way to proceed?
Christop R.
> We're currently developing a new Ethernet device driver for a 10G IBM
chip
> for System p. (ppc64)
>
> A later version of the driver should end up in mainline kernel.
> How should we proceed to get first comments by the community?
> Either post this code as a patch to netdev or
yes
> put a full tarball on for example sourceforge?
nope.
Please read and observe: Documentation/SubmittingPatches
and Section 3 of it, References, for other sources of
expectations/requirements.
The -mm tree also contains Documentation/SubmitChecklist
that you may find useful.
---
~Randy
Jeff Garzik <jeff@xxxxx> wrote on 08.06.2006 13:34:36:
> Jan-Bernd Themann wrote:
> > Hello,
> >
> > we tried two times to send a patch set. In both cases the second
> > (largest) patch
> > got lost. The first one was a bit above 100k, the second one we tried
> > was like 75K.
> >
> > Any idea what might be the problem?
>
> It might be size, or tripping a spam filter.
>
> For a new driver, do the sane thing and just post a URL.
>
> Jeff
>
>
>
^ permalink raw reply
* Re: EHEA: Is there a size limit below 80K for patches?
From: Jeff Garzik @ 2006-06-08 11:34 UTC (permalink / raw)
To: Jan-Bernd Themann; +Cc: netdev, meder, raisch, schickhj, themann, tklein
In-Reply-To: <4487FB64.1070307@de.ibm.com>
Jan-Bernd Themann wrote:
> Hello,
>
> we tried two times to send a patch set. In both cases the second
> (largest) patch
> got lost. The first one was a bit above 100k, the second one we tried
> was like 75K.
>
> Any idea what might be the problem?
It might be size, or tripping a spam filter.
For a new driver, do the sane thing and just post a URL.
Jeff
^ permalink raw reply
* Re: [PATCH 2.6.17-rc6-mm1 ] net: RFC 3828-compliant UDP-Lite support
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-06-08 11:30 UTC (permalink / raw)
To: gerrit
Cc: davem, kuznet, pekkas, jmorris, kaber, linux-kernel, netdev,
yoshfuji
In-Reply-To: <200606081150.34018@this-message-has-been-logged>
In article <200606081150.34018@this-message-has-been-logged> (at Thu, 8 Jun 2006 11:50:33 +0100), Gerrit Renker <gerrit@erg.abdn.ac.uk> says:
> + UDP-Lite introduces a new socket type, the SOCK_LDGRAM (note the L) for
> + lightweight, connection-less services. These are the socket options:
I disagree. It should be SOCK_DGRAM.
--
YOSHIFUJI Hideaki @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG-FP : 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply
* Re: [PATCH 2.6.17-rc6-mm1 ] net: RFC 3828-compliant UDP-Lite support
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-06-08 11:03 UTC (permalink / raw)
To: gerrit
Cc: davem, kuznet, pekkas, jmorris, kaber, linux-kernel, netdev,
yoshfuji
In-Reply-To: <200606081150.34018@this-message-has-been-logged>
In article <200606081150.34018@this-message-has-been-logged> (at Thu, 8 Jun 2006 11:50:33 +0100), Gerrit Renker <gerrit@erg.abdn.ac.uk> says:
> Attached is an extension which adds RFC3828 - compliant UDP-Lite functionality
> to the IPv4 networking stack.
:
> net/core/sock.c | 7
> net/ipv4/af_inet.c | 64 +
> net/ipv4/proc.c | 32
> net/udp_lite/Kbuild | 1
> net/udp_lite/Kconfig | 20
> net/udp_lite/udplitev4.c | 1730 ++++++++++++++++++++++++++++++++++
> 19 files changed, 2296 insertions(+), 22 deletions(-)
Plase do the ipv6 side. Thank you.
BTW, is it possible to do merge or share codes among the following things?
- udp / udp-lite (=> net/ipv4, net/ipv6)
and/or
- udp-lite/ipv6 / udp-lite/ipv4 (=> net/udplite)
Regards,
--
YOSHIFUJI Hideaki @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG-FP : 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply
* EHEA: Is there a size limit below 80K for patches?
From: Jan-Bernd Themann @ 2006-06-08 10:26 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, schickhj, themann, tklein
Hello,
we tried two times to send a patch set. In both cases the second (largest) patch
got lost. The first one was a bit above 100k, the second one we tried was like 75K.
Any idea what might be the problem?
Thanks,
Jan-Bernd Themann
^ permalink raw reply
* [PATCH 2.6.17-rc6-mm1 ] net: RFC 3828-compliant UDP-Lite support
From: Gerrit Renker @ 2006-06-08 10:50 UTC (permalink / raw)
To: davem, kuznet, pekkas, jmorris, yoshfuji, kaber; +Cc: linux-kernel, netdev
Attached is an extension which adds RFC3828 - compliant UDP-Lite functionality
to the IPv4 networking stack.
The code has been adapted from our stable kernel patch, which we have been
maintaining and testing extensively over the last 9 months. The attached
has been tested to run ok so far on i386, dual-processor, and AMD architectures.
Due to the similarities to UDP, a lot of code from net/ipv4/udp.c has been
reused; whereas checksumming code has been rewritten entirely - in particular
with regard to ensuring correct behaviour in various and unusual cases, such
as fragmentation and split. Use CONFIG_IP_UDPLITE=y to enable, find docs attached.
Please CC: any feedback/discussion to gerrit.renker@ukuug.org
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: William Stanislaus <william@erg.abdn.ac.uk>
---
Documentation/networking/udp_lite.txt | 246 ++++
include/asm-mips/socket.h | 2
include/linux/in.h | 1
include/linux/net.h | 16
include/linux/skbuff.h | 15
include/linux/snmp.h | 18
include/linux/socket.h | 1
include/linux/udplite.h | 89 +
include/net/snmp.h | 7
include/net/udplite.h | 65 +
include/net/xfrm.h | 2
net/Kconfig | 1
net/Makefile | 1
net/core/sock.c | 7
net/ipv4/af_inet.c | 64 +
net/ipv4/proc.c | 32
net/udp_lite/Kbuild | 1
net/udp_lite/Kconfig | 20
net/udp_lite/udplitev4.c | 1730 ++++++++++++++++++++++++++++++++++
19 files changed, 2296 insertions(+), 22 deletions(-)
diff -Nurp a/Documentation/networking/udp_lite.txt b/Documentation/networking/udp_lite.txt
--- a/Documentation/networking/udp_lite.txt 1970-01-01 01:00:00.000000000 +0100
+++ b/Documentation/networking/udp_lite.txt 2006-06-07 22:07:26.000000000 +0100
@@ -0,0 +1,246 @@
+ ===========================================================================
+ The UDP-Lite protocol (RFC 3828)
+ ===========================================================================
+
+ last modified: Wed 7 Jun 2006
+
+
+ UDP-Lite is a Standards-Track IETF transport protocol which features a
+ variable-length checksum. This has advantages for transport of multimedia
+ (video, VoIP) over wireless networks, as partly damaged packets can still be
+ fed into the codec instead of being discarded due to a failed checksum test.
+
+ This file briefly describes the existing kernel support and the socket API.
+ For in-depth information, you can consult:-
+
+ o The UDP-Lite Homepage: http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/
+ Fom here you can always also pull the latest patch for the stable
+ kernel tree and example application source code.
+
+ o The UDP-Lite HOWTO on
+ http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/UDP-Lite-HOWTO.txt
+
+ o The Ethereal UDP-Lite WiKi (with capture files):
+ http://wiki.ethereal.com/Lightweight_User_Datagram_Protocol
+
+ o The Protocol Spec: RFC 3828, http://www.ietf.org/rfc/rfc3828.txt
+
+
+
+ I) APPLICATIONS
+
+ Several applications have ported successfully to UDP-Lite. Ethereal
+ now comes with UDP-Lite support by default. The tarball on
+
+ http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/files/udplite_linux.tar.gz
+
+ has source code for several client-server and network testing examples.
+
+ Porting applications to UDP-Lite is straightforward: only socket level and
+ IPPROTO need to be changed, senders additionally set the checksum coverage
+ length (default = header length = 8). Details are in the next section.
+
+
+
+ II) PROGRAMMING API
+
+ UDP-Lite introduces a new socket type, the SOCK_LDGRAM (note the L) for
+ lightweight, connection-less services. These are the socket options:
+
+ * Sender checksum coverage: UDPLITE_SOCKOPT_SEND_CSCOV
+
+ For instance,
+
+ int val = 20;
+ setsockopt(s, SOL_UDPLITE, UDPLITE_SOCKOPT_SEND_CSCOV, &val, sizeof(int));
+
+ sets the checksum coverage length to 20 (12b data + 8b header).
+
+
+ * Receiver checksum coverage: UDPLITE_SOCKOPT_RECV_CSCOV
+
+ This option is analogously used at the receiver to set its
+ checksum coverage.
+ While the checksum coverage at the sender means the /actual/
+ length that will be used for the checksum, the receiver
+ checksum coverage stands for the /minimum/ coverage value a
+ receiver is willing to accept; and may drop packets which do
+ not meet this threshold.
+
+ A detailed description of the socket options is in section IV.
+
+
+
+ III) HEADER FILES
+
+ The socket API requires support in header files in /usr/include:
+ * /usr/include/netinet/udplite.h
+ * /usr/include/netinet/in.h
+ * /usr/include/bits/socket.h
+ Changes are minor and replicate the information contained in the patched
+ kernel include files; details and example files for various distros can
+ be found on the UDP-Lite homepage
+
+
+
+ IV) KERNEL BEHAVIOUR WITH REGARD TO THE VARIOUS SOCKET OPTIONS
+
+ To enable debugging messages, the log level must be set to 8, as most
+ messages use the KERN_DEBUG level (7).
+
+
+ 1) Sender Socket Options
+
+ If the sender specifies a value of 0 as coverage length, the module
+ assumes full coverage, transmits a packet with coverage length of 0
+ and according checksum. If the sender specifies a coverage < 8 and
+ different from 0, the kernel assumes 8 as default value. Finally,
+ if the specified coverage length exceeds the packet length, the packet
+ length is used instead as coverage length.
+
+
+ 2) Receiver Socket Options
+
+ The receiver specifies the minimum value of the coverage length it
+ is willing to accept. A value of 0 here indicates that the receiver
+ always wants the whole of the packet covered. In this case, all
+ partially covered packets are dropped and an error is logged.
+
+ It is not possible to specify illegal values (<0 and <8); in these
+ cases the default of 8 is assumed.
+
+ All packets arriving with a coverage value less than the specified
+ threshold are discarded, these events are also logged.
+
+
+ 3) Disabling the Checksum Computation
+
+ On both sender and receiver, trying to disable the UDP Lite checksum
+ (option SO_NO_CHECK) in setsockopt(2) results in an error. Thus
+
+ setsockopt(sockfd,SOL_SOCKET, SO_NO_CHECK, ... );
+
+ will always result in an error, while
+
+ getsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, &value,...);
+
+ will always return a value of 0 (meaning checksum enabled). Packets
+ with a zero checksum field are silently discarded by the receiver.
+
+
+ 4) Fragmentation
+
+ The checksum computation respects both buffersize and MTU. The size
+ of UDP Lite packets is determined by the size of the send buffer. The
+ minimum size of the send buffer is 2048 (defined as SOCK_MIN_SNDBUF
+ in include/net/sock.h), the default value is configurable as
+ net.core.wmem_default or via setting the SO_SNDBUF socket(7)
+ option. The maximum upper bound for the send buffer is determined
+ by net.core.wmem_max.
+
+ Given a payload size larger than the send buffer size, UDP Lite will
+ split the payload into several individual packets, filling up the
+ send buffer size in each case.
+
+ The precise value also depends on the interface MTU. The interface MTU,
+ in turn, may trigger IP fragmentation. In this case, the generated
+ UDP Lite packet is split into several IP packets, of which only the
+ first one contains the header.
+
+ The send buffer size has implications on the checksum coverage length.
+ Consider the following example:
+
+ Payload: 1536 bytes Send Buffer: 1024 bytes
+ MTU : 1500 bytes Coverage Length: 856 bytes
+
+ UDP Lite will ship the 1536 bytes in two separate packets:
+
+ Packet 1: 1024 payload + 8 byte header + 20 byte IP header = 1052 bytes
+ Packet 2: 520 payload + 8 byte header + 20 byte IP header = 528 bytes
+
+ The coverage packet covers the UDP Lite header and 848 bytes of the
+ payload in the first packet, the second packet is fully covered. Note
+ that for the second packet, the coverage length exceeds the packet
+ length. The kernel always re-adjusts the coverage length to the packet
+ length in such cases.
+
+ As an example of what happens when one UDP Lite packet is split into
+ several tiny fragments, consider the following example.
+
+ Payload: 1024 bytes Send buffer size: 1024 bytes
+ MTU: 300 bytes Coverage length: 575 bytes
+
+ +-+-----------+--------------+--------------+--------------+
+ |8| 272 | 280 | 280 | 280 |
+ +-+-----------+--------------+--------------+--------------+
+ 280 560 840 1032
+ ^
+ *****checksum coverage*************
+
+ The UDP Lite module generates one 1032 byte packet (1024 + 8 byte
+ header). According to the interface MTU, these are split into 4 IP
+ packets (280 byte IP payload + 20 byte IP header). The kernel module
+ sums the contents of the entire first two packets, plus 15 bytes of
+ the last packet before releasing the fragments to the IP module.
+
+
+
+ V) UDP-LITE RUNTIME STATISTICS AND THEIR MEANING
+
+ Exceptional and error conditions are logged to syslog at the KERN_DEBUG
+ level. Live statistics about UDP-Lite are available in /proc/net/snmp
+ and can--with newer versions of netstat--be queried using
+
+ netstat -svu
+
+ This displays UDP-Lite statistics variables, whose meaning is as follows.
+
+ InDatagrams: Total number of received datagrams (as in UDP).
+
+ InPartialCov: Number of received datagrams with csum coverage < length.
+
+ NoPorts: Number of packets received to an unknown port (as in UDP).
+ These cases are counted separately (not as InErrors).
+
+ InErrors: Number of erroneous UDP-Lite packets. Errors include:
+ * internal socket queue receive errors
+ * packet too short (less than 8 bytes or stated
+ coverage length exceeds received length)
+ * no socket available for ICMP error condition
+ * xfrm4_policy_check returned error
+ * application has specified larger min. coverage
+ length than that of incoming packet (cf. below)
+ * checksum coverage violated (InBadCoverage)
+ * bad checksum (InBadChecksum)
+
+ InBadCoverage: Datagrams with invalid checksum coverage (also InErrors):
+ * coverage length is less than the minimum 8
+ * coverage length exceeds actual datagram length
+
+ InBadChecksum: Datagrams with wrong checksum (also InErrors).
+
+ OutDatagrams: Total number of sent datagrams.
+
+ OutPartialCov: Number of sent datagrams with csum coverage < length.
+
+ If a receiving application has specified a minimum coverage length and
+ received a packet with a smaller coverage value than this, or if it has
+ specified full coverage (UDP mode) and received a partially covered packet,
+ this counts as error (under InErrors), and an error message is logged.
+
+
+
+ VI) OPEN ISSUES
+
+ At the University of Aberdeen (where this patch was developed), much work
+ has gone into making sure that the UDP-Lite v4 variant behaves according
+ to spec. We have been maintaining and updating a patch for the stable
+ kernel tree since 2.6.12.4 and have run extensive experiments to verify
+ the protocol behaviour. As a result, there was no time left to develop an
+ IPv6 extension with the same degree of testing.
+ Secondly, the statistics variables detailed in the previous section are
+ not standardized. A MIB for UDP-Lite does not (yet) exist. For a person
+ familiar with SNMP/ASN.1 it would be a trivial task to turn the above
+ variable definitions into a MIB, in the same manner as per e.g. RFC 2013.
+ Anyone interested in helping with these two issues should contact us at
+ <gerrit@erg.abdn.ac.uk>.
diff -Nurp a/include/asm-mips/socket.h b/include/asm-mips/socket.h
--- a/include/asm-mips/socket.h 2006-06-05 21:52:55.000000000 +0100
+++ b/include/asm-mips/socket.h 2006-06-07 21:28:09.000000000 +0100
@@ -80,6 +80,7 @@ To add: #define SO_REUSEPORT 0x0200 /* A
*
* @SOCK_DGRAM - datagram (conn.less) socket
* @SOCK_STREAM - stream (connection) socket
+ * @SOCK_LDGRAM - UDP Lite (conn.less) datagram socket (see RFC 3828)
* @SOCK_RAW - raw socket
* @SOCK_RDM - reliably-delivered message
* @SOCK_SEQPACKET - sequential packet socket
@@ -93,6 +94,7 @@ enum sock_type {
SOCK_RDM = 4,
SOCK_SEQPACKET = 5,
SOCK_DCCP = 6,
+ SOCK_LDGRAM = 7,
SOCK_PACKET = 10,
};
diff -Nurp a/include/linux/in.h b/include/linux/in.h
--- a/include/linux/in.h 2006-06-07 20:44:01.000000000 +0100
+++ b/include/linux/in.h 2006-06-07 21:28:09.000000000 +0100
@@ -44,6 +44,7 @@ enum {
IPPROTO_COMP = 108, /* Compression Header protocol */
IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
+ IPPROTO_UDPLITE = 136, /* UDP-Lite Protocol (RFC 3828) */
IPPROTO_RAW = 255, /* Raw IP packets */
IPPROTO_MAX
diff -Nurp a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h 2006-06-07 20:49:51.000000000 +0100
+++ b/include/linux/net.h 2006-06-07 21:28:09.000000000 +0100
@@ -67,6 +67,7 @@ typedef enum {
* enum sock_type - Socket types
* @SOCK_STREAM: stream (connection) socket
* @SOCK_DGRAM: datagram (conn.less) socket
+ * @SOCK_LDGRAM: UDP Lite datagram socket (see RFC 3828)
* @SOCK_RAW: raw socket
* @SOCK_RDM: reliably-delivered message
* @SOCK_SEQPACKET: sequential packet socket
@@ -79,13 +80,14 @@ typedef enum {
* overrides this enum for binary compat reasons.
*/
enum sock_type {
- SOCK_STREAM = 1,
- SOCK_DGRAM = 2,
- SOCK_RAW = 3,
- SOCK_RDM = 4,
- SOCK_SEQPACKET = 5,
- SOCK_DCCP = 6,
- SOCK_PACKET = 10,
+ SOCK_STREAM = 1,
+ SOCK_DGRAM = 2,
+ SOCK_RAW = 3,
+ SOCK_RDM = 4,
+ SOCK_SEQPACKET = 5,
+ SOCK_DCCP = 6,
+ SOCK_LDGRAM = 7,
+ SOCK_PACKET = 10,
};
#define SOCK_MAX (SOCK_PACKET + 1)
diff -Nurp a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h 2006-06-07 20:49:51.000000000 +0100
+++ b/include/linux/skbuff.h 2006-06-07 21:28:09.000000000 +0100
@@ -223,13 +223,14 @@ struct sk_buff {
struct net_device *input_dev;
union {
- struct tcphdr *th;
- struct udphdr *uh;
- struct icmphdr *icmph;
- struct igmphdr *igmph;
- struct iphdr *ipiph;
- struct ipv6hdr *ipv6h;
- unsigned char *raw;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct udplitehdr *ulh; /* UDP-Lite (RFC 3828) */
+ struct icmphdr *icmph;
+ struct igmphdr *igmph;
+ struct iphdr *ipiph;
+ struct ipv6hdr *ipv6h;
+ unsigned char *raw;
} h;
union {
diff -Nurp a/include/linux/snmp.h b/include/linux/snmp.h
--- a/include/linux/snmp.h 2006-06-05 21:52:55.000000000 +0100
+++ b/include/linux/snmp.h 2006-06-07 21:28:09.000000000 +0100
@@ -158,6 +158,24 @@ enum
__UDP_MIB_MAX
};
+/*
+ * UDP Lite (RFC 3828) runtime statistics.
+ * A MIB does not exist yet, but these statistics are useful nevertheless.
+ */
+enum
+{
+ UDPLITE_MIB_NUM = 0,
+ UDPLITE_MIB_INDATAGRAMS, /* total received datagramns */
+ UDPLITE_MIB_INDATAGRAMS_PARTIAL_CHECK, /* rcvd datagrams with partial coverage */
+ UDPLITE_MIB_NOPORTS, /* rcvd datagrams with port errors */
+ UDPLITE_MIB_INERRORS, /* total erroneous rcvd datagrams */
+ UDPLITE_MIB_INERRORS_CHECKSUM_COVERAGE, /* checksum coverage errors */
+ UDPLITE_MIB_INERRORS_CHECKSUMMING, /* checksum itself did not qualify */
+ UDPLITE_MIB_OUTDATAGRAMS, /* total sent datagrams */
+ UDPLITE_MIB_OUTDATAGRAMS_PARTIAL_CHECK, /* sent datagrams with partial coverage */
+ __UDPLITE_MIB_MAX
+};
+
/* sctp mib definitions */
/*
* draft-ietf-sigtran-sctp-mib-07.txt
diff -Nurp a/include/linux/socket.h b/include/linux/socket.h
--- a/include/linux/socket.h 2006-06-07 20:49:51.000000000 +0100
+++ b/include/linux/socket.h 2006-06-07 21:28:09.000000000 +0100
@@ -264,6 +264,7 @@ struct ucred {
#define SOL_IPV6 41
#define SOL_ICMPV6 58
#define SOL_SCTP 132
+#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */
#define SOL_RAW 255
#define SOL_IPX 256
#define SOL_AX25 257
diff -Nurp a/include/linux/udplite.h b/include/linux/udplite.h
--- a/include/linux/udplite.h 1970-01-01 01:00:00.000000000 +0100
+++ b/include/linux/udplite.h 2006-06-07 21:27:36.000000000 +0100
@@ -0,0 +1,89 @@
+/*
+ * Header file for UDP Lite (RFC 3828),
+ * see net/udp_lite for further details.
+ */
+#ifndef _LINUX_UDPLITE_H
+#define _LINUX_UDPLITE_H
+#include <linux/types.h>
+
+/**
+ * struct udplitehdr - UDP-Lite header re-interpreting UDP (RFC 768) fields
+ *
+ * @source: source port number (as in UDP)
+ * @dest: destination port number (as in UDP)
+ * @checklen: checksum coverage length
+ * @check: checksum field (as in UDP)
+ *
+ * For the detailed header semantics see RFC 3828.
+ */
+struct udplitehdr {
+ __u16 source;
+ __u16 dest;
+ __u16 checklen;
+ __u16 check;
+};
+
+
+/* UDP Lite socket options:
+ * Sender specifies actual coverage length.
+ * Receiver specifies _minimal_ coverage length. */
+#define UDPLITE_SOCKOPT_SEND_CSCOV 10 /* sender */
+#define UDPLITE_SOCKOPT_RECV_CSCOV 11 /* receiver */
+
+#define UDPLITE_CORK 1 /* Never send part. complete segm. */
+
+
+
+/* checksum coverage set flags */
+#define UDPLITE_SEND_CHCKFLAG 0x1
+#define UDPLITE_RECV_CHCKFLAG 0x2
+
+
+/* FIXME: UDP-Lite encapsulation types ??? */
+#define UDPLITE_ENCAP 100 /* accept encapsulated pkts */
+#define UDPLITE_ENCAP_ESPINUDPLITE_NON_IKE 1
+#define UDPLITE_ENCAP_ESPINUDPLITE 2
+
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <net/sock.h>
+#include <linux/ip.h>
+/**
+ * struct udplite_sock - unreliable UDP-Lite datagram service
+ *
+ * @inet: has to be the first member
+ * @pending: any pending frames?
+ * @corkflag: when cork is required
+ * @encap_type: is this an encapsulation socket?
+ * @len: total length of pending frames
+ * @pcslen: partial checksum coverage length for sending socket
+ * @pcrlen: partial checksum coverage length for receiving socket
+ * @pcflag: partial checksum coverage flag
+ *
+ * NOTE: Checksum coverage length has different semantics for sending and
+ * receiving sockets.
+ *
+ */
+struct udplite_sock {
+ struct inet_sock inet;
+ int pending;
+ unsigned int corkflag;
+ __u16 encap_type;
+ /* The following members retain the information to create a
+ * UDP-Lite header when the socket is uncorked. */
+ __u16 len;
+ __u16 pcslen;
+ __u16 pcrlen;
+ __u8 pcflag;
+};
+
+static inline struct udplite_sock *udplite_sk(const struct sock *sk)
+{
+ return (struct udplite_sock *)sk;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_UDPLITE_H */
diff -Nurp a/include/net/snmp.h b/include/net/snmp.h
--- a/include/net/snmp.h 2006-06-05 21:52:55.000000000 +0100
+++ b/include/net/snmp.h 2006-06-07 21:28:09.000000000 +0100
@@ -100,6 +100,13 @@ struct udp_mib {
unsigned long mibs[UDP_MIB_MAX];
} __SNMP_MIB_ALIGN__;
+
+/* UDP Lite (RFC 3828) */
+#define UDPLITE_MIB_MAX __UDPLITE_MIB_MAX
+struct udplite_mib {
+ unsigned long mibs[UDPLITE_MIB_MAX];
+} __SNMP_MIB_ALIGN__;
+
/* SCTP */
#define SCTP_MIB_MAX __SCTP_MIB_MAX
struct sctp_mib {
diff -Nurp a/include/net/udplite.h b/include/net/udplite.h
--- a/include/net/udplite.h 1970-01-01 01:00:00.000000000 +0100
+++ b/include/net/udplite.h 2006-06-07 21:16:56.000000000 +0100
@@ -0,0 +1,65 @@
+/*
+ * Header file for UDP Lite (RFC 3828)
+ */
+#ifndef _UDPLITE_H
+#define _UDPLITE_H
+
+#include <linux/udplite.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
+#include <linux/ip.h>
+#include <net/sock.h>
+#include <net/snmp.h>
+
+/* In_UDP Lite the checksum MUST always be computed, hence in contrast to UDP,
+ * there is no UDPLITE_CSUM_DEFAULT and no UDPLITE_CSUM_NOXMIT */
+#define UDPLITE_HTABLE_SIZE 128
+
+
+/* net/udp_lite/udplitev4.c */
+extern struct proto udplite_prot;
+
+extern void udplite_err(struct sk_buff *, u32);
+extern int udplite_sendmsg(struct kiocb *iocb, struct sock *sk,
+ struct msghdr *msg, size_t len);
+extern int udplite_rcv(struct sk_buff *skb);
+extern int udplite_ioctl(struct sock *sk, int cmd, unsigned long arg);
+extern int udplite_disconnect(struct sock *sk, int flags);
+extern unsigned int udplite_poll(struct file *file, struct socket *sock,
+ poll_table * wait);
+
+/*
+ * SNMP MIB for the UDP-Lite layer
+ */
+DECLARE_SNMP_STAT(struct udplite_mib, udplite_statistics);
+#define UDPLITE_INC_STATS(f) SNMP_INC_STATS(udplite_statistics, f)
+#define UDPLITE_INC_STATS_BH(f) SNMP_INC_STATS_BH(udplite_statistics, f)
+#define UDPLITE_INC_STATS_USER(f) SNMP_INC_STATS_USER(udplite_statistics, f)
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * /proc
+ */
+struct udplite_seq_afinfo {
+ struct module *owner;
+ char *name;
+ sa_family_t family;
+ int (*seq_show) (struct seq_file *m, void *v);
+ struct file_operations *seq_fops;
+};
+
+struct udplite_iter_state {
+ sa_family_t family;
+ int bucket;
+ struct seq_operations seq_ops;
+};
+
+extern int udplite_proc_register(struct udplite_seq_afinfo *afinfo);
+extern void udplite_proc_unregister(struct udplite_seq_afinfo *afinfo);
+
+extern int udplite4_proc_init(void);
+extern void udplite4_proc_exit(void);
+#endif /* CONFIG_PROC_FS */
+
+#endif /* _UDPLITE_H */
diff -Nurp a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h 2006-06-07 20:49:52.000000000 +0100
+++ b/include/net/xfrm.h 2006-06-07 21:28:09.000000000 +0100
@@ -501,6 +501,7 @@ u16 xfrm_flowi_sport(struct flowi *fl)
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
case IPPROTO_SCTP:
port = fl->fl_ip_sport;
break;
@@ -521,6 +522,7 @@ u16 xfrm_flowi_dport(struct flowi *fl)
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
case IPPROTO_SCTP:
port = fl->fl_ip_dport;
break;
diff -Nurp a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig 2006-06-07 20:49:53.000000000 +0100
+++ b/net/Kconfig 2006-06-07 21:28:09.000000000 +0100
@@ -164,6 +164,7 @@ endif
source "net/dccp/Kconfig"
source "net/sctp/Kconfig"
+source "net/udp_lite/Kconfig"
source "net/tipc/Kconfig"
source "net/atm/Kconfig"
source "net/bridge/Kconfig"
diff -Nurp a/net/Makefile b/net/Makefile
--- a/net/Makefile 2006-06-05 21:52:55.000000000 +0100
+++ b/net/Makefile 2006-06-07 21:28:09.000000000 +0100
@@ -44,6 +44,7 @@ obj-$(CONFIG_ECONET) += econet/
obj-$(CONFIG_VLAN_8021Q) += 8021q/
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
+obj-$(CONFIG_IP_UDPLITE) += udp_lite/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
diff -Nurp a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c 2006-06-07 20:49:52.000000000 +0100
+++ b/net/core/sock.c 2006-06-07 21:28:09.000000000 +0100
@@ -426,7 +426,12 @@ set_rcvbuf:
break;
case SO_NO_CHECK:
- sk->sk_no_check = valbool;
+ /* UDP-Lite (RFC 3828) mandates checksumming,
+ * hence user must not enable this option. */
+ if (sk->sk_protocol == IPPROTO_UDPLITE)
+ ret = -EOPNOTSUPP;
+ else
+ sk->sk_no_check = valbool;
break;
case SO_PRIORITY:
diff -Nurp a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c 2006-06-07 20:44:09.000000000 +0100
+++ b/net/ipv4/af_inet.c 2006-06-07 21:28:09.000000000 +0100
@@ -15,6 +15,8 @@
* Changes (see also sock.c)
*
* piggy,
+ * W. Stanislaus : Added the UDP-Lite protocol (RFC 3828),
+ * (maintainer: <gerrit@erg.abdn.ac.uk>)
* Karl Knutson : Socket protocol table
* A.N.Kuznetsov : Socket death error in accept().
* John Richardson : Fix non blocking error in connect()
@@ -104,6 +106,7 @@
#include <net/inet_connection_sock.h>
#include <net/tcp.h>
#include <net/udp.h>
+#include <net/udplite.h> /* UDP Lite (RFC 3828) */
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/raw.h>
@@ -838,6 +841,30 @@ const struct proto_ops inet_dgram_ops =
};
/*
+ * For SOCK_LDGRAM sockets, these support the UDP Lite protocol (RFC 3828).
+ */
+struct proto_ops inet_ldgram_ops = {
+ .family = PF_INET,
+ .owner = THIS_MODULE,
+ .release = inet_release,
+ .bind = inet_bind,
+ .connect = inet_dgram_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = inet_getname,
+ .poll = udplite_poll,
+ .ioctl = inet_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = inet_shutdown,
+ .setsockopt = sock_common_setsockopt,
+ .getsockopt = sock_common_getsockopt,
+ .sendmsg = inet_sendmsg,
+ .recvmsg = sock_common_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = inet_sendpage,
+};
+
+/*
* For SOCK_RAW sockets; should be the same as inet_dgram_ops but without
* udp_poll
*/
@@ -898,6 +925,15 @@ static struct inet_protosw inetsw_array[
.flags = INET_PROTOSW_PERMANENT,
},
+ {
+ .type = SOCK_LDGRAM, /* UDP-Lite (RFC 3828) */
+ .protocol = IPPROTO_UDPLITE,
+ .prot = &udplite_prot,
+ .ops = &inet_ldgram_ops,
+ .capability = -1,
+ .no_check = 0, /* checksum mandatory */
+ .flags = INET_PROTOSW_PERMANENT,
+ },
{
.type = SOCK_RAW,
@@ -1114,6 +1150,12 @@ static struct net_protocol udp_protocol
.no_policy = 1,
};
+static struct net_protocol udplite_protocol = { /* UDP-Lite (RFC 3828) */
+ .handler = udplite_rcv,
+ .err_handler = udplite_err,
+ .no_policy = 1,
+};
+
static struct net_protocol icmp_protocol = {
.handler = icmp_rcv,
};
@@ -1130,11 +1172,13 @@ static int __init init_ipv4_mibs(void)
tcp_statistics[1] = alloc_percpu(struct tcp_mib);
udp_statistics[0] = alloc_percpu(struct udp_mib);
udp_statistics[1] = alloc_percpu(struct udp_mib);
- if (!
- (net_statistics[0] && net_statistics[1] && ip_statistics[0]
- && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
- && udp_statistics[0] && udp_statistics[1]))
- return -ENOMEM;
+ udplite_statistics[0] = alloc_percpu(struct udplite_mib);
+ udplite_statistics[1] = alloc_percpu(struct udplite_mib);
+ if (!(net_statistics[0] && net_statistics[1] && ip_statistics[0]
+ && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
+ && udp_statistics[0] && udp_statistics[1]
+ && udplite_statistics[0] && udplite_statistics[1]) )
+ return -ENOMEM;
(void) tcp_mib_init();
@@ -1172,6 +1216,10 @@ static int __init inet_init(void)
if (rc)
goto out_unregister_tcp_proto;
+ rc = proto_register(&udplite_prot, 1); /* UDP Lite (RFC 3828) */
+ if (rc)
+ goto out_unregister_udp_proto; /* XXX: not entirely sure --gr */
+
rc = proto_register(&raw_prot, 1);
if (rc)
goto out_unregister_udp_proto;
@@ -1190,6 +1238,8 @@ static int __init inet_init(void)
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
+ if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0)
+ printk(KERN_CRIT "inet_init: Cannot add UDP-Lite protocol\n");
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICAST
@@ -1272,6 +1322,8 @@ static int __init ipv4_proc_init(void)
goto out_tcp;
if (udp4_proc_init())
goto out_udp;
+ if (udplite4_proc_init())
+ goto out_udplite;
if (fib_proc_init())
goto out_fib;
if (ip_misc_proc_init())
@@ -1281,6 +1333,8 @@ out:
out_misc:
fib_proc_exit();
out_fib:
+ udplite4_proc_exit();
+out_udplite:
udp4_proc_exit();
out_udp:
tcp4_proc_exit();
diff -Nurp a/net/ipv4/proc.c b/net/ipv4/proc.c
--- a/net/ipv4/proc.c 2006-06-07 20:44:12.000000000 +0100
+++ b/net/ipv4/proc.c 2006-06-07 21:28:09.000000000 +0100
@@ -14,6 +14,10 @@
* Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
* Erik Schoenfelder, <schoenfr@ibr.cs.tu-bs.de>
*
+ * Changes:
+ * William Stanislaus: added support for UDP-Lite protocol (RFC 3828),
+ * code maintained by Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *
* Fixes:
* Alan Cox : UDP sockets show the rxqueue/txqueue
* using hint flag for the netinfo.
@@ -38,6 +42,7 @@
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/udp.h>
+#include <net/udplite.h> /* UDP Lite (RFC 3828) */
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -66,9 +71,10 @@ static int sockstat_seq_show(struct seq_
tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
atomic_read(&tcp_memory_allocated));
seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+ seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
- seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
- atomic_read(&ip_frag_mem));
+ seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
+ atomic_read(&ip_frag_mem));
return 0;
}
@@ -176,6 +182,18 @@ static const struct snmp_mib snmp4_udp_l
SNMP_MIB_SENTINEL
};
+static struct snmp_mib snmp4_udplite_list[] = { /* UDP Lite (gerrit@erg.abdn.ac.uk) */
+ SNMP_MIB_ITEM("InDatagrams", UDPLITE_MIB_INDATAGRAMS),
+ SNMP_MIB_ITEM("InPartialCov", UDPLITE_MIB_INDATAGRAMS_PARTIAL_CHECK),
+ SNMP_MIB_ITEM("NoPorts", UDPLITE_MIB_NOPORTS),
+ SNMP_MIB_ITEM("InErrors", UDPLITE_MIB_INERRORS),
+ SNMP_MIB_ITEM("InBadChecksum", UDPLITE_MIB_INERRORS_CHECKSUMMING),
+ SNMP_MIB_ITEM("InBadCoverage", UDPLITE_MIB_INERRORS_CHECKSUM_COVERAGE),
+ SNMP_MIB_ITEM("OutDatagrams", UDPLITE_MIB_OUTDATAGRAMS),
+ SNMP_MIB_ITEM("OutPartialCov", UDPLITE_MIB_OUTDATAGRAMS_PARTIAL_CHECK),
+ SNMP_MIB_SENTINEL
+};
+
static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("SyncookiesSent", LINUX_MIB_SYNCOOKIESSENT),
SNMP_MIB_ITEM("SyncookiesRecv", LINUX_MIB_SYNCOOKIESRECV),
@@ -302,6 +320,16 @@ static int snmp_seq_show(struct seq_file
fold_field((void **) udp_statistics,
snmp4_udp_list[i].entry));
+ seq_puts(seq, "\nUdpLite:"); /* UDP Lite (RFC 3828) */
+ for (i = 0; snmp4_udplite_list[i].name != NULL; i++)
+ seq_printf(seq, " %s", snmp4_udplite_list[i].name);
+
+ seq_puts(seq, "\nUdpLite:");
+ for (i = 0; snmp4_udplite_list[i].name != NULL; i++)
+ seq_printf(seq, " %lu",
+ fold_field((void **) udplite_statistics,
+ snmp4_udplite_list[i].entry));
+
seq_putc(seq, '\n');
return 0;
}
diff -Nurp a/net/udp_lite/Kbuild b/net/udp_lite/Kbuild
--- a/net/udp_lite/Kbuild 1970-01-01 01:00:00.000000000 +0100
+++ b/net/udp_lite/Kbuild 2006-06-07 21:16:56.000000000 +0100
@@ -0,0 +1 @@
+obj-$(CONFIG_IP_UDPLITE) += udplitev4.o
diff -Nurp a/net/udp_lite/Kconfig b/net/udp_lite/Kconfig
--- a/net/udp_lite/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ b/net/udp_lite/Kconfig 2006-06-07 21:38:56.000000000 +0100
@@ -0,0 +1,20 @@
+config IP_UDPLITE
+ bool "The UDP-Lite Protocol (EXPERIMENTAL)"
+ depends on INET && EXPERIMENTAL
+ default n
+ ---help---
+ The UDP Lite Protocol (RFC 3828, <http://tools.ietf.org/html/rfc3828>)
+
+ UDP-Lite is a Standards-Track IETF transport protocol. It features a
+ variable-length checksum, which allows partially damaged packets to be
+ forwarded to media codecs, rather than being discarded due to invalid
+ (UDP) checksum values. This can have advantages for the transport of
+ multimedia (e.g. video/audio) over wireless networks.
+
+ The socket API resembles that of UDP. Applications must indicate their
+ wish to utilise the partial checksum coverage feature offered by UDP-
+ Lite by setting a socket option.
+
+ More information can be found in Documentation/networking/udp_lite.txt
+
+ If in doubt, say N.
diff -Nurp a/net/udp_lite/udplitev4.c b/net/udp_lite/udplitev4.c
--- a/net/udp_lite/udplitev4.c 1970-01-01 01:00:00.000000000 +0100
+++ b/net/udp_lite/udplitev4.c 2006-06-07 21:32:28.000000000 +0100
@@ -0,0 +1,1730 @@
+/*
+ * UDPLITE An implementation of the UDP-Lite protocol as standardised in
+ * RFC 3828. UDP-Lite is based on UDP: this code is a revision of
+ * the original udp.c code with regard to all those aspects in
+ * which UDP-Lite differs from UDP.
+ *
+ * Version: $Id: udplitev4.c,v 1.3 2006/05/25 13:57:06 root Exp root $
+ *
+ * Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ * William Stanislaus <william@erg.abdn.ac.uk>
+ *
+ * based on original code from udp.c, by Ross Biro, Fred N. van
+ * Kempen, Arnt Gulbrandsen, Alan Cox, and Hirokazu Takahashi
+ *
+ * Changes:
+ *
+ */
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/ioctls.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/igmp.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+#include <linux/inet.h>
+#include <linux/ipv6.h>
+#include <linux/netdevice.h>
+#include <net/snmp.h>
+#include <net/ip.h>
+#include <net/tcp_states.h>
+#include <net/protocol.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <net/sock.h>
+#include <net/udplite.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/inet_common.h>
+#include <net/checksum.h>
+#include <net/xfrm.h>
+
+/*
+ * SNMP MIB for the UDP-Lite layer
+ */
+DEFINE_SNMP_STAT(struct udplite_mib, udplite_statistics);
+
+/*
+ * Global variables
+ */
+int udplite_port_rover;
+struct hlist_head udplite_hash[UDPLITE_HTABLE_SIZE];
+DEFINE_RWLOCK(udplite_hash_lock);
+
+
+
+static inline int udplite_lport_inuse(u16 num)
+{
+ struct sock *sk;
+ struct hlist_node *node;
+
+ sk_for_each(sk, node, &udplite_hash[num & (UDPLITE_HTABLE_SIZE - 1)])
+ if (inet_sk(sk)->num == num)
+ return 1;
+ return 0;
+}
+
+/* The following function is identical to the one used in udp.c: */
+
+static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
+{
+ struct hlist_node *node;
+ struct sock *sk2;
+ struct inet_sock *inet = inet_sk(sk);
+
+ write_lock_bh(&udplite_hash_lock);
+ if (snum == 0) {
+ int best_size_so_far, best, result, i;
+
+ if (udplite_port_rover > sysctl_local_port_range[1] ||
+ udplite_port_rover < sysctl_local_port_range[0])
+ udplite_port_rover = sysctl_local_port_range[0];
+ best_size_so_far = 32767;
+ best = result = udplite_port_rover;
+ for (i = 0; i < UDPLITE_HTABLE_SIZE; i++, result++) {
+ struct hlist_head *list;
+ int size;
+
+ list =
+ &udplite_hash[result & (UDPLITE_HTABLE_SIZE - 1)];
+ if (hlist_empty(list)) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0] +
+ ((result -
+ sysctl_local_port_range[0]) &
+ (UDPLITE_HTABLE_SIZE - 1));
+ goto gotit;
+ }
+ size = 0;
+ sk_for_each(sk2, node, list)
+ if (++size >= best_size_so_far)
+ goto next;
+ best_size_so_far = size;
+ best = result;
+ next:;
+ }
+ result = best;
+ for (i = 0; i < (1 << 16) / UDPLITE_HTABLE_SIZE;
+ i++, result += UDPLITE_HTABLE_SIZE) {
+ if (result > sysctl_local_port_range[1])
+ result = sysctl_local_port_range[0]
+ + ((result - sysctl_local_port_range[0]) &
+ (UDPLITE_HTABLE_SIZE - 1));
+ if (!udplite_lport_inuse(result))
+ break;
+ }
+ if (i >= (1 << 16) / UDPLITE_HTABLE_SIZE)
+ goto fail;
+ gotit:
+ udplite_port_rover = snum = result;
+ } else {
+ sk_for_each(sk2, node,
+ &udplite_hash[snum & (UDPLITE_HTABLE_SIZE - 1)]) {
+ struct inet_sock *inet2 = inet_sk(sk2);
+
+ if (inet2->num == snum &&
+ sk2 != sk &&
+ !ipv6_only_sock(sk2) &&
+ (!sk2->sk_bound_dev_if ||
+ !sk->sk_bound_dev_if ||
+ sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (!inet2->rcv_saddr ||
+ !inet->rcv_saddr ||
+ inet2->rcv_saddr == inet->rcv_saddr) &&
+ (!sk2->sk_reuse || !sk->sk_reuse))
+ goto fail;
+ }
+ }
+ inet->num = snum;
+ if (sk_unhashed(sk)) {
+ struct hlist_head *h =
+ &udplite_hash[snum & (UDPLITE_HTABLE_SIZE - 1)];
+
+ sk_add_node(sk, h);
+ sock_prot_inc_use(sk->sk_prot);
+ }
+ write_unlock_bh(&udplite_hash_lock);
+ return 0;
+
+ fail:
+ write_unlock_bh(&udplite_hash_lock);
+ return 1;
+}
+
+static void udplite_v4_hash(struct sock *sk) /* Identical to udp.c */
+{
+ BUG();
+}
+
+static void udplite_v4_unhash(struct sock *sk) /* Identical to udp.c */
+{
+ write_lock_bh(&udplite_hash_lock);
+ if (sk_del_node_init(sk)) {
+ inet_sk(sk)->num = 0;
+ sock_prot_dec_use(sk->sk_prot);
+ }
+ write_unlock_bh(&udplite_hash_lock);
+}
+
+
+/* The following function is identical to the one used in udp.c: */
+
+static struct sock *udplite_v4_lookup_longway(u32 saddr, u16 sport,
+ u32 daddr, u16 dport, int dif)
+{
+ struct sock *sk,
+ *result = NULL;
+ struct hlist_node *node;
+ unsigned short hnum = ntohs(dport);
+ int badness = -1;
+
+ sk_for_each(sk, node, &udplite_hash[hnum & (UDPLITE_HTABLE_SIZE - 1)]) {
+ struct inet_sock *inet = inet_sk(sk);
+
+ if (inet->num == hnum && !ipv6_only_sock(sk)) {
+ int score = (sk->sk_family == PF_INET ? 1 : 0);
+ if (inet->rcv_saddr) {
+ if (inet->rcv_saddr != daddr)
+ continue;
+ score += 2;
+ }
+ if (inet->daddr) {
+ if (inet->daddr != saddr)
+ continue;
+ score += 2;
+ }
+ if (inet->dport) {
+ if (inet->dport != sport)
+ continue;
+ score += 2;
+ }
+ if (sk->sk_bound_dev_if) {
+ if (sk->sk_bound_dev_if != dif)
+ continue;
+ score += 2;
+ }
+ if (score == 9) {
+ result = sk;
+ break;
+ } else if (score > badness) {
+ result = sk;
+ badness = score;
+ }
+ }
+ }
+ return result;
+}
+
+/* The following function is identical to the one used in udp.c: */
+
+static __inline__ struct sock *udplite_v4_lookup(u32 saddr, u16 sport,
+ u32 daddr, u16 dport, int dif)
+{
+ struct sock *sk;
+
+ read_lock(&udplite_hash_lock);
+ sk = udplite_v4_lookup_longway(saddr, sport, daddr, dport, dif);
+ if (sk)
+ sock_hold(sk);
+ read_unlock(&udplite_hash_lock);
+ return sk;
+}
+
+/* The following function is identical to the one used in udp.c: */
+
+static inline struct sock *udplite_v4_mcast_next(struct sock *sk,
+ u16 loc_port, u32 loc_addr,
+ u16 rmt_port, u32 rmt_addr,
+ int dif)
+{
+ struct hlist_node *node;
+ struct sock *s = sk;
+ unsigned short hnum = ntohs(loc_port);
+
+ sk_for_each_from(s, node) {
+ struct inet_sock *inet = inet_sk(s);
+
+ if (inet->num != hnum ||
+ (inet->daddr && inet->daddr != rmt_addr) ||
+ (inet->dport != rmt_port && inet->dport) ||
+ (inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
+ ipv6_only_sock(s) ||
+ (s->sk_bound_dev_if && s->sk_bound_dev_if != dif))
+ continue;
+ if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif))
+ continue;
+ goto found;
+ }
+ s = NULL;
+ found:
+ return s;
+}
+
+/**
+ * udplite_err - handle error conditions (taken from udp.c)
+ * @skb:
+ * @info:
+ *
+ * This routine is called by the ICMP module when it gets some
+ * sort of error condition. If err < 0 then the socket should
+ * be closed and the error returned to the user. If err > 0
+ * it's just the icmp type << 8 | icmp code.
+ * Header points to the ip header of the error packet. We move
+ * on past this. Then (as it used to claim before adjustment)
+ * header points to the first 8 bytes of the UDP-Lite header.
+ * We need to find the appropriate port.
+ */
+
+void udplite_err(struct sk_buff *skb, u32 info)
+{
+ struct inet_sock *inet;
+ struct iphdr *iph = (struct iphdr *)skb->data;
+ struct udplitehdr *uh = (struct udplitehdr *)
+ (skb->data + (iph->ihl << 2));
+ int type = skb->h.icmph->type,
+ code = skb->h.icmph->code;
+ struct sock *sk;
+ int harderr, err;
+
+ sk = udplite_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source,
+ skb->dev->ifindex);
+ if (sk == NULL) {
+ ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
+ return; /* No socket for error */
+ }
+
+ err = 0;
+ harderr = 0;
+ inet = inet_sk(sk);
+
+ switch (type) {
+ default:
+ case ICMP_TIME_EXCEEDED:
+ err = EHOSTUNREACH;
+ break;
+ case ICMP_SOURCE_QUENCH:
+ goto out;
+ case ICMP_PARAMETERPROB:
+ err = EPROTO;
+ harderr = 1;
+ break;
+ case ICMP_DEST_UNREACH:
+ if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
+ if (inet->pmtudisc != IP_PMTUDISC_DONT) {
+ err = EMSGSIZE;
+ harderr = 1;
+ break;
+ }
+ goto out;
+ }
+ err = EHOSTUNREACH;
+ if (code <= NR_ICMP_UNREACH) {
+ harderr = icmp_err_convert[code].fatal;
+ err = icmp_err_convert[code].errno;
+ }
+ break;
+ }
+
+ /*
+ * This is handled as in UDP (cf. RFC 1122, sec. 4.1.3.3),
+ * ICMP errors are passed back to the application.
+ */
+ if (!inet->recverr) {
+ if (!harderr || sk->sk_state != TCP_ESTABLISHED)
+ goto out;
+ } else {
+ ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *) (uh + 1));
+ }
+ sk->sk_err = err;
+ sk->sk_error_report(sk);
+ out:
+ sock_put(sk);
+}
+
+/**
+ * udplite_flush_pending_frames - taken from udp.c
+ *
+ * Throw away all pending data and cancel the corking. Socket is locked.
+ */
+static void udplite_flush_pending_frames(struct sock *sk)
+{
+ struct udplite_sock *up = udplite_sk(sk);
+
+ if (up->pending) {
+ up->len = 0;
+ up->pending = 0;
+ ip_flush_pending_frames(sk);
+ }
+}
+
+/**
+ * udplite_push_pending_frames - send pending data
+ *
+ * Push out all pending data as one UDP-Lite datagram. Socket is locked.
+ * This code is modelled after the original in udp.c, but has been heavily
+ * modified in all parts that relate to (partial) checksum computation.
+ */
+static int udplite_push_pending_frames(struct sock *sk, struct udplite_sock *up)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct flowi *fl = &inet->cork.fl;
+ struct sk_buff *skb;
+ struct udplitehdr *uh;
+ int offset, /* within skb structure */
+ err = 0;
+ unsigned short clen = 0, /* checksum coverage length */
+ len;
+ unsigned int csum = 0; /* Intermediate checksum value. */
+
+ /* Grab the skbuff where UDP-Lite header space exists. */
+ if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
+ goto out;
+
+ /*
+ * Create a UDP-Lite header
+ */
+ uh = skb->h.ulh;
+ uh->source = fl->fl_ip_sport;
+ uh->dest = fl->fl_ip_dport;
+ uh->check = 0;
+
+ offset = (unsigned char *)uh - skb->data;
+
+
+ if (up->pcflag & UDPLITE_SEND_CHCKFLAG) {
+ /* Sender has requested partial coverage via sockopts. */
+ if (up->pcslen < up->len) {
+ if (up->pcslen == 0) /* Full coverage (RFC 3828) */
+ clen = up->len;
+ else { /* Genuine partial coverage */
+ clen = up->pcslen;
+ UDPLITE_INC_STATS_BH
+ (UDPLITE_MIB_OUTDATAGRAMS_PARTIAL_CHECK);
+ }
+ uh->checklen = htons(up->pcslen);
+
+ } else { /* up->pcslen >= up->len */
+ /*
+ * Causes for up->pcslen > up->len (error):
+ * (i) Sender error (will not be penalized).
+ * (ii) Payload too big for send buffer: data is split
+ * into several packets, each with its own header. In
+ * this case (e.g. last fragment), coverage length may
+ * exceed packet length.
+ * Since packets with coverage length > packet length
+ * are illegal, we adjust in both cases to the maximum
+ * upper bound.
+ */
+ clen = up->len;
+ uh->checklen = htons(clen);
+ }
+ } else { /* No flag: emulate UDP. */
+ clen = up->len;
+ uh->checklen = htons(clen);
+ }
+
+ /*
+ * Checksum computation: is mandatory in UDP-Lite (RFC 3828).
+ * There are no known drivers which would allow HW offloading of csum.
+ */
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (skb_queue_len(&sk->sk_write_queue) == 1) {
+ /* Only one fragment on the socket. */
+ csum = csum_partial(skb->data + offset, clen, 0);
+
+ } else { /* Packet is fragmented. */
+
+ if (clen <= (skb->len - offset)) {
+ /* Coverage lies within the first frame. */
+ csum = csum_partial(skb->data + offset, clen, 0);
+
+ } else { /* Collect the checksum over the fragments */
+ skb_queue_walk(&sk->sk_write_queue, skb) {
+ offset = (unsigned char*)skb->h.raw - skb->data;
+ len = skb->len - offset;
+
+ skb->csum =
+ csum_partial(skb->data + offset,
+ (clen > len) ? len : clen, 0);
+ csum = csum_add(csum, skb->csum);
+
+ if (clen < len) /* Enough seen. */
+ break;
+ clen -= len;
+ }
+ }
+ }
+ /* Finalise the checksum by adding the pseudo-header. */
+ uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len,
+ IPPROTO_UDPLITE, csum);
+
+ /* RFC 3828: if computed checksum is 0, transmit it as all ones.
+ * The transmitted checksum MUST NOT be all zeroes (sec. 3.1). */
+ if (uh->check == 0)
+ uh->check = -1;
+
+ err = ip_push_pending_frames(sk); /* Send the datagram (fragments). */
+out:
+ up->len = 0;
+ up->pending = 0;
+ return err;
+}
+
+/**
+ * udplite_sendmsg - send function
+ *
+ * Code taken from udp.c but modified with regard to UDP-Lite specifics.
+ */
+int udplite_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+ size_t len)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct udplite_sock *up = udplite_sk(sk);
+ struct ipcm_cookie ipc;
+ struct rtable *rt = NULL;
+ int free = 0, err,
+ connected = 0,
+ ulen = len; /* UDP-Lite length */
+ u32 daddr, faddr, saddr;
+ u16 dport;
+ u8 tos;
+ int corkreq = up->corkflag || msg->msg_flags & MSG_MORE;
+
+ if (len > 0xFFFF)
+ return -EMSGSIZE;
+
+ /*
+ * Check the flags.
+ */
+ if (msg->msg_flags & MSG_OOB) /* BSD error message compatibility */
+ return -EOPNOTSUPP;
+
+ ipc.opt = NULL;
+
+ if (up->pending) {
+ /*
+ * There are pending frames.
+ * The socket lock must be held while it's corked.
+ */
+ lock_sock(sk);
+ if (likely(up->pending)) {
+ if (unlikely(up->pending != AF_INET)) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+ goto do_append_data;
+ }
+ release_sock(sk);
+ }
+ ulen += sizeof(struct udplitehdr);
+
+ /*
+ * Get and verify the address.
+ */
+ if (msg->msg_name) {
+ struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
+ if (msg->msg_namelen < sizeof(*usin))
+ return -EINVAL;
+ if (usin->sin_family != AF_INET) {
+ if (usin->sin_family != AF_UNSPEC)
+ return -EAFNOSUPPORT;
+ }
+
+ daddr = usin->sin_addr.s_addr;
+ dport = usin->sin_port;
+ if (dport == 0)
+ return -EINVAL;
+ } else {
+ if (sk->sk_state != TCP_ESTABLISHED)
+ return -EDESTADDRREQ;
+ daddr = inet->daddr;
+ dport = inet->dport;
+ /* Open fast path for connected socket.
+ * Route will not be used, if at least one option is set.
+ */
+ connected = 1;
+ }
+ ipc.addr = inet->saddr;
+
+ ipc.oif = sk->sk_bound_dev_if;
+ if (msg->msg_controllen) {
+ err = ip_cmsg_send(msg, &ipc);
+ if (err)
+ return err;
+ if (ipc.opt)
+ free = 1;
+ connected = 0;
+ }
+ if (!ipc.opt)
+ ipc.opt = inet->opt;
+
+ saddr = ipc.addr;
+ ipc.addr = faddr = daddr;
+
+ if (ipc.opt && ipc.opt->srr) {
+ if (!daddr)
+ return -EINVAL;
+ faddr = ipc.opt->faddr;
+ connected = 0;
+ }
+ tos = RT_TOS(inet->tos);
+ if (sock_flag(sk, SOCK_LOCALROUTE) ||
+ (msg->msg_flags & MSG_DONTROUTE) ||
+ (ipc.opt && ipc.opt->is_strictroute)) {
+ tos |= RTO_ONLINK;
+ connected = 0;
+ }
+
+ if (MULTICAST(daddr)) {
+ if (!ipc.oif)
+ ipc.oif = inet->mc_index;
+ if (!saddr)
+ saddr = inet->mc_addr;
+ connected = 0;
+ }
+
+ if (connected)
+ rt = (struct rtable *)sk_dst_check(sk, 0);
+
+ if (rt == NULL) {
+ struct flowi fl = {
+ .oif = ipc.oif,
+ .nl_u = {.ip4_u =
+ {.daddr = faddr,.saddr = saddr,.tos = tos}},
+ .proto = IPPROTO_UDPLITE,
+ .uli_u = {.ports =
+ {.sport = inet->sport,.dport = dport}}
+ };
+
+ err =
+ ip_route_output_flow(&rt, &fl, sk,
+ !(msg->msg_flags & MSG_DONTWAIT));
+ if (err)
+ goto out;
+
+ err = -EACCES;
+ if ((rt->rt_flags & RTCF_BROADCAST) &&
+ !sock_flag(sk, SOCK_BROADCAST))
+ goto out;
+ if (connected)
+ sk_dst_set(sk, dst_clone(&rt->u.dst));
+ }
+
+ if (msg->msg_flags & MSG_CONFIRM)
+ goto do_confirm;
+
+back_from_confirm:
+
+ saddr = rt->rt_src;
+ if (!ipc.addr)
+ daddr = ipc.addr = rt->rt_dst;
+
+ lock_sock(sk);
+ if (unlikely(up->pending)) {
+ /* The socket is already corked while preparing it. */
+ /* ... which is an evident application bug. --ANK */
+ release_sock(sk);
+
+ LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: cork app bug 2\n");
+ err = -EINVAL;
+ goto out;
+ }
+ /*
+ * Now cork the socket to pend data.
+ */
+ inet->cork.fl.fl4_dst = daddr;
+ inet->cork.fl.fl_ip_dport = dport;
+ inet->cork.fl.fl4_src = saddr;
+ inet->cork.fl.fl_ip_sport = inet->sport;
+ up->pending = AF_INET;
+
+do_append_data:
+ up->len += ulen;
+ err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
+ sizeof(struct udplitehdr), &ipc, rt,
+ corkreq ? msg->msg_flags | MSG_MORE
+ : msg->msg_flags);
+ if (err)
+ udplite_flush_pending_frames(sk);
+ else if (!corkreq)
+ err = udplite_push_pending_frames(sk, up);
+ release_sock(sk);
+
+out:
+ ip_rt_put(rt);
+ if (free)
+ kfree(ipc.opt);
+ if (!err) {
+ UDPLITE_INC_STATS_USER(UDPLITE_MIB_OUTDATAGRAMS);
+ return len;
+ }
+ return err;
+
+do_confirm:
+ dst_confirm(&rt->u.dst);
+ if (!(msg->msg_flags & MSG_PROBE) || len)
+ goto back_from_confirm;
+ err = 0;
+ goto out;
+}
+
+/* as in udp.c */
+static int udplite_sendpage(struct sock *sk, struct page *page, int offset,
+ size_t size, int flags)
+{
+ struct udplite_sock *up = udplite_sk(sk);
+ int ret;
+
+ if (!up->pending) {
+ struct msghdr msg = {.msg_flags = flags | MSG_MORE };
+
+ /* Call udplite_sendmsg to specify destination address which
+ * sendpage interface can't pass.
+ * This will succeed only when the socket is connected.
+ */
+ ret = udplite_sendmsg(NULL, sk, &msg, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ lock_sock(sk);
+
+ if (unlikely(!up->pending)) {
+ release_sock(sk);
+
+ LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: cork app bug 3\n");
+ return -EINVAL;
+ }
+
+ ret = ip_append_page(sk, page, offset, size, flags);
+ if (ret == -EOPNOTSUPP) {
+ release_sock(sk);
+ return sock_no_sendpage(sk->sk_socket, page, offset,
+ size, flags);
+ }
+ if (ret < 0) {
+ udplite_flush_pending_frames(sk);
+ goto out;
+ }
+
+ up->len += size;
+ if (!(up->corkflag || (flags & MSG_MORE)))
+ ret = udplite_push_pending_frames(sk, up);
+ if (!ret)
+ ret = size;
+out:
+ release_sock(sk);
+ return ret;
+}
+
+/**
+ * udplite_ioctl - taken from udp.c
+ *
+ * IOCTL requests applicable to the UDP-Lite protocol
+ */
+int udplite_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case SIOCOUTQ:
+ {
+ int amount = atomic_read(&sk->sk_wmem_alloc);
+ return put_user(amount, (int __user *)arg);
+ }
+
+ case SIOCINQ:
+ {
+ struct sk_buff *skb;
+ unsigned long amount;
+
+ amount = 0;
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ skb = skb_peek(&sk->sk_receive_queue);
+ if (skb != NULL) {
+ /*
+ * We will only return the amount
+ * of this packet since that is all
+ * that will be read.
+ */
+ amount = skb->len - sizeof(struct udplitehdr);
+ }
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ return put_user(amount, (int __user *)arg);
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return (0);
+}
+
+/*---------------------------------------------------------------------------
+ * Checksumming functions used for receiving and polling events.
+ *---------------------------------------------------------------------------*/
+/**
+ * __udplite_checksum_complete - UDP-Lite csum workhorse
+ *
+ * Returns 1 on error, 0 if checksum is fine.
+ */
+static __inline__ int __udplite_checksum_complete(struct sk_buff *skb)
+{
+ struct udplitehdr *uh;
+ unsigned short len, /* Total length of the UDP-Lite packet. */
+ clen; /* Coverage length as stated in header. */
+ int offset; /* Offset of UDP-Lite header within buff. */
+
+ uh = skb->h.ulh;
+ clen = ntohs(uh->checklen);
+ offset = (unsigned char *)uh - skb->data;
+ len = skb->len - offset;
+
+ if (clen == 0) /* Honour full packet coverage. */
+ clen = len;
+
+ /* Don't checksum if we have illegal coverage lengths (RFC 3828).
+ * FIXME: The syslog messages are really there to flag bug conditions,
+ * illegal checksum coverage length problems should have been resolved
+ * before this routine is called. */
+ if (clen < 8 || clen > len) { /* Using clen > len leads to crash! */
+ LIMIT_NETDEBUG(KERN_WARNING
+ "UDPLITE: Illegal coverage length %d (length %d).\n",
+ clen, len);
+ return 1;
+ } else if (uh->check == 0) {
+ LIMIT_NETDEBUG(KERN_WARNING
+ "UDPLITE: Illegal packet - zero checksum.\n");
+ return 1;
+ } else /* packet is law-abiding, so checksum it */
+ return (unsigned short)
+ csum_fold(skb_checksum(skb, offset, clen, skb->csum));
+}
+
+
+/**
+ * udplite_checksum_complete - finalise UDP-Lite csum computation
+ *
+ * Return 0 if no checksum required or checksum computes ok.
+ */
+static __inline__ int udplite_checksum_complete(struct sk_buff *skb)
+{
+ return skb->ip_summed != CHECKSUM_UNNECESSARY
+ && __udplite_checksum_complete(skb);
+}
+
+/**
+ * udplite_recvmsg - receive a message (taken from udp.c)
+ */
+static int udplite_recvmsg(struct kiocb *iocb,
+ struct sock *sk,
+ struct msghdr *msg,
+ size_t len, int noblock, int flags, int *addr_len)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
+ struct sk_buff *skb;
+ int copied, err;
+
+ /*
+ * Check any passed addresses
+ */
+ if (addr_len)
+ *addr_len = sizeof(*sin);
+
+ if (flags & MSG_ERRQUEUE)
+ return ip_recv_error(sk, msg, len);
+
+ try_again:
+ skb = skb_recv_datagram(sk, flags, noblock, &err);
+ if (!skb)
+ goto out;
+
+ copied = skb->len - sizeof(struct udplitehdr);
+ if (copied > len) {
+ copied = len;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+ if (udplite_checksum_complete(skb)) /* Checksum validation */
+ goto csum_copy_err;
+
+ err =
+ skb_copy_datagram_iovec(skb, sizeof(struct udplitehdr),
+ msg->msg_iov, copied);
+ if (err)
+ goto out_free;
+
+ sock_recv_timestamp(msg, sk, skb);
+
+ if (sin) { /* Copy the address. */
+ sin->sin_family = AF_INET;
+ sin->sin_port = skb->h.uh->source;
+ sin->sin_addr.s_addr = skb->nh.iph->saddr;
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ }
+ if (inet->cmsg_flags)
+ ip_cmsg_recv(msg, skb);
+
+ err = copied;
+ if (flags & MSG_TRUNC)
+ err = skb->len - sizeof(struct udplitehdr);
+
+ out_free:
+ skb_free_datagram(sk, skb);
+ out:
+ return err;
+
+ csum_copy_err:
+ LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: csum error in recvmsg.\n");
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS_CHECKSUMMING);
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS);
+ if (flags & MSG_PEEK) { /* Clear queue. */
+ int clear = 0;
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ clear = 1;
+ }
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ if (clear)
+ kfree_skb(skb);
+ }
+
+ skb_free_datagram(sk, skb);
+
+ if (noblock)
+ return -EAGAIN;
+ goto try_again;
+}
+
+/* The following function is identical to the one used in udp.c: */
+
+int udplite_disconnect(struct sock *sk, int flags)
+{
+ struct inet_sock *inet = inet_sk(sk);
+
+ /*
+ * 1003.1g - break association.
+ */
+ sk->sk_state = TCP_CLOSE;
+ sk->sk_bound_dev_if = 0;
+ inet->daddr = 0;
+ inet->dport = 0;
+ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
+ inet_reset_saddr(sk);
+
+ if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) {
+ sk->sk_prot->unhash(sk);
+ inet->sport = 0;
+ }
+ sk_dst_reset(sk);
+ return 0;
+}
+
+
+static void udplite_close(struct sock *sk, long timeout)
+{
+ sk_common_release(sk);
+}
+
+/**
+ * udplite_encap_rcv - taken from udp.c
+ *
+ * Return:
+ * 1 if the the UDP-Lite system should process it
+ * 0 if we should drop this packet
+ * -1 if it should get processed by xfrm4_rcv_encap
+ */
+
+static int udplite_encap_rcv(struct sock *sk, struct sk_buff *skb)
+{
+#ifndef CONFIG_XFRM
+ return 1;
+#else
+ struct udplite_sock *up = udplite_sk(sk);
+ struct udplitehdr *uh = skb->h.ulh;
+ struct iphdr *iph;
+ int iphlen, len;
+
+ __u8 *udplitedata = (__u8 *) uh + sizeof(struct udplitehdr);
+ __u32 *udplitedata32 = (__u32 *) udplitedata;
+ __u16 encap_type = up->encap_type;
+
+ /* if we're overly short, let UDP-Lite handle it */
+ if (udplitedata > skb->tail)
+ return 1;
+
+ /* if this is not encapsulated socket, then just return now */
+ if (!encap_type)
+ return 1;
+
+ len = skb->tail - udplitedata;
+
+ switch (encap_type) {
+ default:
+ case UDPLITE_ENCAP_ESPINUDPLITE:
+ /* Check if this is a keepalive packet. If so, eat it. */
+ if (len == 1 && udplitedata[0] == 0xff) {
+ return 0;
+ } else if (len > sizeof(struct ip_esp_hdr)
+ && udplitedata32[0] != 0) {
+ /* ESP Packet without Non-ESP header */
+ len = sizeof(struct udplitehdr);
+ } else
+ /* Must be an IKE packet.. pass it through */
+ return 1;
+ break;
+ case UDPLITE_ENCAP_ESPINUDPLITE_NON_IKE:
+ /* Check if this is a keepalive packet. If so, eat it. */
+ if (len == 1 && udplitedata[0] == 0xff) {
+ return 0;
+ } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
+ udplitedata32[0] == 0 && udplitedata32[1] == 0) {
+
+ /* ESP Packet with Non-IKE marker */
+ len = sizeof(struct udplitehdr) + 2 * sizeof(u32);
+ } else
+ /* Must be an IKE packet.. pass it through */
+ return 1;
+ break;
+ }
+
+ /* At this point we are sure that this is an ESP-in-UDP-Lite packet,
+ * so we need to remove 'len' bytes from the packet (the UDP-Lite
+ * header and optional ESP marker bytes) and then modify the
+ * protocol to ESP, and then call into the transform receiver.
+ */
+ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ return 0;
+
+ /* Now we can update and verify the packet length... */
+ iph = skb->nh.iph;
+ iphlen = iph->ihl << 2;
+ iph->tot_len = htons(ntohs(iph->tot_len) - len);
+ if (skb->len < iphlen + len) {
+ /* packet is too small!?! */
+ return 0;
+ }
+
+ /* pull the data buffer up to the ESP header and set the
+ * transport header to point to ESP. Keep UDP-Lite on the stack
+ * for later.
+ */
+ skb->h.raw = skb_pull(skb, len);
+
+ /* modify the protocol (it's ESP!) */
+ iph->protocol = IPPROTO_ESP;
+
+ /* and let the caller know to send this into the ESP processor... */
+ return -1;
+#endif
+}
+
+/**
+ * udplite_queue_rcv - same code as in udp.c
+ *
+ * Returns:
+ * -1: error
+ * 0: success
+ * >0: "UDP-Lite encap" protocol resubmission
+ *
+ * Note that in the success and error cases, the skb is assumed to
+ * have either been requeued or freed.
+ */
+
+static int udplite_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct udplite_sock *up = udplite_sk(sk);
+
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+ */
+ if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
+ kfree_skb(skb);
+ return -1;
+ }
+
+ if (up->encap_type) {
+ /*
+ * This is an encapsulation socket, so let's see if this is
+ * an encapsulated packet.
+ * If it's a keepalive packet, then just eat it.
+ * If it's an encapsulateed packet, then pass it to the
+ * IPsec xfrm input and return the response
+ * appropriately. Otherwise, just fall through and
+ * pass this up the UDP-Lite socket.
+ */
+ int ret;
+
+ ret = udplite_encap_rcv(sk, skb);
+ if (ret == 0) {
+ /* Eat the packet .. */
+ kfree_skb(skb);
+ return 0;
+ }
+ if (ret < 0) {
+ /* process the ESP packet */
+ ret = xfrm4_rcv_encap(skb, up->encap_type);
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INDATAGRAMS);
+ return -ret;
+ }
+ /* FALLTHROUGH -- it's a UDP-Lite Packet */
+ }
+ /*
+ * FIXME: The use of encapsulated packets has not yet been tested. The
+ * code below reflects the common-sense options, but may have to check
+ * whether it works in all possible cases. -- gr
+ */
+ if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
+ if (__udplite_checksum_complete(skb)) {
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS_CHECKSUMMING);
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS);
+ kfree_skb(skb);
+ return -1;
+ }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+
+ if (sock_queue_rcv_skb(sk, skb) < 0) {
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS);
+ kfree_skb(skb);
+ return -1;
+ }
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INDATAGRAMS);
+ return 0;
+}
+
+/*
+ * udplite_v4_mcast_deliver - code taken from udp.c
+ *
+ * Multicasts and broadcasts go to each listener.
+ * Note: called only from the BH handler context,
+ * so we don't need to lock the hashes.
+ */
+static int udplite_v4_mcast_deliver(struct sk_buff *skb, struct udplitehdr *uh,
+ u32 saddr, u32 daddr)
+{
+ struct sock *sk;
+ int dif;
+
+ read_lock(&udplite_hash_lock);
+ sk = sk_head(&udplite_hash
+ [ntohs(uh->dest) & (UDPLITE_HTABLE_SIZE - 1)]);
+ dif = skb->dev->ifindex;
+ sk = udplite_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
+ if (sk) {
+ struct sock *sknext = NULL;
+
+ do {
+ struct sk_buff *skb1 = skb;
+
+ sknext =
+ udplite_v4_mcast_next(sk_next(sk), uh->dest, daddr,
+ uh->source, saddr, dif);
+ if (sknext)
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+
+ if (skb1) {
+ int ret = udplite_queue_rcv_skb(sk, skb1);
+ if (ret > 0)
+ /* we should probably re-process instead
+ * of dropping packets here. */
+ kfree_skb(skb1);
+ }
+ sk = sknext;
+ } while (sknext);
+ } else
+ kfree_skb(skb);
+ read_unlock(&udplite_hash_lock);
+ return 0;
+}
+
+/**
+ * udplite_checksum_init - Initialize UDP-Lite checksum.
+ *
+ * If exited with zero value (success), CHECKSUM_UNNECESSARY means that
+ * no more checks are required. Otherwise, csum completion requires to
+ * checksum packet body plus UDP-Lite header, and folding it to skb->csum.
+ */
+static int udplite_checksum_init(struct sk_buff *skb,
+ struct udplitehdr *uh,
+ unsigned short clen, u32 saddr, u32 daddr)
+{
+ /* In UDPv4 a zero checksum means that the transmitter generated no
+ * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets
+ * with a zero checksum field are illegal. */
+ if (uh->check == 0) {
+ return 1;
+ } else if (skb->ip_summed == CHECKSUM_HW) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (csum_tcpudp_magic
+ (saddr, daddr, clen, IPPROTO_UDPLITE, skb->csum) == 0)
+ return 0;
+ LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: hw csum failure.\n");
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY)
+ skb->csum =
+ csum_tcpudp_nofold(saddr, daddr, clen, IPPROTO_UDPLITE, 0);
+ return 0;
+}
+
+/**
+ * udplite_rcv - receive packets
+ *
+ * This code is modelled after the one in udp.c, but heavily modified
+ * with regard to the differences in computing the checksum.
+ */
+int udplite_rcv(struct sk_buff *skb)
+{
+ struct sock *sk;
+ struct udplitehdr *uh;
+ u32 saddr = skb->nh.iph->saddr,
+ daddr = skb->nh.iph->daddr;
+ int len = skb->len; /* total packet length */
+ unsigned short clen; /* csum coverage length */
+ struct udplite_sock *up;
+ struct rtable *rt = (struct rtable *)skb->dst;
+
+ /*
+ * Validate the packet and the UDP-Lite length.
+ */
+ if (!pskb_may_pull(skb, sizeof(struct udplitehdr)))
+ goto drop; /* No header. */
+
+ uh = skb->h.ulh;
+ sk = udplite_v4_lookup(saddr, uh->source, daddr, uh->dest,
+ skb->dev->ifindex);
+ up = udplite_sk(sk);
+ clen = ntohs(uh->checklen);
+
+ if (sk == NULL)
+ goto no_port;
+
+ if (len < sizeof(*uh)) /* Unlike udp.c, pskb_trim makes */
+ goto short_packet; /* no sense, since len = skb->len */
+
+ if (clen == 0) /* Indicates that full coverage is required. */
+ clen = len;
+ else if (clen < 8 || /* Illegal coverage length, 8 is minimum. */
+ clen > len) /* Coverage length exceeds datagram length. */
+ goto csumlen_error;
+ else if (clen < len) /* Normal: partial coverage required. */
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INDATAGRAMS_PARTIAL_CHECK);
+
+ if (up->pcflag & UDPLITE_RECV_CHCKFLAG) { /* min. coverage was set */
+ /*
+ * MIB statistics other than incrementing the error count are
+ * disabled for the following two types of errors: these depend
+ * on the application settings, not on the functioning of the
+ * protocol stack as such.
+ *
+ * RFC 3828 here recommends (sec 3.3): "There should also be a
+ * way ... to ... at least let the receiving application block
+ * delivery of packets with coverage values less than a value
+ * provided by the application."
+ */
+ if (clen < len) {
+ if (up->pcrlen == 0) {
+ LIMIT_NETDEBUG(KERN_WARNING
+ "UDPLITE: partial coverage %d, but "
+ "full coverage %d requ. "
+ "(IP %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d)\n",
+ clen, len, NIPQUAD(saddr),
+ ntohs(uh->source), NIPQUAD(daddr),
+ ntohs(uh->dest));
+ goto drop;
+ }
+ } else if (clen < up->pcrlen) { /* here: clen=len */
+ LIMIT_NETDEBUG(KERN_WARNING
+ "UDPLITE: coverage %d too small, need min. %d "
+ "(IP %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d)\n", clen,
+ up->pcrlen, NIPQUAD(saddr), ntohs(uh->source),
+ NIPQUAD(daddr), ntohs(uh->dest));
+ goto drop;
+ }
+ }
+ /* Compute initial checksum, including pseudo-header. */
+ if (udplite_checksum_init(skb, uh, len, saddr, daddr) < 0)
+ goto csum_error;
+
+ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+ return udplite_v4_mcast_deliver(skb, uh, saddr, daddr);
+
+ if (sk != NULL) {
+ int ret = udplite_queue_rcv_skb(sk, skb);
+ sock_put(sk);
+
+ /*
+ * A return value > 0 means to resubmit the input, but
+ * it wants the return to be -protocol, or 0.
+ *
+ */
+ if (ret > 0)
+ return -ret;
+ return 0;
+ }
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto drop;
+
+ /* No socket. Drop packet silently, if checksum is wrong */
+ if (udplite_checksum_complete(skb))
+ goto csum_error;
+
+no_port:
+ /*
+ * Got a UDP-Lite packet to a port to which we don't wanna listen.
+ * Ignore it and increment the count of `NoPort' messages.
+ */
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_NOPORTS);
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+ kfree_skb(skb);
+ return (0);
+
+short_packet:
+ LIMIT_NETDEBUG(KERN_NOTICE "UDPLITE: short packet, %d/%d bytes "
+ "(%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n)\n",
+ len, clen, NIPQUAD(saddr), ntohs(uh->source),
+ NIPQUAD(daddr), ntohs(uh->dest) );
+ goto drop;
+
+csumlen_error:
+ /*
+ * Coverage length violates RFC 3828: log and discard silently.
+ */
+ LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad csum coverage %d "
+ "(%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d, len %d)\n",
+ clen, NIPQUAD(saddr), ntohs(uh->source),
+ NIPQUAD(daddr), ntohs(uh->dest), len);
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS_CHECKSUM_COVERAGE);
+ goto drop;
+
+csum_error:
+ /*
+ * Checksum violated: proceed as per RFC 1122/3828.
+ */
+ LIMIT_NETDEBUG(KERN_DEBUG "UDPLITE: bad checksum "
+ "(%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d)\n", NIPQUAD(saddr),
+ ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest));
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS_CHECKSUMMING);
+
+drop:
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS);
+ kfree_skb(skb);
+ return (0);
+}
+
+static int udplite_destroy_sock(struct sock *sk)
+{
+ lock_sock(sk);
+ udplite_flush_pending_frames(sk);
+ release_sock(sk);
+ return 0;
+}
+
+/**
+ * udplite_setsocktopt - set UDP-Lite socket options
+ *
+ * This function is very similar to udp.c, the only difference being
+ * the two new socket options for setting receiver/sender csum coverage.
+ */
+static int udplite_setsockopt(struct sock *sk,
+ int level,
+ int optname, char __user * optval, int optlen)
+{
+ struct udplite_sock *up = udplite_sk(sk);
+ int val;
+ int err = 0;
+
+ if (level != SOL_UDPLITE)
+ return ip_setsockopt(sk, level, optname, optval, optlen);
+
+ if (optlen < sizeof(int))
+ return -EINVAL;
+
+ if (get_user(val, (int __user *)optval))
+ return -EFAULT;
+
+ switch (optname) {
+ case UDPLITE_CORK:
+ if (val != 0) {
+ up->corkflag = 1;
+ } else {
+ up->corkflag = 0;
+ lock_sock(sk);
+ udplite_push_pending_frames(sk, up);
+ release_sock(sk);
+ }
+ break;
+
+ case UDPLITE_ENCAP:
+ switch (val) {
+ case 0:
+ case UDP_ENCAP_ESPINUDP:
+ case UDP_ENCAP_ESPINUDP_NON_IKE:
+ up->encap_type = val;
+ break;
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+ break;
+ /* Sender sets actual checksum coverage length via this option.
+ The case coverage > packet length is handled by send module. */
+ case UDPLITE_SOCKOPT_SEND_CSCOV:
+ if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
+ val = 8;
+ up->pcslen = val;
+ up->pcflag |= UDPLITE_SEND_CHCKFLAG;
+ break;
+
+ /* The receiver specifies a minimum checksum coverage value. To make
+ * sense, this should be set to 8 (as done below). */
+ case UDPLITE_SOCKOPT_RECV_CSCOV:
+ if (val != 0 && val < 8) /* Disallow silly minimal values. */
+ val = 8;
+ up->pcrlen = val;
+ up->pcflag |= UDPLITE_RECV_CHCKFLAG;
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ };
+
+ return err;
+}
+
+/**
+ * udplite_getsockopt - as per udp.c
+ */
+static int udplite_getsockopt(struct sock *sk, int level, int optname,
+ char __user * optval, int __user * optlen)
+{
+ struct udplite_sock *up = udplite_sk(sk);
+ int val, len;
+
+ if (level != SOL_UDPLITE)
+ return ip_getsockopt(sk, level, optname, optval, optlen);
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ len = min_t(unsigned int, len, sizeof(int));
+
+ if (len < 0)
+ return -EINVAL;
+
+ switch (optname) {
+ case UDPLITE_CORK:
+ val = up->corkflag;
+ break;
+
+ case UDPLITE_ENCAP:
+ val = up->encap_type;
+ break;
+
+ case UDPLITE_SOCKOPT_SEND_CSCOV:
+ val = up->pcslen;
+ break;
+
+ case UDPLITE_SOCKOPT_RECV_CSCOV:
+ val = up->pcrlen;
+ break;
+
+ default:
+ return -ENOPROTOOPT;
+ };
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, &val, len))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * udplite_poll - wait for a UDP-Lite event (agrees mostly with udp.c)
+ *
+ * @file: file struct
+ * @sock: socket
+ * @wait: poll table
+ *
+ * This is same as datagram poll, except for the special case of
+ * blocking sockets. If application is using a blocking fd
+ * and a packet with checksum error is in the queue;
+ * then it could get return from select indicating data available
+ * but then block when reading it. Add special case code
+ * to work around these arguably broken applications.
+ */
+
+unsigned int udplite_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
+{
+ unsigned int mask = datagram_poll(file, sock, wait);
+ struct sock *sk = sock->sk;
+
+ /* Check for false positives due to checksum errors */
+ if ((mask & POLLRDNORM) &&
+ !(file->f_flags & O_NONBLOCK) &&
+ !(sk->sk_shutdown & RCV_SHUTDOWN)) {
+ struct sk_buff_head *rcvq = &sk->sk_receive_queue;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&rcvq->lock);
+ while ((skb = skb_peek(rcvq)) != NULL) {
+ if (udplite_checksum_complete(skb)) {
+ /* checksum invalidated */
+ UDPLITE_INC_STATS_BH
+ (UDPLITE_MIB_INERRORS_CHECKSUMMING);
+ UDPLITE_INC_STATS_BH(UDPLITE_MIB_INERRORS);
+ __skb_unlink(skb, rcvq);
+ kfree_skb(skb);
+ } else {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ break;
+ }
+ }
+ spin_unlock_bh(&rcvq->lock);
+
+ if (skb == NULL) /* Nothing to see, move along. */
+ mask &= ~(POLLIN | POLLRDNORM);
+ }
+
+ return mask;
+
+}
+
+
+struct proto udplite_prot = {
+ .name = "UDPLITE",
+ .owner = THIS_MODULE,
+ .close = udplite_close,
+ .connect = ip4_datagram_connect,
+ .disconnect = udplite_disconnect,
+ .ioctl = udplite_ioctl,
+ .destroy = udplite_destroy_sock,
+ .setsockopt = udplite_setsockopt,
+ .getsockopt = udplite_getsockopt,
+ .sendmsg = udplite_sendmsg,
+ .recvmsg = udplite_recvmsg,
+ .sendpage = udplite_sendpage,
+ .backlog_rcv = udplite_queue_rcv_skb,
+ .hash = udplite_v4_hash,
+ .unhash = udplite_v4_unhash,
+ .get_port = udplite_v4_get_port,
+ .obj_size = sizeof(struct udplite_sock),
+};
+
+/*-------------------------------------------------------------------------
+ * Operations related to the proc filesystem. These are are all taken
+ * (modulo name change) from udp.c
+ *-------------------------------------------------------------------------*/
+#ifdef CONFIG_PROC_FS
+static struct sock *udplite_get_first(struct seq_file *seq)
+{
+ struct sock *sk;
+ struct udplite_iter_state *state = seq->private;
+
+ for (state->bucket = 0; state->bucket < UDPLITE_HTABLE_SIZE;
+ ++state->bucket) {
+ struct hlist_node *node;
+ sk_for_each(sk, node, &udplite_hash[state->bucket]) {
+ if (sk->sk_family == state->family)
+ goto found;
+ }
+ }
+ sk = NULL;
+found:
+ return sk;
+}
+
+static struct sock *udplite_get_next(struct seq_file *seq, struct sock *sk)
+{
+ struct udplite_iter_state *state = seq->private;
+
+ do {
+ sk = sk_next(sk);
+try_again:
+ ;
+ } while (sk && sk->sk_family != state->family);
+
+ if (!sk && ++state->bucket < UDPLITE_HTABLE_SIZE) {
+ sk = sk_head(&udplite_hash[state->bucket]);
+ goto try_again;
+ }
+ return sk;
+}
+
+static struct sock *udplite_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct sock *sk = udplite_get_first(seq);
+
+ if (sk)
+ while (pos && (sk = udplite_get_next(seq, sk)) != NULL)
+ --pos;
+ return pos? NULL : sk;
+}
+
+static void *udplite_seq_start(struct seq_file *seq, loff_t * pos)
+{
+ read_lock(&udplite_hash_lock);
+ return *pos ? udplite_get_idx(seq, *pos - 1) : (void *)1;
+}
+
+static void *udplite_seq_next(struct seq_file *seq, void *v, loff_t * pos)
+{
+ struct sock *sk;
+
+ if (v == (void *)1)
+ sk = udplite_get_idx(seq, 0);
+ else
+ sk = udplite_get_next(seq, v);
+
+ ++*pos;
+ return sk;
+}
+
+static void udplite_seq_stop(struct seq_file *seq, void *v)
+{
+ read_unlock(&udplite_hash_lock);
+}
+
+static int udplite_seq_open(struct inode *inode, struct file *file)
+{
+ struct udplite_seq_afinfo *afinfo = PDE(inode)->data;
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct udplite_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+ memset(s, 0, sizeof(*s));
+ s->family = afinfo->family;
+ s->seq_ops.start = udplite_seq_start;
+ s->seq_ops.next = udplite_seq_next;
+ s->seq_ops.show = afinfo->seq_show;
+ s->seq_ops.stop = udplite_seq_stop;
+
+ rc = seq_open(file, &s->seq_ops);
+ if (rc)
+ goto out_kfree;
+
+ seq = file->private_data;
+ seq->private = s;
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+}
+
+/* ------------------------------------------------------------------------ */
+int udplite_proc_register(struct udplite_seq_afinfo *afinfo)
+{
+ struct proc_dir_entry *p;
+ int rc = 0;
+
+ if (!afinfo)
+ return -EINVAL;
+ afinfo->seq_fops->owner = afinfo->owner;
+ afinfo->seq_fops->open = udplite_seq_open;
+ afinfo->seq_fops->read = seq_read;
+ afinfo->seq_fops->llseek = seq_lseek;
+ afinfo->seq_fops->release = seq_release_private;
+
+ p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops);
+ if (p)
+ p->data = afinfo;
+ else
+ rc = -ENOMEM;
+ return rc;
+}
+
+void udplite_proc_unregister(struct udplite_seq_afinfo *afinfo)
+{
+ if (!afinfo)
+ return;
+ proc_net_remove(afinfo->name);
+ memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
+}
+
+
+static void udplite4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
+{
+ struct inet_sock *inet = inet_sk(sp);
+ unsigned int dest = inet->daddr;
+ unsigned int src = inet->rcv_saddr;
+ __u16 destp = ntohs(inet->dport);
+ __u16 srcp = ntohs(inet->sport);
+
+ sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
+ bucket, src, srcp, dest, destp, sp->sk_state,
+ atomic_read(&sp->sk_wmem_alloc),
+ atomic_read(&sp->sk_rmem_alloc),
+ 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
+ atomic_read(&sp->sk_refcnt), sp);
+}
+
+static int udplite4_seq_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "%-127s\n",
+ " sl local_address rem_address st tx_queue "
+ "rx_queue tr tm->when retrnsmt uid timeout "
+ "inode");
+ else {
+ char tmpbuf[129];
+ struct udplite_iter_state *state = seq->private;
+
+ udplite4_format_sock(v, tmpbuf, state->bucket);
+ seq_printf(seq, "%-127s\n", tmpbuf);
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+static struct file_operations udplite4_seq_fops;
+
+static struct udplite_seq_afinfo udplite4_seq_afinfo = {
+ .owner = THIS_MODULE,
+ .name = "udplite",
+ .family = AF_INET,
+ .seq_show = udplite4_seq_show,
+ .seq_fops = &udplite4_seq_fops,
+};
+
+
+int __init udplite4_proc_init(void)
+{
+ return udplite_proc_register(&udplite4_seq_afinfo);
+}
+
+void udplite4_proc_exit(void)
+{
+ udplite_proc_unregister(&udplite4_seq_afinfo);
+}
+#endif /* CONFIG_PROC_FS */
+/* ------------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(udplite_disconnect);
+EXPORT_SYMBOL(udplite_hash);
+EXPORT_SYMBOL(udplite_hash_lock);
+EXPORT_SYMBOL(udplite_ioctl);
+EXPORT_SYMBOL(udplite_port_rover);
+EXPORT_SYMBOL(udplite_prot);
+EXPORT_SYMBOL(udplite_sendmsg);
+EXPORT_SYMBOL(udplite_poll);
+
+#ifdef CONFIG_PROC_FS
+EXPORT_SYMBOL(udplite_proc_register);
+EXPORT_SYMBOL(udplite_proc_unregister);
+#endif
^ permalink raw reply
* [PATCH 5/5] ehea: makefile and Kconfig
From: Jan-Bernd Themann @ 2006-06-08 9:56 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/Kconfig | 6 ++++++
drivers/net/ehea/Makefile | 7 +++++++
2 files changed, 13 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/Makefile 2006-06-08 01:58:28.839212488 -0700
@@ -0,0 +1,7 @@
+#
+# Makefile for the eHEA ethernet device driver for IBM eServer System p
+#
+
+ehea_mod-objs = ehea_main.o ehea_phyp.o ehea_qmr.o ehea_ethtool.o ehea_phyp.o
+obj-$(CONFIG_EHEA) += ehea_mod.o
+
--- linux-2.6.16-rc5-orig/drivers/net/ehea/Kconfig 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/Kconfig 2006-06-08 01:58:28.842212032 -0700
@@ -0,0 +1,6 @@
+config EHEA
+ tristate "eHEA Ethernet support"
+ depends on IBMEBUS
+ ---help---
+ This driver supports the IBM pSeries ethernet adapter
+
^ permalink raw reply
* [PATCH 4/5] ehea: main header files
From: Jan-Bernd Themann @ 2006-06-08 9:55 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/ehea.h | 434 +++++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_hw.h | 319 +++++++++++++++++++++++++++++++++
2 files changed, 753 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea.h 2006-06-08 01:58:29.611229144 -0700
@@ -0,0 +1,434 @@
+/*
+ * linux/drivers/net/ehea/ehea.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#ifndef __EHEA_H__
+#define __EHEA_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/kthread.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <asm/ibmebus.h>
+#include <asm/of_device.h>
+#include <asm/abs_addr.h>
+#include <asm/semaphore.h>
+#include <asm/current.h>
+#include <asm/io.h>
+
+
+#define EHEA_DRIVER_NAME "IBM eHEA"
+#define EHEA_DRIVER_VERSION "EHEA_0002"
+
+/* #define EHEA_CQE_TIMER */
+ #define EHEA_ADDITIONAL_STATISTICS
+
+#ifdef EHEA_SMALL_QUEUES
+#define EHEA_MAX_CQE_COUNT 1020
+#define EHEA_MAX_ENTRIES_SQ 1020
+#define EHEA_MAX_ENTRIES_RQ1 4080
+#define EHEA_MAX_ENTRIES_RQ2 1020
+#define EHEA_MAX_ENTRIES_RQ3 1020
+#define EHEA_SWQE_REFILL_TH 100
+#else
+#define EHEA_MAX_CQE_COUNT 32000
+#define EHEA_MAX_ENTRIES_SQ 16000
+#define EHEA_MAX_ENTRIES_RQ1 32080
+#define EHEA_MAX_ENTRIES_RQ2 4020
+#define EHEA_MAX_ENTRIES_RQ3 4020
+#define EHEA_SWQE_REFILL_TH 1000
+#endif
+
+#define EHEA_MAX_ENTRIES_EQ 20
+
+#define EHEA_SG_SQ 2
+#define EHEA_SG_RQ1 1
+#define EHEA_SG_RQ2 0
+#define EHEA_SG_RQ3 0
+
+#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frame */
+#define EHEA_LL_PKT_SIZE 256
+
+/* Send completion signaling */
+#define EHEA_SIG_IV 1000
+#define EHEA_SIG_IV_LONG 4
+#define EHEA_SQ_HL_TRIGGER 5000
+
+/* Protection Domain Identifier */
+#define EHEA_PD_ID 0xaabcdeff
+
+#define EHEA_RQ2_THRESHOLD 1
+#define EHEA_RQ3_THRESHOLD 5
+
+#define EHEA_SPEED_10G 10000
+#define EHEA_SPEED_1G 1000
+#define EHEA_SPEED_100M 100
+#define EHEA_SPEED_10M 10
+
+/* Broadcast/Multicast registration types */
+#define EHEA_BCMC_SCOPE_ALL 0x08
+#define EHEA_BCMC_SCOPE_SINGLE 0x00
+#define EHEA_BCMC_MULTICAST 0x04
+#define EHEA_BCMC_BROADCAST 0x00
+#define EHEA_BCMC_UNTAGGED 0x02
+#define EHEA_BCMC_TAGGED 0x00
+#define EHEA_BCMC_VLANID_ALL 0x01
+#define EHEA_BCMC_VLANID_SINGLE 0x00
+
+/* Use this define to kmallocate PHYP control blocks */
+#define H_CB_ALIGNMENT 4096
+
+#define EHEA_PAGESHIFT 12
+#define EHEA_PAGESIZE 4096UL
+#define EHEA_PT_ENTRIES 512UL
+#define EHEA_CACHE_LINE 128
+
+#define EHEA_ENABLE 1
+#define EHEA_DISABLE 0
+
+void ehea_set_ethtool_ops(struct net_device *netdev);
+
+#ifndef KEEP_EDEBS_BELOW
+#define KEEP_EDEBS_BELOW 8
+#endif
+
+extern int ehea_trace_level;
+extern struct ehea_adapter *adapter_global;
+
+#ifdef EHEA_NO_EDEB
+#define EDEB_P_GENERIC(level, idstring, format, args...) \
+ while (0 == 1) { \
+ if(unlikely (level <= ehea_trace_level)) { \
+ printk("%s " idstring " "format "\n", \
+ __func__, ##args); \
+ } \
+ } \
+
+#else
+
+#define EDEB_P_GENERIC(level,idstring,format,args...) \
+if (level < KEEP_EDEBS_BELOW) { \
+ do { \
+ if(unlikely (level <= ehea_trace_level)) { \
+ printk("%s " idstring " "format "\n", \
+ __func__, ##args); \
+ } \
+ } while (1 == 0); \
+}
+#endif
+
+#define EDEB(level, format, args...) \
+ EDEB_P_GENERIC(level, "", format, ##args)
+
+#define EDEB_ERR(level, format, args...) \
+ EDEB_P_GENERIC(level, "EHEA_ERROR", format, ##args)
+
+#define EDEB_EN(level, format, args...) \
+ EDEB_P_GENERIC(level, ">>>", format, ##args)
+
+#define EDEB_EX(level, format, args...) \
+ EDEB_P_GENERIC(level, "<<<", format, ##args)
+
+#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
+#define EHEA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
+#define EHEA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
+#define EHEA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
+#define EHEA_BMASK_SET(mask, value) \
+ ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
+#define EHEA_BMASK_GET(mask, value) \
+ (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
+
+extern void exit(int);
+
+#define EDEB_DMP(level, adr, len, format, args...) \
+if (level < KEEP_EDEBS_BELOW) { \
+ if(unlikely (level <= ehea_trace_level)) { \
+ do { \
+ unsigned int x; \
+ unsigned int l = (unsigned int)(len); \
+ unsigned char *deb = (unsigned char*)(adr); \
+ for (x = 0; x < l; x += 16) { \
+ EDEB(level, format " adr=%p ofs=%04x %016lx %016lx", \
+ ##args, deb, x, *((u64 *)&deb[0]), \
+ *((u64 *)&deb[8])); \
+ deb += 16; \
+ } \
+ } while (0); \
+ } \
+}
+
+
+/*
+ * struct generic ehea page
+ */
+struct ipz_page {
+ u8 entries[PAGE_SIZE];
+};
+
+/*
+ * struct generic queue in linux kernel virtual memory
+ */
+struct ipz_queue {
+ u64 current_q_offset; /* current queue entry */
+ struct ipz_page **queue_pages; /* array of pages belonging to queue */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state; /* toggle flag - per page */
+ u32 reserved; /* 64 bit alignment */
+};
+
+
+/*
+ * h_galpa:
+ * for pSeries this is a 64bit memory address where
+ * I/O memory is mapped into CPU address space
+ */
+
+struct h_galpa {
+ u64 fw_handle;
+};
+
+struct h_galpas {
+ struct h_galpa kernel; /* kernel space accessible resource,
+ set to 0 if unused */
+ struct h_galpa user; /* user space accessible resource
+ set to 0 if unused */
+ u32 pid; /* PID of userspace galpa checking */
+};
+
+struct ehea_qp;
+struct ehea_cq;
+struct ehea_eq;
+struct ehea_port;
+struct ehea_av;
+
+struct ehea_qp_init_attr {
+ /* input parameter */
+ u32 qp_token;
+ u8 low_lat_rq1;
+ u8 signalingtype;
+ u8 rq_count;
+ u8 eqe_gen;
+ u16 max_nr_send_wqes;
+ u16 max_nr_rwqes_rq1;
+ u16 max_nr_rwqes_rq2;
+ u16 max_nr_rwqes_rq3;
+ u8 wqe_size_enc_sq;
+ u8 wqe_size_enc_rq1;
+ u8 wqe_size_enc_rq2;
+ u8 wqe_size_enc_rq3;
+ u8 swqe_imm_data_len;
+ u16 port_nr;
+ u16 rq2_threshold;
+ u16 rq3_threshold;
+ u64 send_cq_handle;
+ u64 recv_cq_handle;
+ u64 aff_eq_handle;
+
+ /* output parameter */
+ u32 qp_nr;
+ u16 act_nr_send_wqes;
+ u16 act_nr_rwqes_rq1;
+ u16 act_nr_rwqes_rq2;
+ u16 act_nr_rwqes_rq3;
+ u8 act_wqe_size_enc_sq;
+ u8 act_wqe_size_enc_rq1;
+ u8 act_wqe_size_enc_rq2;
+ u8 act_wqe_size_enc_rq3;
+ u32 nr_sq_pages;
+ u32 nr_rq1_pages;
+ u32 nr_rq2_pages;
+ u32 nr_rq3_pages;
+ u32 liobn_sq;
+ u32 liobn_rq1;
+ u32 liobn_rq2;
+ u32 liobn_rq3;
+};
+
+struct ehea_eq_attr {
+ u32 type;
+ u32 max_nr_of_eqes;
+ u8 eqe_gen;
+ u64 eq_handle;
+ u32 act_nr_of_eqes;
+ u32 nr_pages;
+ u32 ist1;
+ u32 ist2;
+ u32 ist3;
+ u32 ist4;
+};
+
+struct ehea_eq {
+ struct ipz_queue ipz_queue;
+ u64 ipz_eq_handle;
+ struct h_galpas galpas;
+ spinlock_t spinlock;
+ struct ehea_eq_attr attr;
+};
+
+struct ehea_qp {
+ struct ehea_adapter *adapter;
+ u64 ipz_qp_handle; /* QP handle for h-calls */
+ struct ipz_queue ipz_squeue;
+ struct ipz_queue ipz_rqueue1;
+ struct ipz_queue ipz_rqueue2;
+ struct ipz_queue ipz_rqueue3;
+ struct h_galpas galpas;
+ struct ehea_qp_init_attr init_attr;
+};
+
+struct ehea_cq_attr {
+ /* input parameter */
+ u32 max_nr_of_cqes;
+ u32 cq_token;
+ u64 eq_handle;
+
+ /* output parameter */
+ u32 act_nr_of_cqes;
+ u32 nr_pages;
+};
+
+struct ehea_cq {
+ struct ehea_adapter *adapter;
+ u64 ipz_cq_handle;
+ struct ipz_queue ipz_queue;
+ struct h_galpas galpas;
+ struct ehea_cq_attr attr;
+};
+
+struct ehea_port_res {
+ spinlock_t xmit_lock;
+ struct ehea_port *port;
+ struct ehea_qp *qp;
+ struct ehea_cq *send_cq;
+ struct ehea_cq *recv_cq;
+ struct ehea_eq *send_eq;
+ struct ehea_eq *recv_eq;
+ struct ehea_eq *qp_eq;
+ spinlock_t send_lock;
+ struct sk_buff **skb_arr_rq1;
+ struct sk_buff **skb_arr_rq2;
+ struct sk_buff **skb_arr_rq3;
+ struct sk_buff **skb_arr_sq;
+ int skb_arr_rq1_len;
+ int skb_arr_rq2_len;
+ int skb_arr_rq3_len;
+ int skb_arr_sq_len;
+ int skb_rq2_index;
+ int skb_rq3_index;
+ int skb_sq_index;
+ spinlock_t netif_queue;
+ atomic_t swqe_avail;
+ int swqe_ll_count;
+ int swqe_count;
+ struct tasklet_struct send_comp_task;
+ spinlock_t recv_lock;
+ u32 swqe_id_counter;
+ struct timer_list timer; /* polling mode, no interrupts */
+ struct timer_list skb_timer; /* skb cleanup timer */
+};
+
+
+struct ehea_adapter {
+
+ u64 handle;
+ u8 num_ports;
+ struct ehea_port *port[16];
+ struct ehea_eq *neq;
+ struct tasklet_struct neq_tasklet;
+ u32 lkey;
+ u32 pd;
+ u64 mr_handle;
+ u64 max_mc_mac;
+
+};
+
+inline static u32 ehea_get_lkey(struct ehea_adapter *adapter, void *addr)
+{
+ EDEB(8, "ehea_adapter=%p, addr=%p", adapter, addr);
+ EDEB(8, "Lkey returned: %X", adapter->lkey);
+ return adapter->lkey;
+}
+
+struct ehea_mc_list {
+ struct list_head list;
+ u64 macaddr;
+};
+
+struct port_state {
+ int poll_max_processed;
+ int poll_receive_errors;
+ int ehea_poll;
+ int queue_stopped;
+ int min_swqe_avail;
+ u64 sqc_stop_sum;
+ int pkt_send;
+ int pkt_xmit;
+ int send_tasklet;
+ int nwqe;
+};
+
+struct ehea_port {
+ struct ehea_adapter *adapter; /* adapter that owns this port */
+ struct net_device *netdev;
+ struct net_device_stats stats;
+ struct port_state p_state;
+ struct ehea_port_res port_res[1];
+ struct device_node *of_dev_node; /* Open Firmware Device Node */
+ struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
+ struct vlan_group * vgrp;
+ int allmulti; /* Indicates IFF_ALLMULTI state */
+ int promisc; /* Indicates IFF_PROMISC state */
+
+ char int_recv_name[20];
+ char int_send_name[20];
+ char int_aff_name[20];
+
+ int kernel_l_key;
+ u64 mac_addr;
+ u32 logical_port_id;
+ u32 port_speed;
+ u8 full_duplex;
+ u8 num_def_qps;
+};
+
+
+#endif /* __EHEA_H__ */
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_hw.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_hw.h 2006-06-08 01:58:28.844211728 -0700
@@ -0,0 +1,319 @@
+/*
+ * linux/drivers/net/ehea/ehea_hw.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#ifndef __EHEA_HW_H__
+#define __EHEA_HW_H__
+
+#define QPX_SQA_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48,63)
+
+#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
+
+struct ehea_qptemm {
+ u64 qpx_hcr;
+ u64 qpx_c;
+ u64 qpx_herr;
+ u64 qpx_aer;
+ u64 qpx_sqa;
+ u64 qpx_sqc;
+ u64 qpx_rq1a;
+ u64 qpx_rq1c;
+ u64 qpx_st;
+ u64 qpx_aerr;
+ u64 qpx_tenure;
+ u64 qpx_reserved1[(0x098 - 0x058) / 8];
+ u64 qpx_portp;
+ u64 qpx_reserved2[(0x100 - 0x0A0) / 8];
+ u64 qpx_t;
+ u64 qpx_sqhp;
+ u64 qpx_sqptp;
+ u64 qpx_reserved3[(0x140 - 0x118) / 8];
+ u64 qpx_sqwsize;
+ u64 qpx_reserved4[(0x170 - 0x148) / 8];
+ u64 qpx_sqsize;
+ u64 qpx_reserved5[(0x1B0 - 0x178) / 8];
+ u64 qpx_sigt;
+ u64 qpx_wqecnt;
+ u64 qpx_rq1hp;
+ u64 qpx_rq1ptp;
+ u64 qpx_rq1size;
+ u64 qpx_reserved6[(0x220 - 0x1D8) / 8];
+ u64 qpx_rq1wsize;
+ u64 qpx_reserved7[(0x240 - 0x228) / 8];
+ u64 qpx_pd;
+ u64 qpx_scqn;
+ u64 qpx_rcqn;
+ u64 qpx_aeqn;
+ u64 reserved49;
+ u64 qpx_ram;
+ u64 qpx_reserved8[(0x300 - 0x270) / 8];
+ u64 qpx_rq2a;
+ u64 qpx_rq2c;
+ u64 qpx_rq2hp;
+ u64 qpx_rq2ptp;
+ u64 qpx_rq2size;
+ u64 qpx_rq2wsize;
+ u64 qpx_rq2th;
+ u64 qpx_rq3a;
+ u64 qpx_rq3c;
+ u64 qpx_rq3hp;
+ u64 qpx_rq3ptp;
+ u64 qpx_rq3size;
+ u64 qpx_rq3wsize;
+ u64 qpx_rq3th;
+ u64 qpx_lpn;
+ u64 qpx_reserved9[(0x400 - 0x378) / 8];
+ u64 reserved_ext[(0x500 - 0x400) / 8];
+ u64 reserved2[(0x1000 - 0x500) / 8];
+};
+
+#define MRx_HCR_LPARID_VALID EHEA_BMASK_IBM(0, 0)
+
+#define MRMWMM_OFFSET(x) offsetof(struct ehea_mrmwmm, x)
+
+struct ehea_mrmwmm {
+ u64 mrx_hcr;
+ u64 mrx_c;
+ u64 mrx_herr;
+ u64 mrx_aer;
+ u64 mrx_pp;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ u64 reserved4[(0x200 - 0x40) / 8];
+ u64 mrx_ctl[64];
+};
+
+#define QPEDMM_OFFSET(x) offsetof(struct ehea_qpedmm, x)
+
+struct ehea_qpedmm {
+
+ u64 reserved0[(0x400) / 8];
+ u64 qpedx_phh;
+ u64 qpedx_ppsgp;
+ u64 qpedx_ppsgu;
+ u64 qpedx_ppdgp;
+ u64 qpedx_ppdgu;
+ u64 qpedx_aph;
+ u64 qpedx_apsgp;
+ u64 qpedx_apsgu;
+ u64 qpedx_apdgp;
+ u64 qpedx_apdgu;
+ u64 qpedx_apav;
+ u64 qpedx_apsav;
+ u64 qpedx_hcr;
+ u64 reserved1[4];
+ u64 qpedx_rrl0;
+ u64 qpedx_rrrkey0;
+ u64 qpedx_rrva0;
+ u64 reserved2;
+ u64 qpedx_rrl1;
+ u64 qpedx_rrrkey1;
+ u64 qpedx_rrva1;
+ u64 reserved3;
+ u64 qpedx_rrl2;
+ u64 qpedx_rrrkey2;
+ u64 qpedx_rrva2;
+ u64 reserved4;
+ u64 qpedx_rrl3;
+ u64 qpedx_rrrkey3;
+ u64 qpedx_rrva3;
+};
+
+#define CQX_FECADDER EHEA_BMASK_IBM(32, 63)
+#define CQX_FEC_CQE_CNT EHEA_BMASK_IBM(32, 63)
+#define CQX_N1_GENERATE_COMP_EVENT EHEA_BMASK_IBM(0, 0)
+#define CQX_EP_EVENT_PENDING EHEA_BMASK_IBM(0, 0)
+
+#define CQTEMM_OFFSET(x) offsetof(struct ehea_cqtemm, x)
+
+struct ehea_cqtemm {
+ u64 cqx_hcr;
+ u64 cqx_c;
+ u64 cqx_herr;
+ u64 cqx_aer;
+ u64 cqx_ptp;
+ u64 cqx_tp;
+ u64 cqx_fec;
+ u64 cqx_feca;
+ u64 cqx_ep;
+ u64 cqx_eq;
+ u64 reserved1;
+ u64 cqx_n0;
+ u64 cqx_n1;
+ u64 reserved2[(0x1000 - 0x60) / 8];
+};
+
+#define EQTEMM_OFFSET(x) offsetof(struct ehea_eqtemm, x)
+
+struct ehea_eqtemm {
+ u64 EQx_HCR;
+ u64 EQx_C;
+ u64 EQx_HERR;
+ u64 EQx_AER;
+ u64 EQx_PTP;
+ u64 EQx_TP;
+ u64 EQx_SSBA;
+ u64 EQx_PSBA;
+ u64 EQx_CEC;
+ u64 EQx_MEQL;
+ u64 EQx_XISBI;
+ u64 EQx_XISC;
+ u64 EQx_IT;
+};
+
+static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
+{
+ u64 addr = galpa.fw_handle + offset;
+ u64 out;
+ EDEB_EN(7, "addr=%lx offset=%x ", addr, offset);
+ out = *(volatile u64 *)addr;
+ EDEB_EX(7, "addr=%lx value=%lx", addr, out);
+ return out;
+};
+
+static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
+{
+ u64 addr = galpa.fw_handle + offset;
+ EDEB_EN(7, "addr=%lx offset=%x value=%lx", addr, offset,
+ value);
+ *(u64 *) addr = value;
+ hipz_galpa_load(galpa, offset); /* synchronize explicitly to ehea */
+ EDEB_EX(7, "");
+};
+
+static inline void hipz_galpa_store_acc(struct h_galpa galpa, u32 offset,
+ u64 value)
+{
+ u64 addr = galpa.fw_handle + offset;
+ EDEB(7, "Accelerated store: addr=%lx offset=%x value=%lx",
+ addr, offset, value);
+ *(u64 *) addr = value;
+};
+
+#define hipz_galpa_store_eq(gal, offset, value)\
+ hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value)
+#define hipz_galpa_load_eq(gal, offset)\
+ hipz_galpa_load(gal, EQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_cq(gal, offset, value)\
+ hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value)
+#define hipz_galpa_load_cq(gal, offset)\
+ hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qp(gal, offset, value)\
+ hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
+#define hipz_galpa_load_qp(gal, offset)\
+ hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qped(gal, offset, value)\
+ hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value)
+#define hipz_galpa_load_qped(gal, offset)\
+ hipz_galpa_load(gal, QPEDMM_OFFSET(offset))
+
+#define hipz_galpa_store_mrmw(gal, offset, value)\
+ hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value)
+#define hipz_galpa_load_mrmw(gal, offset)\
+ hipz_galpa_load(gal, MRMWMM_OFFSET(offset))
+
+#define hipz_galpa_store_base(gal, offset, value)\
+ hipz_galpa_store(gal, HCAGR_OFFSET(offset), value)
+#define hipz_galpa_load_base(gal, offset)\
+ hipz_galpa_load(gal, HCAGR_OFFSET(offset))
+
+static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal = qp->galpas.kernel;
+ EDEB_EN(7, "qp=%p, nr_wqes=%d", qp, nr_wqes);
+
+ hipz_galpa_store_acc(gal, QPTEMM_OFFSET(qpx_sqa),
+ EHEA_BMASK_SET(QPX_SQA_VALUE, nr_wqes));
+ EDEB_EX(7, "qpx_sqa = %i", nr_wqes);
+}
+
+static inline void ehea_update_rq3a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal = qp->galpas.kernel;
+ EDEB_EN(7, "ehea_qp=%p, nr_wqes=%d", qp, nr_wqes);
+ hipz_galpa_store_acc(gal, QPTEMM_OFFSET(qpx_rq3a),
+ EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+ EDEB_EX(7, "QPx_RQA = %i", nr_wqes);
+}
+
+static inline void ehea_update_rq2a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal = qp->galpas.kernel;
+ EDEB_EN(7, "ehea_qp=%p, nr_wqes=%d", qp, nr_wqes);
+ hipz_galpa_store_acc(gal, QPTEMM_OFFSET(qpx_rq2a),
+ EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+ EDEB_EX(7, "QPx_RQA = %i", nr_wqes);
+}
+
+static inline void ehea_update_rq1a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_galpa gal = qp->galpas.kernel;
+ EDEB_EN(7, "ehea_qp=%p, nr_wqes=%d", qp, nr_wqes);
+ hipz_galpa_store_acc(gal, QPTEMM_OFFSET(qpx_rq1a),
+ EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+ EDEB_EX(7, "QPx_RQA = %i", nr_wqes);
+}
+
+static inline void ehea_update_feca(struct ehea_cq *cq, u32 nr_cqes)
+{
+ struct h_galpa gal = cq->galpas.kernel;
+ EDEB_EN(7, "");
+ hipz_galpa_store_acc(gal, CQTEMM_OFFSET(cqx_feca),
+ EHEA_BMASK_SET(CQX_FECADDER, nr_cqes));
+ EDEB_EX(7, "cqx_feca = %i", nr_cqes);
+}
+
+static inline void ehea_reset_cq_n1(struct ehea_cq *cq)
+{
+ struct h_galpa gal = cq->galpas.kernel;
+ EDEB_EN(7, "");
+ hipz_galpa_store_cq(gal,
+ cqx_n1,
+ EHEA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, 1));
+ EDEB_EX(7, "");
+}
+
+static inline void ehea_reset_cq_ep(struct ehea_cq *my_cq)
+{
+ struct h_galpa gal = my_cq->galpas.kernel;
+ EDEB_EN(7, "");
+ hipz_galpa_store_acc(gal,
+ CQTEMM_OFFSET(cqx_ep),
+ EHEA_BMASK_SET(CQX_EP_EVENT_PENDING, 0));
+ EDEB_EX(7, "");
+}
+
+
+#endif /* __EHEA_HW_H__ */
^ permalink raw reply
* [PATCH 3/5] ehea: queue management
From: Jan-Bernd Themann @ 2006-06-08 9:55 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/ehea_qmr.c | 719 ++++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_qmr.h | 390 +++++++++++++++++++++++
2 files changed, 1109 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_qmr.c 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.c 2006-06-08 01:58:28.862208992 -0700
@@ -0,0 +1,719 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#include "ehea.h"
+#include "ehea_phyp.h"
+#include "ehea_qmr.h"
+
+static void *ipz_qpageit_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->pagesize;
+ if (queue->current_q_offset > queue->queue_length) {
+ queue->current_q_offset -= queue->pagesize;
+ retvalue = NULL;
+ }
+ else if ((((u64) retvalue) & (EHEA_PAGESIZE-1)) != 0) {
+ EDEB(4, "ERROR!! not at PAGE-Boundary");
+ return NULL;
+ }
+ EDEB(7, "queue=%p retvalue=%p", queue, retvalue);
+ return retvalue;
+}
+
+static int ipz_queue_ctor(struct ipz_queue *queue,
+ const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size,
+ const u32 nr_of_sg)
+{
+ int f;
+ EDEB_EN(7, "nr_of_pages=%x pagesize=%x qe_size=%x",
+ nr_of_pages, pagesize, qe_size);
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ EDEB(4, "ERROR!! didn't get the memory");
+ return 0;
+ }
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+ for (f = 0; f < nr_of_pages; f++) {
+ (queue->queue_pages)[f] =
+ (struct ipz_page *)get_zeroed_page(GFP_KERNEL);
+ if (!(queue->queue_pages)[f]) {
+ break;
+ }
+ }
+ if (f < nr_of_pages) {
+ int g;
+ EDEB_ERR(4, "couldn't get 0ed pages queue=%p f=%x "
+ "nr_of_pages=%x", queue, f, nr_of_pages);
+ for (g = 0; g < f; g++) {
+ free_page((unsigned long)(queue->queue_pages)[g]);
+ }
+ return 0;
+ }
+ queue->current_q_offset = 0;
+ queue->qe_size = qe_size;
+ queue->act_nr_of_sg = nr_of_sg;
+ queue->pagesize = pagesize;
+ queue->toggle_state = 1;
+ EDEB_EX(7, "queue_length=%x queue_pages=%p qe_size=%x"
+ " act_nr_of_sg=%x", queue->queue_length, queue->queue_pages,
+ queue->qe_size, queue->act_nr_of_sg);
+ return 1;
+}
+
+static int ipz_queue_dtor(struct ipz_queue *queue)
+{
+ int g;
+ EDEB_EN(7, "ipz_queue pointer=%p", queue);
+ if (!queue) {
+ return 0;
+ }
+ if (!queue->queue_pages) {
+ return 0;
+ }
+ EDEB(7, "destructing a queue with the following properties:\n"
+ "queue_length=%x act_nr_of_sg=%x pagesize=%x qe_size=%x",
+ queue->queue_length, queue->act_nr_of_sg, queue->pagesize,
+ queue->qe_size);
+ for (g = 0; g < (queue->queue_length / queue->pagesize); g++) {
+ free_page((unsigned long)(queue->queue_pages)[g]);
+ }
+ vfree(queue->queue_pages);
+
+ EDEB_EX(7, "queue freed!");
+ return 1;
+}
+
+struct ehea_cq *ehea_cq_new(void)
+{
+ struct ehea_cq *cq = vmalloc(sizeof(*cq));
+ if (cq)
+ memset(cq, 0, sizeof(*cq));
+ return cq;
+}
+
+void ehea_cq_delete(struct ehea_cq *cq)
+{
+ vfree(cq);
+}
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
+ int nr_of_cqe, u64 eq_handle, u32 cq_token)
+{
+ struct ehea_cq *cq = NULL;
+ struct h_galpa gal;
+
+ u64 *cq_handle_ref;
+ u32 act_nr_of_entries;
+ u32 act_pages;
+ u64 hret;
+ int ipz_rc;
+ u32 counter;
+ void *vpage = NULL;
+ u64 rpage = 0;
+
+ EDEB_EN(7, "adapter=%p nr_of_cqe=%x , eq_handle: %016lX",
+ adapter, nr_of_cqe, eq_handle);
+
+ cq = ehea_cq_new();
+ if (!cq) {
+ cq = NULL;
+ EDEB_ERR(4, "ehea_create_cq ret=%p (-ENOMEM)", cq);
+ goto create_cq_exit0;
+ }
+
+ cq->attr.max_nr_of_cqes = nr_of_cqe;
+ cq->attr.cq_token = cq_token;
+ cq->attr.eq_handle = eq_handle;
+
+ cq->adapter = adapter;
+
+ cq_handle_ref = &cq->ipz_cq_handle;
+ act_nr_of_entries = 0;
+ act_pages = 0;
+
+ hret = ehea_h_alloc_resource_cq(adapter->handle,
+ cq,
+ &cq->attr,
+ &cq->ipz_cq_handle, &cq->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "ehea_h_alloc_resource_cq failed. hret=%lx", hret);
+ goto create_cq_exit1;
+ }
+
+ ipz_rc = ipz_queue_ctor(&cq->ipz_queue, cq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_cqe), 0);
+ if (!ipz_rc)
+ goto create_cq_exit2;
+
+ hret = H_SUCCESS;
+
+ for (counter = 0; counter < cq->attr.nr_pages; counter++) {
+ vpage = ipz_qpageit_get_inc(&cq->ipz_queue);
+ if (!vpage) {
+ EDEB_ERR(4, "ipz_qpageit_get_inc() "
+ "returns NULL adapter=%p", adapter);
+ goto create_cq_exit3;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ hret = ehea_h_register_rpage_cq(adapter->handle,
+ cq->ipz_cq_handle,
+ 0,
+ HIPZ_CQ_REGISTER_ORIG,
+ rpage, 1, cq->galpas.kernel);
+
+ if (hret < H_SUCCESS) {
+ EDEB_ERR(4, "ehea_h_register_rpage_cq() failed "
+ "ehea_cq=%p hret=%lx "
+ "counter=%i act_pages=%i",
+ cq, hret, counter, cq->attr.nr_pages);
+ goto create_cq_exit3;
+ }
+
+ if (counter == (cq->attr.nr_pages - 1)) {
+ vpage = ipz_qpageit_get_inc(&cq->ipz_queue);
+
+ if ((hret != H_SUCCESS) || (vpage)) {
+ EDEB_ERR(4, "Registration of pages not "
+ "complete ehea_cq=%p hret=%lx",
+ cq, hret)
+ goto create_cq_exit3;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (vpage == 0)) {
+ EDEB_ERR(4, "Registration of page failed "
+ "ehea_cq=%p hret=%lx"
+ "counter=%i act_pages=%i",
+ cq, hret, counter, cq->attr.nr_pages);
+ goto create_cq_exit3;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&cq->ipz_queue);
+ gal = cq->galpas.kernel;
+ ehea_reset_cq_ep(cq);
+ ehea_reset_cq_n1(cq);
+
+ EDEB_EX(7, "ret=%p ", cq);
+ return cq;
+
+create_cq_exit3:
+ ipz_queue_dtor(&cq->ipz_queue);
+
+create_cq_exit2:
+ hret = ehea_h_destroy_cq(adapter->handle, cq, cq->ipz_cq_handle,
+ &cq->galpas);
+ EDEB(7, "return code of ehea_cq_destroy=%lx", hret);
+
+create_cq_exit1:
+ ehea_cq_delete(cq);
+
+create_cq_exit0:
+ EDEB_EX(7, "ret=NULL");
+ return NULL;
+}
+
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+ int ret = 0;
+ u64 adapter_handle;
+ u64 hret;
+
+ adapter_handle = cq->adapter->handle;
+ EDEB_EN(7, "adapter=%p cq=%p", cq->adapter, cq);
+
+ /* deregister all previous registered pages */
+ hret = ehea_h_destroy_cq(adapter_handle, cq, cq->ipz_cq_handle,
+ &cq->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "destroy CQ failed!");
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&cq->ipz_queue);
+ ehea_cq_delete(cq);
+
+ EDEB_EX(7, "ret=%x ", ret);
+ return ret;
+}
+
+struct ehea_eq *ehea_eq_new(void)
+{
+ struct ehea_eq *eq = vmalloc(sizeof(*eq));
+ if (eq)
+ memset(eq, 0, sizeof(*eq));
+ return eq;
+}
+
+void ehea_eq_delete(struct ehea_eq *eq)
+{
+ vfree(eq);
+}
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ const enum ehea_eq_type type,
+ const u32 max_nr_of_eqes, const u8 eqe_gen)
+{
+ u64 hret = H_HARDWARE;
+ int ret = 0;
+ u32 i;
+ void *vpage = NULL;
+ struct ehea_eq *eq;
+
+ EDEB_EN(7, "adapter=%p, max_nr_of_eqes=%x", adapter, max_nr_of_eqes);
+
+ eq = ehea_eq_new();
+ if (!eq)
+ return NULL;
+
+ eq->attr.type = type;
+ eq->attr.max_nr_of_eqes = max_nr_of_eqes;
+ eq->attr.eqe_gen = eqe_gen;
+ spin_lock_init(&eq->spinlock);
+
+ hret = ehea_h_alloc_resource_eq(adapter->handle,
+ eq, &eq->attr, &eq->ipz_eq_handle);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "ehea_h_alloc_resource_eq failed. hret=%lx", hret);
+ goto free_eq_mem;
+ }
+
+ ret = ipz_queue_ctor(&eq->ipz_queue, eq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_eqe), 0);
+ if (!ret) {
+ EDEB_ERR(4, "can't allocate EQ pages");
+ goto alloc_pages_failed;
+ }
+
+ for (i = 0; i < eq->attr.nr_pages; i++) {
+ u64 rpage;
+
+ if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ hret = H_RESOURCE;
+ goto register_page_failed;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ hret = ehea_h_register_rpage_eq(adapter->handle,
+ eq->ipz_eq_handle,
+ 0,
+ HIPZ_EQ_REGISTER_ORIG,
+ rpage, 1);
+
+ if (i == (eq->attr.nr_pages - 1)) {
+ /* last page */
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if ((hret != H_SUCCESS) || (vpage)) {
+ goto register_page_failed;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+ goto register_page_failed;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&eq->ipz_queue);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return eq;
+
+register_page_failed:
+ ipz_queue_dtor(&eq->ipz_queue);
+
+alloc_pages_failed:
+ ehea_h_destroy_eq(adapter->handle, eq, eq->ipz_eq_handle, &eq->galpas);
+free_eq_mem:
+ ehea_eq_delete(eq);
+
+ EDEB_EX(7, "return with error hret=%lx", hret);
+ return NULL;
+}
+
+void *ehea_poll_eq(struct ehea_adapter *adapter, struct ehea_eq *eq)
+{
+ void *eqe = NULL;
+ unsigned long flags = 0;
+
+ EDEB_EN(7, "adapter=%p eq=%p", adapter, eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ EDEB_EX(7, "eqe=%p", eqe);
+
+ return eqe;
+}
+
+int ehea_destroy_eq(struct ehea_adapter *adapter, struct ehea_eq *eq)
+{
+ unsigned long flags = 0;
+ u64 hret = H_HARDWARE;
+
+ EDEB_EN(7, "adapter=%p eq=%p", adapter, eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+
+ hret = ehea_h_destroy_eq(adapter->handle, eq, eq->ipz_eq_handle,
+ &eq->galpas);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "Failed freeing EQ resources. hret=%lx", hret);
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&eq->ipz_queue);
+ ehea_eq_delete(eq);
+ EDEB_EX(7, "");
+
+ return 0;
+}
+
+struct ehea_qp *ehea_qp_new(void) {
+ struct ehea_qp *qp = vmalloc(sizeof(*qp));
+ if (qp != 0) {
+ memset(qp, 0, sizeof(*qp));
+ }
+ return qp;
+}
+
+void ehea_qp_delete(struct ehea_qp *qp)
+{
+ vfree(qp);
+}
+
+/**
+ * allocates memory for a queue and registers pages in phyp
+ */
+int ehea_qp_alloc_register(struct ehea_qp *qp,
+ struct ipz_queue *ipz_queue,
+ int nr_pages,
+ int wqe_size,
+ int act_nr_sges,
+ struct ehea_adapter *adapter, int h_call_q_selector)
+{
+ u64 hret = H_HARDWARE;
+ u64 rpage = 0;
+ int iret = 0;
+ int cnt = 0;
+ void *vpage = NULL;
+
+ iret = ipz_queue_ctor(ipz_queue,
+ nr_pages, EHEA_PAGESIZE, wqe_size, act_nr_sges);
+ if (!iret) {
+ EDEB_ERR(4, "Cannot allocate page for queue. iret=%x", iret);
+ return -ENOMEM;
+ }
+
+ EDEB(7, "queue_size=%x, alloc_len=%x, toggle_state=%d",
+ ipz_queue->qe_size,
+ ipz_queue->queue_length, ipz_queue->toggle_state);
+
+ for (cnt = 0; cnt < nr_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(ipz_queue);
+ if (!vpage) {
+ EDEB_ERR(4, "SQ ipz_qpageit_get_inc() "
+ "failed p_vpage= %p", vpage);
+ goto qp_alloc_register_exit0;
+ }
+ rpage = virt_to_abs(vpage);
+
+ hret = ehea_h_register_rpage_qp(adapter->handle,
+ qp->ipz_qp_handle,
+ 0,
+ h_call_q_selector,
+ rpage,
+ 1, qp->galpas.kernel);
+
+ if (hret < H_SUCCESS) {
+ EDEB_ERR(4, "ehea_h_register_rpage_qp failed. hret=%lx",
+ hret);
+ goto qp_alloc_register_exit0;
+ }
+ }
+ ipz_qeit_reset(ipz_queue);
+
+ return 0;
+
+qp_alloc_register_exit0:
+ ipz_queue_dtor(ipz_queue);
+ return -EINVAL;
+}
+
+static inline u32 map_swqe_size(u8 swqe_enc_size)
+{
+ return 128 << swqe_enc_size;
+}
+
+static inline u32 map_rwqe_size(u8 rwqe_enc_size)
+{
+ return 128 << rwqe_enc_size;
+}
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
+ u32 pd, struct ehea_qp_init_attr *init_attr)
+{
+ struct ehea_qp *qp;
+ u64 hret = H_HARDWARE;
+
+ u32 wqe_size_in_bytes_sq = 0;
+ u32 wqe_size_in_bytes_rq1 = 0;
+ u32 wqe_size_in_bytes_rq2 = 0;
+ u32 wqe_size_in_bytes_rq3 = 0;
+
+ int ret = -1;
+
+ EDEB_EN(7, "init_attr=%p", init_attr);
+
+ qp = ehea_qp_new();
+
+ if (!qp) {
+ EDEB_ERR(4, "pd=%X not enough memory to alloc qp", pd);
+ return NULL;
+ }
+ qp->adapter = adapter;
+
+ EDEB(7, "send_ehea_cq->ipz_cq_handle=0x%lX"
+ "recv_ehea_cq->ipz_cq_handle=0x%lX", init_attr->send_cq_handle,
+ init_attr->recv_cq_handle);
+
+
+ hret = ehea_h_alloc_resource_qp(adapter->handle, qp,
+ init_attr,
+ pd,
+ &qp->ipz_qp_handle,
+ &qp->galpas);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "ehea_h_alloc_resource_qp failed. hret=%lx", hret);
+ goto create_qp_exit1;
+ }
+
+ wqe_size_in_bytes_sq = map_swqe_size(init_attr->act_wqe_size_enc_sq);
+ EDEB(7, "SWQE SG %d", init_attr->wqe_size_enc_sq);
+
+ wqe_size_in_bytes_rq1 = map_rwqe_size(init_attr->act_wqe_size_enc_rq1);
+ wqe_size_in_bytes_rq2 = map_rwqe_size(init_attr->act_wqe_size_enc_rq2);
+ wqe_size_in_bytes_rq3 = map_rwqe_size(init_attr->act_wqe_size_enc_rq3);
+
+ EDEB(7, "SQ pages: %d, SQ WQE size:%d, max SWQE size enc: %d",
+ init_attr->nr_sq_pages,
+ wqe_size_in_bytes_sq, init_attr->act_wqe_size_enc_sq);
+
+ EDEB(7, "RQ1 pages: %d, RQ1 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq1_pages,
+ wqe_size_in_bytes_rq1, init_attr->act_wqe_size_enc_rq1);
+
+ EDEB(7, "RQ2 pages: %d, RQ2 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq2_pages,
+ wqe_size_in_bytes_rq2, init_attr->act_wqe_size_enc_rq2);
+
+ EDEB(7, "RQ3 pages: %d, RQ3 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq3_pages,
+ wqe_size_in_bytes_rq3, init_attr->act_wqe_size_enc_rq3);
+
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_squeue,
+ init_attr->nr_sq_pages,
+ wqe_size_in_bytes_sq,
+ init_attr->act_wqe_size_enc_sq, adapter,
+ 0);
+ if (ret < H_SUCCESS) {
+ EDEB_ERR(4, "can't register for sq hret=%x", ret);
+ goto create_qp_exit2;
+ }
+
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue1,
+ init_attr->nr_rq1_pages,
+ wqe_size_in_bytes_rq1,
+ init_attr->act_wqe_size_enc_rq1,
+ adapter, 1);
+
+ if (ret < 0) {
+ EDEB_ERR(4, "can't register for rq1 hret=%x", ret);
+ goto create_qp_exit3;
+ }
+
+ if (init_attr->rq_count > 1) {
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue2,
+ init_attr->nr_rq2_pages,
+ wqe_size_in_bytes_rq2,
+ init_attr->act_wqe_size_enc_rq2,
+ adapter, 2);
+
+ if (ret < 0) {
+ EDEB_ERR(4, "can't register for rq2 hret=%x", ret);
+ goto create_qp_exit4;
+ }
+ }
+
+ if (init_attr->rq_count > 2) {
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue3,
+ init_attr->nr_rq3_pages,
+ wqe_size_in_bytes_rq3,
+ init_attr->act_wqe_size_enc_rq3,
+ adapter, 3);
+
+ if (ret != 0) {
+ EDEB_ERR(4, "can't register for rq3 hret=%x", ret);
+ goto create_qp_exit5;
+ }
+ }
+
+ qp->init_attr = *init_attr;
+
+ EDEB_EX(7, "");
+ return qp;
+
+create_qp_exit5:
+ ipz_queue_dtor(&qp->ipz_rqueue2);
+
+create_qp_exit4:
+ ipz_queue_dtor(&qp->ipz_rqueue1);
+
+create_qp_exit3:
+ ipz_queue_dtor(&qp->ipz_squeue);
+
+create_qp_exit2:
+ hret = ehea_h_destroy_qp(adapter->handle, qp, qp->ipz_qp_handle,
+ &qp->galpas);
+
+create_qp_exit1:
+ ehea_qp_delete(qp);
+
+ EDEB_EX(7, "hret=NULL");
+ return NULL;
+
+}
+
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+ int ret = 0;
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+ EDEB_EX(7, "");
+
+ hret = ehea_h_destroy_qp(qp->adapter->handle, qp, qp->ipz_qp_handle,
+ &qp->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "destroy QP failed!");
+ ret = -EINVAL;
+ }
+
+ ipz_queue_dtor(&qp->ipz_squeue);
+ ipz_queue_dtor(&qp->ipz_rqueue1);
+
+ if(qp_attr->rq_count > 1)
+ ipz_queue_dtor(&qp->ipz_rqueue2);
+ if(qp_attr->rq_count > 2)
+ ipz_queue_dtor(&qp->ipz_rqueue3);
+ ehea_qp_delete(qp);
+
+ EDEB_EX(7, "hret=%lx", hret);
+
+ return ret;
+}
+
+#define EHEA_MEM_START 0xc000000000000000
+#define EHEA_MEM_ACC_CTRL 0x00800000
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+{
+ int i;
+ u64 hret;
+ u64 start = EHEA_MEM_START;
+ u64 end = (u64) high_memory;
+ u64 nr_pages = (end - start) / PAGE_SIZE;
+ u32 acc_ctrl = EHEA_MEM_ACC_CTRL;
+
+ EDEB_EN(7, "adapter=%p", adapter);
+
+ hret = ehea_h_alloc_resource_mr(adapter->handle,
+ start,
+ end - start,
+ acc_ctrl,
+ adapter->pd,
+ &adapter->mr_handle,
+ &adapter->lkey);
+ if (hret != H_SUCCESS) {
+ EDEB_EX(4, "Error: hret=%lX\n", hret);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ hret = ehea_h_register_rpage_mr(adapter->handle,
+ adapter->mr_handle,
+ 0,
+ 0,
+ virt_to_abs(
+ (void *)(((u64) start)
+ + (i * PAGE_SIZE))),
+ 1);
+
+ if (((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))) {
+ ehea_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ EDEB_EX(4, " register rpage_mr: hret=%lX\n", hret);
+ return -EINVAL;
+ }
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ EDEB_EX(4, " register rpage_mr failed for last page:"
+ "hret=%lX\n", hret);
+ return -EINVAL;
+ }
+
+ EDEB_EX(7, "");
+ return 0;
+}
+
+int ehea_dereg_mr_adapter(struct ehea_adapter *adapter)
+{
+ u64 hret;
+ EDEB_EN(7, "adapter=%p", adapter);
+ hret = ehea_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ if (hret != H_SUCCESS) {
+ EDEB_EX(4, "deregistering memory region failed");
+ return -EINVAL;
+ }
+ EDEB_EX(7, "");
+ return 0;
+}
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_qmr.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.h 2006-06-08 01:58:28.865208536 -0700
@@ -0,0 +1,390 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#ifndef __EHEA_QMR_H__
+#define __EHEA_QMR_H__
+
+#include "ehea.h"
+#include "ehea_hw.h"
+
+/* Use of WR_ID field for EHEA */
+#define EHEA_WR_ID_COUNT EHEA_BMASK_IBM(0, 19)
+#define EHEA_WR_ID_TYPE EHEA_BMASK_IBM(20, 23)
+#define EHEA_SWQE2_TYPE 0x1
+#define EHEA_SWQE3_TYPE 0x2
+#define EHEA_RWQE2_TYPE 0x3 /* RQ2 */
+#define EHEA_RWQE3_TYPE 0x4 /* RQ3 */
+#define EHEA_WR_ID_INDEX EHEA_BMASK_IBM(24, 47)
+#define EHEA_WR_ID_REFILL EHEA_BMASK_IBM(48, 63)
+
+struct ehea_vsgentry {
+ u64 vaddr;
+ u32 l_key;
+ u32 len;
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define EHEA_MAX_WQE_SG_ENTRIES 252
+#define SWQE2_RES_IMM 14
+#define SWQE2_MAX_IMM (160-SWQE2_RES_IMM)
+#define SWQE3_MAX_IMM 224
+
+/* tx control flags for swqe */
+#define EHEA_SWQE_CRC 0x8000
+#define EHEA_SWQE_IP_CHECKSUM 0x4000
+#define EHEA_SWQE_TCP_CHECKSUM 0x2000
+#define EHEA_SWQE_TSO 0x1000
+#define EHEA_SWQE_SIGNALLED_COMPLETION 0x0800
+#define EHEA_SWQE_VLAN_INSERT 0x0400
+#define EHEA_SWQE_IMM_DATA_PRESENT 0x0200
+#define EHEA_SWQE_DESCRIPTORS_PRESENT 0x0100
+#define EHEA_SWQE_WRAP_CTL_REC 0x0080
+#define EHEA_SWQE_WRAP_CTL_FORCE 0x0040
+#define EHEA_SWQE_BIND 0x0020
+#define EHEA_SWQE_PURGE 0x0010
+
+#define SWQE_HEADER_SIZE 32
+
+struct ehea_swqe {
+ u64 wr_id;
+ u16 tx_control;
+ u16 vlan_tag;
+ u8 reserved1;
+ u8 ip_start;
+ u8 ip_end;
+ u8 immediate_data_length;
+ u8 tcp_offset;
+ u8 reserved2;
+ u16 tcp_end;
+ u8 wrap_tag;
+ u8 descriptors; /* number of valid descriptors in WQE */
+ u16 reserved3;
+ u16 reserved4;
+ u16 mss;
+ u32 reserved5;
+ union {
+ /* Send WQE Format 1 */
+ struct {
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+ } no_immediate_data;
+
+ /* Send WQE Format 2 */
+ struct {
+ struct ehea_vsgentry sg_entry;
+ /* 0x30 */
+ u8 immediate_data[0xd0 - 0x30];
+ /* 0xd0 */
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES -
+ 1];
+ } immdata_desc __attribute__ ((packed));
+
+ /* Send WQE Format 3 */
+ struct {
+ u8 immediate_data[1];
+ } immdata_nodesc;
+ } u;
+};
+
+struct ehea_rwqe {
+ u64 wr_id; /* work request ID */
+ u8 reserved1[5];
+ u8 data_segments;
+ u16 reserved2;
+ u64 reserved3;
+ u64 reserved4;
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+};
+
+#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
+
+#define EHEA_CQE_TYPE_RQ 0x60
+#define EHEA_CQE_STAT_ERR_MASK 0x7300
+#define EHEA_CQE_STAT_ERR_TCP 0x4000
+
+struct ehea_cqe {
+ u64 wr_id; /* work request ID from WQE */
+ u8 type;
+ u8 valid;
+ u16 status;
+ u16 reserved1;
+ u16 num_bytes_transfered;
+ u16 vlan_tag;
+ u16 inet_checksum_value;
+ u8 reserved2;
+ u8 header_length;
+ u16 reserved3;
+ u16 page_offset;
+ u16 wqe_count;
+ u32 qp_token;
+ u32 timestamp;
+ u32 reserved4;
+ u64 reserved5[3];
+};
+
+#define EHEA_EQE_VALID EHEA_BMASK_IBM(0, 0)
+#define EHEA_EQE_IS_CQE EHEA_BMASK_IBM(1, 1)
+#define EHEA_EQE_IDENTIFIER EHEA_BMASK_IBM(2, 7)
+#define EHEA_EQE_QP_CQ_NUMBER EHEA_BMASK_IBM(8, 31)
+#define EHEA_EQE_QP_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_CQ_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_KEY EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+#define EHEA_EQE_EQ_NUMBER EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_ID EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55)
+#define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+
+struct ehea_eqe {
+ u64 entry;
+};
+
+struct ehea_mrte {
+ u64 starting_va;
+ u64 length; /* length of memory region in bytes */
+ u32 pd;
+ u8 key_instance;
+ u8 pagesize;
+ u8 mr_control;
+ u8 local_remote_access_controll;
+ u8 reserved[0x20 - 0x18];
+ u64 at_pointer[4];
+};
+
+static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
+{
+ struct ipz_page *current_page = NULL;
+ if (q_offset >= queue->queue_length)
+ q_offset -= queue->queue_length;
+ current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
+ return ¤t_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
+}
+
+static inline void *ipz_qeit_get(struct ipz_queue *queue)
+{
+ return ipz_qeit_calc(queue, queue->current_q_offset);
+}
+
+static inline void ipz_qeit_inc(struct ipz_queue *queue)
+{
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset >= queue->queue_length) {
+ queue->current_q_offset = 0;
+ /* toggle the valid flag */
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+}
+
+static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ ipz_qeit_inc(queue);
+ EDEB(8, "queue=%p retvalue=%p new current_q_addr=%lx qe_size=%x",
+ queue, retvalue, queue->current_q_offset, queue->qe_size);
+
+ return retvalue;
+}
+
+static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
+{
+ struct ehea_cqe *retvalue = ipz_qeit_get(queue);
+ void *pref;
+ u8 valid = retvalue->valid;
+ if ((valid >> 7) == (queue->toggle_state & 1)) {
+ /* this is a good one */
+ iosync();
+ ipz_qeit_inc(queue);
+ pref = ipz_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ } else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *ipz_qeit_get_valid(struct ipz_queue *queue)
+{
+ struct ehea_cqe *retvalue = ipz_qeit_get(queue);
+ void *pref;
+ pref = ipz_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ prefetch(pref + 256);
+ u8 valid = retvalue->valid;
+ if ((valid >> 7) == (queue->toggle_state & 1))
+ iosync();
+ else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *ipz_qeit_reset(struct ipz_queue *queue)
+{
+ queue->current_q_offset = 0;
+ return ipz_qeit_get(queue);
+}
+
+static inline void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = NULL;
+ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+
+ retvalue = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset > last_entry_in_q) {
+ queue->current_q_offset = 0;
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ EDEB(7, "queue=%p retvalue=%p new current_q_offset=%lx qe_size=%x",
+ queue, retvalue, queue->current_q_offset, queue->qe_size);
+
+ return retvalue;
+}
+
+static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ u32 qe = *(u8 *) retvalue;
+ EDEB(7, "ipz_eqit_eq_get_inc_valid qe=%x", qe);
+ if ((qe >> 7) == (queue->toggle_state & 1))
+ ipz_qeit_eq_get_inc(queue);
+ else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
+ int rq_nr)
+{
+
+ struct ehea_rwqe *wqe_p = NULL;
+ struct ipz_queue *queue = NULL;
+ struct ehea_qp *my_qp = qp;
+ EDEB_EN(8, "QP=%p, RQ_nr=%d", qp, rq_nr);
+
+ if (rq_nr == 1)
+ queue = &my_qp->ipz_rqueue1;
+ else if (rq_nr == 2)
+ queue = &my_qp->ipz_rqueue2;
+ else
+ queue = &my_qp->ipz_rqueue3;
+ wqe_p = (struct ehea_rwqe *)ipz_qeit_get_inc(queue);
+
+ EDEB_EX(8, "&RWQE=%p, queue=%p", wqe_p, queue);
+ return wqe_p;
+}
+
+static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp)
+{
+
+ struct ehea_swqe *wqe_p = NULL;
+ EDEB_EN(7, "QP=%p, queue=%p", my_qp, &my_qp->ipz_squeue);
+ wqe_p = (struct ehea_swqe *)ipz_qeit_get_inc(&my_qp->ipz_squeue);
+ EDEB_EX(7, "");
+ return wqe_p;
+}
+
+static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
+{
+
+ EDEB_EN(7, "QP=%p, SWQE=%p", my_qp, swqe);
+ EDEB(6, "SWQE workreqid = 0x%lX, imm_data_len=%d, descriptors=%d",
+ (u64) swqe->wr_id, swqe->immediate_data_length, swqe->descriptors);
+ iosync();
+ ehea_update_sqa(my_qp, 1);
+ EDEB_EX(7, "");
+}
+
+static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
+{
+ struct ipz_queue *queue = &qp->ipz_rqueue1;
+ struct ehea_cqe *cqe = NULL;
+
+ EDEB_EN(7, "QP=%p, RQ1 toggle state = %d, current_q_offset=%lx", qp,
+ queue->toggle_state, queue->current_q_offset);
+ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
+ cqe = (struct ehea_cqe *)ipz_qeit_get_valid(queue);
+ EDEB_EX(7, "cqe=%p, new toggle state %d, wqe_index = %d",
+ cqe, queue->toggle_state, *wqe_index);
+ return cqe;
+}
+
+static inline void ehea_inc_rq1(struct ehea_qp *qp)
+{
+ struct ipz_queue *queue = &qp->ipz_rqueue1;
+ ipz_qeit_inc(queue);
+}
+
+static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
+{
+
+ struct ehea_cqe *wqe_p = NULL;
+ EDEB_EN(7, "CQ=%p", my_cq);
+
+ EDEB(7, "queue_element_size=%x, alloc_len=%x, queue=%p",
+ my_cq->ipz_queue.qe_size,
+ my_cq->ipz_queue.queue_length, &my_cq->ipz_queue);
+ wqe_p = (struct ehea_cqe *)ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
+
+ EDEB_EX(7, "wqe_p=%p", wqe_p);
+ return wqe_p;
+};
+
+#define HIPZ_CQ_REGISTER_ORIG 0
+#define HIPZ_EQ_REGISTER_ORIG 0
+
+enum ehea_eq_type {
+ EHEA_EQ = 0, /* event queue */
+ EHEA_NEQ /* notification event queue */
+};
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ enum ehea_eq_type type,
+ const u32 length, const u8 eqe_gen);
+
+int ehea_destroy_eq(struct ehea_adapter *adapter, struct ehea_eq *eq);
+
+void *ehea_poll_eq(struct ehea_adapter *adapter, struct ehea_eq *eq);
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
+ u64 eq_handle, u32 cq_token);
+
+int ehea_destroy_cq(struct ehea_cq *cq);
+
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter,
+ u32 pd,
+ struct ehea_qp_init_attr *init_attr);
+
+int ehea_destroy_qp(struct ehea_qp *qp);
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_dereg_mr_adapter(struct ehea_adapter *adapter);
+
+#endif /* __EHEA_QMR_H__ */
^ permalink raw reply
* [PATCH 2/5] ehea: pHYP interface
From: Jan-Bernd Themann @ 2006-06-08 9:55 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/ehea_phyp.c | 1023 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_phyp.h | 625 ++++++++++++++++++++++++++
2 files changed, 1648 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_phyp.c 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.c 2006-06-08 01:58:28.856209904 -0700
@@ -0,0 +1,1023 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#include "ehea_phyp.h"
+
+
+static inline u16 get_order_of_qentries(u16 queue_entries)
+{
+ u8 ld = 1; /* logarithmus dualis */
+ EDEB_EN(7, "queue_entries=0x%X", queue_entries);
+ while (((1U << ld) - 1) < queue_entries) {
+ ld++;
+ };
+ EDEB_EX(7, "mapped queue_entries=%d", ld - 1);
+ return ld - 1;
+}
+
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+u64 ehea_h_query_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX cat=%X qp_handle=%lX sel_mask=%lX "
+ "cb_addr=%p\n",
+ hcp_adapter_handle,
+ (u16) qp_category, qp_handle, sel_mask, cb_addr);
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "Before HCALL");
+
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0)
+ panic("query_ehea_qp: cb_addr not on page boundary!!!");
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA_QP,
+ hcp_adapter_handle, /* R4 */
+ qp_category, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, /* R9-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "After HCALL");
+ EDEB_EX(7, "");
+ return hret;
+}
+
+/* input param R5 */
+#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
+
+/* input param R9 */
+#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32,63)
+
+/* input param R10 */
+#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
+/* Max Send Scatter Gather Elements */
+#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
+/* Max Receive SG Elements RQ1 */
+#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
+
+/* input param R11 */
+#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
+/* max swqe immediate data length */
+#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
+
+/* input param R12 */
+#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
+/* Threshold RQ2 */
+#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
+/* Threshold RQ3 */
+
+/* output param R6 */
+#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
+
+/* output param, R7 */
+#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
+
+/* output param R8,R9 */
+#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
+
+/* output param R11,R12 */
+#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp *ehea_qp,
+ struct ehea_qp_init_attr *init_attr,
+ const u32 pd,
+ u64 *qp_handle, struct h_galpas *h_galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ u64 allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6) /* RQ1 & RQ2 & rq3 */
+ |EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0) /* EQE gen. disabled */
+ |EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
+
+ u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
+
+ u64 max_r10_reg =
+ EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
+ get_order_of_qentries(init_attr->max_nr_send_wqes))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
+ init_attr->wqe_size_enc_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
+ init_attr->wqe_size_enc_rq2)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
+ init_attr->wqe_size_enc_rq3);
+
+ u64 r11_in =
+ EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
+ u64 threshold =
+ EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
+
+ u64 r5_out = 0;
+ u64 r6_out = 0;
+ u64 r7_out = 0;
+ u64 r8_out = 0;
+ u64 r9_out = 0;
+ u64 g_la_user_out = 0;
+ u64 r11_out = 0;
+ u64 r12_out = 0;
+
+ EDEB_EN(7, "adapter_handle=%lx low latency RQ1 0x%X "
+ "signalingtype=0x%X number of RQs=0x%X "
+ "send_cq_handle=%lx receive_cq_handle=%lx",
+ adapter_handle, init_attr->low_lat_rq1,
+ init_attr->signalingtype, init_attr->rq_count,
+ init_attr->send_cq_handle, init_attr->recv_cq_handle);
+ EDEB(7, "async_eq_handle=%lx qp_token=0x%X "
+ "max_nr_send_wqes=0x%X max_nr_rcv_wqes_rq1=0x%X "
+ "max_nr_rcv_wqes_rq2=0x%X max_nr_rcv_wqes_rq3=0x%X ",
+ init_attr->aff_eq_handle, init_attr->qp_token,
+ init_attr->max_nr_send_wqes, init_attr->max_nr_rwqes_rq1,
+ init_attr->max_nr_rwqes_rq2, init_attr->max_nr_rwqes_rq3);
+ EDEB(7, "wqe_enc_size=0x%X wqe_enc_size_rq1=0x%X "
+ "wqe_enc_size_rq2=0x%X wqe_enc_size_rq3=0x%X port_nr=%d",
+ init_attr->wqe_size_enc_sq, init_attr->wqe_size_enc_rq1,
+ init_attr->wqe_size_enc_rq2, init_attr->wqe_size_enc_rq3,
+ init_attr->port_nr);
+ EDEB(7, "rq2_threshold=%d rq3_threshold=%d",
+ init_attr->rq2_threshold, init_attr->rq3_threshold);
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_EHEA_RESOURCE,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ init_attr->send_cq_handle, /* R6 */
+ init_attr->recv_cq_handle, /* R7 */
+ init_attr->aff_eq_handle, /* R8 */
+ r9_reg, /* R9 */
+ max_r10_reg, /* R10 */
+ r11_in, /* R11 */
+ threshold, /* R12 */
+ qp_handle, /* R4 */
+ &r5_out, /* R5 */
+ &r6_out, /* R6 */
+ &r7_out, /* R7 */
+ &r8_out, /* R8 */
+ &r9_out, /* R9 */
+ &g_la_user_out, /* R10 */
+ &r11_out, /* R11 */
+ &r12_out); /* R12 */
+
+ init_attr->qp_nr = (u32)r5_out;
+
+ init_attr->act_nr_send_wqes =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out);
+ init_attr->act_nr_rwqes_rq1 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out);
+ init_attr->act_nr_rwqes_rq2 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out);
+ init_attr->act_nr_rwqes_rq3 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out);
+
+/* Interface is under construction */
+ init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
+ init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
+ init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
+ init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
+
+ init_attr->nr_sq_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out);
+ init_attr->nr_rq1_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out);
+ init_attr->nr_rq2_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out);
+ init_attr->nr_rq3_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out);
+
+ init_attr->liobn_sq =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out);
+ init_attr->liobn_rq1 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out);
+ init_attr->liobn_rq2 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out);
+ init_attr->liobn_rq3 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out);
+
+ if (hret == H_SUCCESS)
+ hcp_galpas_ctor(h_galpas, g_la_user_out, g_la_user_out);
+
+ EDEB(7, " qp_nr=%X, act_nr_send_wqes=%X, "
+ "act_nr_rcv_wqes_rq1=%X, act_nr_rcv_wqes_rq2=%X, "
+ "act_nr_rcv_wqes_rq3=%X, act_nr_send_sges=%X",
+ init_attr->qp_nr, init_attr->act_nr_send_wqes,
+ init_attr->act_nr_rwqes_rq1, init_attr->act_nr_rwqes_rq2,
+ init_attr->act_nr_rwqes_rq3, init_attr->act_wqe_size_enc_sq);
+ EDEB(7, " act_nr_rcv_sges_rq1=%X, act_nr_rcv_sges_rq2=%X, "
+ "act_nr_rcv_sges_rq3=%X", init_attr->act_wqe_size_enc_rq1,
+ init_attr->act_wqe_size_enc_rq2,
+ init_attr->act_wqe_size_enc_rq3);
+ EDEB_EX(7, " nr_sq_pages=%X, nr_rq1_pages=%X, nr_rq2_pages=%X"
+ "nr_rq3_pages=%X, galpa.user=%lx galpa.kernel=%lx",
+ init_attr->nr_sq_pages, init_attr->nr_rq1_pages,
+ init_attr->nr_rq2_pages, init_attr->nr_rq3_pages,
+ h_galpas->user.fw_handle, h_galpas->kernel.fw_handle);
+
+ return hret;
+}
+
+u64 ehea_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *ehea_cq,
+ struct ehea_cq_attr *cq_attr,
+ u64 *cq_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ u64 act_nr_of_cqes_out;
+ u64 act_pages_out;
+ u64 g_la_privileged_out;
+ u64 g_la_user_out;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx eq_handle=%lx"
+ " cq_token=%x max_nr_of_cqes=%x",
+ hcp_adapter_handle, cq_attr->eq_handle, cq_attr->cq_token,
+ cq_attr->max_nr_of_cqes);
+
+
+ hret = ehea_hcall_7arg_7ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ H_ALL_RES_TYPE_CQ, /* R5 */
+ cq_attr->eq_handle, /* R6 */
+ cq_attr->cq_token, /* R7 */
+ cq_attr->max_nr_of_cqes, /* R8 */
+ dummy, /* R9 */
+ dummy, /* R10 */
+ cq_handle, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_nr_of_cqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &g_la_privileged_out, /* R9 */
+ &g_la_user_out); /* R10 */
+
+ cq_attr->act_nr_of_cqes = act_nr_of_cqes_out;
+ cq_attr->nr_pages = act_pages_out;
+
+ if (hret == H_SUCCESS)
+ hcp_galpas_ctor(galpas, g_la_privileged_out, g_la_user_out);
+
+ EDEB_EX(7, "cq_handle=%lx act_nr_of_entries=%x act_pages=%x ",
+ *cq_handle, cq_attr->act_nr_of_cqes, cq_attr->nr_pages);
+
+ return hret;
+}
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+/* input param R5 */
+#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
+#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
+/* input param R6 */
+#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R6 */
+#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
+
+/* output param R7 */
+#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R8 */
+#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
+
+/* output param R9 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
+#define H_ALL_RES_EQ_ACT_EQ_IST_1 EHEA_BMASK_IBM(40, 63)
+
+/* output param R10 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_2 EHEA_BMASK_IBM(40, 63)
+
+/* output param R11 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_3 EHEA_BMASK_IBM(40, 63)
+
+/* output param R12 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_4 EHEA_BMASK_IBM(40, 63)
+
+u64 ehea_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *ehea_eq,
+ struct ehea_eq_attr *eq_attr, u64 *eq_handle)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 eq_liobn = 0;
+ u64 allocate_controls = 0;
+ u64 ist1_out = 0;
+ u64 ist2_out = 0;
+ u64 ist3_out = 0;
+ u64 ist4_out = 0;
+ u64 act_nr_of_eqes_out = 0;
+ u64 act_pages_out = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx new_control=%x "
+ "number_of_entries=%x",
+ hcp_adapter_handle, eq_attr->type, eq_attr->max_nr_of_eqes);
+
+ /* resource type */
+ allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ eq_attr->max_nr_of_eqes, /* R6 */
+ 0, 0, 0, 0, 0, 0, /* R7-R10 */
+ eq_handle, /* R4 */
+ &dummy, /* R5 */
+ &eq_liobn, /* R6 */
+ &act_nr_of_eqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &ist1_out, /* R9 */
+ &ist2_out, /* R10 */
+ &ist3_out, /* R11 */
+ &ist4_out); /* R12 */
+
+ eq_attr->act_nr_of_eqes = act_nr_of_eqes_out;
+ eq_attr->nr_pages = act_pages_out;
+ eq_attr->ist1 = ist1_out;
+ eq_attr->ist2 = ist2_out;
+ eq_attr->ist3 = ist3_out;
+ eq_attr->ist4 = ist4_out;
+
+ EDEB_EX(7, "act_nr_of_entries=%x act_pages=%x eq_ist1=%x",
+ eq_attr->act_nr_of_eqes, eq_attr->nr_pages, eq_attr->ist1);
+
+ return hret;
+}
+
+u64 ehea_h_modify_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 cat,
+ const u64 qp_handle,
+ const u64 sel_mask,
+ void *cb_addr,
+ u64 *inv_attr_id,
+ u64 *proc_mask,
+ u16 *out_swr,
+ u16 *out_rwr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ u64 act_out_swr = 0;
+ u64 act_out_rwr = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX cat=%X qp_handle=%lX sel_mask=%lX "
+ "cb_addr=%p\n",
+ hcp_adapter_handle, (u16) cat, qp_handle, sel_mask, cb_addr);
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0)
+ panic("query_ehea_qp: cb_addr not on page boundary!!!");
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "Before HCALL");
+
+ hret = ehea_hcall_9arg_9ret(H_MODIFY_EHEA_QP,
+ hcp_adapter_handle, /* R4 */
+ (u64) cat, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ inv_attr_id, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_out_swr, /* R7 */
+ &act_out_rwr, /* R8 */
+ proc_mask, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ *out_swr = act_out_swr;
+ *out_rwr = act_out_rwr;
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "H_MODIFY_EHEA_QP failed. hret=%lx", hret);
+ }
+
+ EDEB_EX(7, "inv_attr_id=%lX proc_mask=%lX out_swr=%X out_rwr=%X",
+ *inv_attr_id, *proc_mask, *out_swr, *out_rwr);
+
+ return hret;
+}
+
+u64 ehea_h_register_rpage(const u64 hcp_adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 log_pageaddr, u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 reg_control;
+ EDEB_EN(7, "hcp_adapter_handle=%lx pagesize=%x queue_type=%x "
+ "res_handle=%lx log_pageaddr=%lx "
+ "count=%lx",
+ hcp_adapter_handle,
+ pagesize, queue_type, resource_handle, log_pageaddr, count);
+
+ reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
+ | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
+
+ hret = ehea_hcall_7arg_7ret(H_REGISTER_EHEA_RPAGES,
+ hcp_adapter_handle, /* R4 */
+ reg_control, /* R5 */
+ resource_handle, /* R6 */
+ log_pageaddr, /* R7 */
+ count, /* R8 */
+ 0, /* R9 */
+ 0, /* R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_register_rpage_eq(const u64 hcp_adapter_handle,
+ const u64 eq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx eq_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ eq_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = ehea_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ eq_handle, log_pageaddr, count);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_register_rpage_cq(const u64 hcp_adapter_handle,
+ const u64 cq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, const struct h_galpa gal)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx cq_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ cq_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = ehea_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ cq_handle, log_pageaddr, count);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_register_rpage_qp(const u64 hcp_adapter_handle,
+ const u64 qp_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, struct h_galpa galpa)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx qp_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ qp_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = ehea_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ qp_handle, log_pageaddr, count);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_destroy_qp(const u64 hcp_adapter_handle,
+ struct ehea_qp *qp,
+ u64 qp_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ int ret = 0;
+ u64 dummy;
+ u64 ladr_next_sq_wqe_out;
+ u64 ladr_next_rq1_wqe_out;
+ u64 ladr_next_rq2_wqe_out;
+ u64 ladr_next_rq3_wqe_out;
+
+ EDEB_EN(7, "qp = %p ipz_qp_handle=%lx adapter_handle=%lx",
+ qp, qp_handle, hcp_adapter_handle);
+
+ ret = hcp_galpas_dtor(galpas);
+ if (ret) {
+ EDEB_ERR(4, "Could not destroy qp->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_DISABLE_AND_GET_EHEA,
+ hcp_adapter_handle, /* R4 */
+ H_DISABLE_GET_EHEA_WQE_P, /* R5 */
+ qp_handle, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &ladr_next_sq_wqe_out, /* R4 */
+ &ladr_next_rq1_wqe_out, /* R5 */
+ &ladr_next_rq2_wqe_out, /* R6 */
+ &ladr_next_rq3_wqe_out, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ if (hret == H_HARDWARE) {
+ EDEB_ERR(4, "HCA NOT operational - hret=%lx", hret);
+ return hret;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ qp_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource still in use - hret=%lx", hret);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_destroy_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *cq,
+ u64 cq_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "destroy CQ Entry:>>>> cq = %p ,ipz_cq_handle=%lx"
+ "; adapter_handle=%lx", cq, cq_handle,
+ hcp_adapter_handle);
+ hret = hcp_galpas_dtor(galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "could not destroy cp->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ cq_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource in use - hret=%lx ", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_destroy_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq * eq,
+ u64 eq_handle, struct h_galpas * galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "eq=%p ipz_eq_handle=%lx adapter_handle=%lx",
+ eq, eq_handle, hcp_adapter_handle);
+
+ hret = hcp_galpas_dtor(galpas);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "could not destroy ep->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ eq_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource in use - hret=%lx ", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_free_resource_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "adapter_handle=%lx mr_handle=%lx",
+ hcp_adapter_handle, mr_handle);
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* r4 */
+ mr_handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_alloc_resource_mr(const u64 hcp_adapter_handle,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const u32 pd, u64 * mr_handle, u32 * lkey)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 lkey_out;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx vaddr=%lx length=%lx "
+ "access_ctrl=%x pd=%x",
+ hcp_adapter_handle, vaddr, length, access_ctrl, pd);
+
+
+ hret = ehea_hcall_7arg_7ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ 5, /* R5 */
+ vaddr, /* R6 */
+ length, /* R7 */
+ (((u64) access_ctrl) << 32ULL), /* R8 */
+ pd, /* R9 */
+ 0, /* R10 */
+ mr_handle, /* R4 */
+ &dummy, /* R5 */
+ &lkey_out, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ *lkey = (u32) lkey_out;
+
+ EDEB_EX(7, "hret=%lX mr_handle=%lX, lkey=%x", hret, *mr_handle, *lkey);
+ return hret;
+}
+
+u64 ehea_h_register_rpage_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx mr_handle->handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ mr_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if ((count > 1) && (log_pageaddr & 0xfff)) {
+ EDEB_ERR(4, "log_pageaddr not on a 4k boundary");
+ hret = H_PARAMETER;
+ } else
+ hret = ehea_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ mr_handle, log_pageaddr, count);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ struct hcp_query_ehea *query_ehea_cb = (struct hcp_query_ehea *)cb_addr;
+ u64 cb_logaddr;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX query_ehea_cb=%p",
+ hcp_adapter_handle, query_ehea_cb);
+
+ cb_logaddr = virt_to_abs(cb_addr);
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA,
+ hcp_adapter_handle, /* >R4 */
+ cb_logaddr, /* >R5 */
+ 0, 0, 0, 0, 0, /* >R6-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_query_ehea),
+ "hcp_query_ehea");
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_QUERY_EHEA failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_query_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 port_info = 0;
+ u64 arr_index = 0;
+ u64 dummy = 0;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X cb_cat=%X "
+ "select_mask=%lX cb_addr=%lX",
+ hcp_adapter_handle, port_num, cb_cat, select_mask, cb_logaddr);
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA_PORT,
+ hcp_adapter_handle, /* >R4 */
+ port_info, /* >R5 */
+ select_mask, /* >R6 */
+ arr_index, /* >R7 */
+ cb_logaddr, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_QUERY_EHEA_PORT failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_modify_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 port_info = 0;
+ u64 arr_index = 0;
+ u64 dummy = 0;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X cb_cat=%X "
+ "select_mask=%lX cb_addr=%lX",
+ hcp_adapter_handle, port_num, cb_cat, select_mask, cb_logaddr);
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+ EDEB_DMP(7, (u8 *) cb_addr,
+ sizeof(struct hcp_query_ehea_port_cb_0), "Before HCALL");
+
+ hret = ehea_hcall_7arg_7ret(H_MODIFY_EHEA_PORT,
+ hcp_adapter_handle, /* >R4 */
+ port_info, /* >R5 */
+ select_mask, /* >R6 */
+ arr_index, /* >R7 */
+ cb_logaddr, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_MODIFY_EHEA_PORT failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_reg_dereg_bcmc(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 reg_type,
+ const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 r5_port_num = 0;
+ u64 r6_reg_type = 0;
+ u64 r7_mc_mac_addr = 0;
+ u64 r8_vlan_id = 0;
+ u64 dummy = 0;
+
+ u64 mac_addr = mc_mac_addr >> 16;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X reg_type=%X "
+ "mc_mac_addr=%lX hcall_id=%X",
+ hcp_adapter_handle, port_num, reg_type, mc_mac_addr, hcall_id);
+
+ r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
+ r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
+ r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
+ r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
+
+
+ hret = ehea_hcall_7arg_7ret(hcall_id,
+ hcp_adapter_handle, /* >R4 */
+ r5_port_num, /* >R5 */
+ r6_reg_type, /* >R6 */
+ r7_mc_mac_addr, /* >R7 */
+ r8_vlan_id, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "HCALL 0x%x failed. hret=%lx", hcall_id, hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 ehea_h_reset_events(const u64 hcp_adapter_handle,
+ const u64 neq_handle, const u64 event_mask)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX neq_handle=%lX event_mask=%lX ",
+ hcp_adapter_handle, neq_handle, event_mask);
+
+ hret = ehea_hcall_7arg_7ret(H_RESET_EVENTS,
+ hcp_adapter_handle, /* >R4 */
+ neq_handle, /* >R5 */
+ event_mask, /* >R6 */
+ 0, 0, 0, 0, /* >R7-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_RESET_EVENTS failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_phyp.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.h 2006-06-08 01:58:29.599230968 -0700
@@ -0,0 +1,625 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.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.
+ */
+
+#ifndef __EHEA_PHYP_H__
+#define __EHEA_PHYP_H__
+
+#include <linux/delay.h>
+#include <asm/hvcall.h>
+#include "ehea.h"
+#include "ehea_hw.h"
+#include "ehea_hcall.h"
+
+
+static inline u32 get_longbusy_msecs(int long_busy_ret_code)
+{
+ switch (long_busy_ret_code) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+
+/* Notification Event Queue (NEQ) Entry bit masks */
+#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
+#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
+#define NEQE_PORT_UP EHEA_BMASK_IBM(16, 16)
+#define NEQE_EXTSWITCH_PORT_UP EHEA_BMASK_IBM(17, 17)
+#define NEQE_EXTSWITCH_PRIMARY EHEA_BMASK_IBM(18, 18)
+#define NEQE_PLID EHEA_BMASK_IBM(16, 47)
+
+/* Notification Event Codes */
+#define EHEA_EC_PORTSTATE_CHG 0x30
+#define EHEA_EC_ADAPTER_MALFUNC 0x32
+#define EHEA_EC_PORT_MALFUNC 0x33
+
+/* Notification Event Log Register (NELR) bit masks */
+#define NELR_PORT_MALFUNC EHEA_BMASK_IBM(61, 61)
+#define NELR_ADAPTER_MALFUNC EHEA_BMASK_IBM(62, 62)
+#define NELR_PORTSTATE_CHG EHEA_BMASK_IBM(63, 63)
+
+static inline long ehea_hcall_9arg_9ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7,
+ unsigned long *out8,
+ unsigned long *out9)
+{
+ long hret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
+ "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9);
+
+
+ for (i = 0; i < 5; i++) {
+ hret = plpar_hcall_9arg_9ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ out1, out2, out3, out4,
+ out5, out6, out7, out8,
+ out9);
+
+ if (H_IS_LONG_BUSY(hret)) {
+ sleep_msecs = get_longbusy_msecs(hret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (hret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx hret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
+ " arg9=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx out8=%lx"
+ " out9=%lx",
+ opcode, hret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7, *out8,
+ *out9);
+
+ EDEB_EX(7, "opcode=%lx hret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx out9=%lx",
+ opcode, hret,*out1, *out2, *out3, *out4, *out5, *out6,
+ *out7, *out8, *out9);
+ return hret;
+
+ }
+
+ EDEB_EX(7, "opcode=%lx ret=H_BUSY", opcode);
+ return H_BUSY;
+}
+
+inline static long ehea_hcall_7arg_7ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7)
+{
+ long hret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx arg5=%lx"
+ " arg6=%lx arg7=%lx", opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+
+ for (i = 0; i < 5; i++) {
+ hret = plpar_hcall_7arg_7ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ out1, out2, out3, out4,
+ out5, out6, out7);
+
+ if (H_IS_LONG_BUSY(hret)) {
+ sleep_msecs = get_longbusy_msecs(hret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (hret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx",
+ opcode, hret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7);
+
+ EDEB_EX(7, "opcode=%lx hret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx",
+ opcode, hret, *out1, *out2, *out3, *out4, *out5,
+ *out6, *out7);
+ return hret;
+ }
+
+ EDEB_EX(7, "opcode=%lx hret=H_BUSY", opcode);
+
+ return H_BUSY;
+}
+
+static inline int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user)
+{
+
+ EDEB_EN(7, "ioremap physaddr=%lx mapaddr=%lx\n",
+ paddr_kernel, galpas->kernel.fw_handle);
+ galpas->kernel.fw_handle = (u64) ioremap(paddr_kernel, PAGE_SIZE);
+ galpas->user.fw_handle = paddr_user;
+
+ EDEB_EX(7, "paddr_kernel=%lx paddr_user=%lx galpas->kernel=%lx"
+ " galpas->user=%lx", paddr_kernel, paddr_user,
+ galpas->kernel.fw_handle, galpas->user.fw_handle);
+ return 0;
+}
+
+static inline int hcp_galpas_dtor(struct h_galpas *galpas)
+{
+
+ if (galpas->kernel.fw_handle)
+ iounmap((void *)galpas->kernel.fw_handle);
+ galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
+ return 0;
+}
+
+struct hcp_modify_qp_cb_0 {
+ u64 qp_ctl_reg; /* 00 */
+ u32 max_swqe; /* 02 */
+ u32 max_rwqe; /* 03 */
+ u32 port_nb; /* 04 */
+ u32 reserved0; /* 05 */
+ u64 qp_aer; /* 06 */
+ u64 qp_tenure; /* 08 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
+#define H_QPCB0_ALL EHEA_BMASK_IBM(0, 5)
+#define H_QPCB0_QP_CTL_REG EHEA_BMASK_IBM(0, 0)
+#define H_QPCB0_MAX_SWQE EHEA_BMASK_IBM(1, 1)
+#define H_QPCB0_MAX_RWQE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB0_PORT_NB EHEA_BMASK_IBM(3, 3)
+#define H_QPCB0_QP_AER EHEA_BMASK_IBM(4, 4)
+#define H_QPCB0_QP_TENURE EHEA_BMASK_IBM(5, 5)
+
+/* Queue Pair Control Register Status Bits */
+#define H_QP_CR_ENABLED 0x8000000000000000 /* Queue Pair enabled */
+ /* QP States: */
+#define H_QP_CR_STATE_RESET 0x0000010000000000 /* Reset */
+#define H_QP_CR_STATE_INITIALIZED 0x0000020000000000 /* Initialized */
+#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000 /* Ready to receive */
+#define H_QP_CR_STATE_RDY2SND 0x0000050000000000 /* Ready to send */
+#define H_QP_CR_STATE_ERROR 0x0000800000000000 /* Error */
+
+struct hcp_modify_qp_cb_1 {
+ u32 qpn; /* 00 */
+ u32 qp_asyn_ev_eq_nb; /* 01 */
+ u64 sq_cq_handle; /* 02 */
+ u64 rq_cq_handle; /* 04 */
+ /* sgel = scatter gather element */
+ u32 sgel_nb_sq; /* 06 */
+ u32 sgel_nb_rq1; /* 07 */
+ u32 sgel_nb_rq2; /* 08 */
+ u32 sgel_nb_rq3; /* 09 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
+#define H_QPCB1_ALL EHEA_BMASK_IBM(0, 7)
+#define H_QPCB1_QPN EHEA_BMASK_IBM(0, 0)
+#define H_QPCB1_ASYN_EV_EQ_NB EHEA_BMASK_IBM(1, 1)
+#define H_QPCB1_SQ_CQ_HANDLE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB1_RQ_CQ_HANDLE EHEA_BMASK_IBM(3, 3)
+#define H_QPCB1_SGEL_NB_SQ EHEA_BMASK_IBM(4, 4)
+#define H_QPCB1_SGEL_NB_RQ1 EHEA_BMASK_IBM(5, 5)
+#define H_QPCB1_SGEL_NB_RQ2 EHEA_BMASK_IBM(6, 6)
+#define H_QPCB1_SGEL_NB_RQ3 EHEA_BMASK_IBM(7, 7)
+
+struct hcp_query_ehea {
+ u32 cur_num_qps; /* 00 */
+ u32 cur_num_cqs; /* 01 */
+ u32 cur_num_eqs; /* 02 */
+ u32 cur_num_mrs; /* 03 */
+ u32 auth_level; /* 04 */
+ u32 max_num_qps; /* 05 */
+ u32 max_num_cqs; /* 06 */
+ u32 max_num_eqs; /* 07 */
+ u32 max_num_mrs; /* 08 */
+ u32 reserved0; /* 09 */
+ u32 int_clock_freq; /* 10 */
+ u32 max_num_pds; /* 11 */
+ u32 max_num_addr_handles; /* 12 */
+ u32 max_num_cqes; /* 13 */
+ u32 max_num_wqes; /* 14 */
+ u32 max_num_sgel_rq1wqe; /* 15 */
+ u32 max_num_sgel_rq2wqe; /* 16 */
+ u32 max_num_sgel_rq3wqe; /* 17 */
+ u32 mr_page_size; /*define */
+ u32 reserved1; /* 19 */
+ u64 max_mr_size; /* 20 */
+ u64 reserved2; /* 22 */
+ u32 num_ports; /* 24 */
+ u32 reserved3; /* 25 */
+ u32 reserved4; /* 26 */
+ u32 reserved5; /* 27 */
+ u64 max_mc_mac; /* 28 */
+ u64 ehea_cap; /* 30 */
+ u32 max_isn_per_eq; /* 32 */
+ u32 max_num_neq; /* 33 */
+ u64 max_num_vlan_ids; /* 34 */
+ u32 max_num_port_group; /* 36 */
+ u32 max_num_phys_port; /* 37 */
+
+};
+
+/* Hcall Query/Modify Port Control Block defines */
+#define H_PORT_CB0 0
+#define H_PORT_CB1 1
+#define H_PORT_CB2 2
+#define H_PORT_CB3 3
+#define H_PORT_CB4 4
+#define H_PORT_CB5 5
+#define H_PORT_CB6 6
+#define H_PORT_CB7 7
+
+struct hcp_query_ehea_port_cb_0 {
+ u64 port_mac_addr;
+ u64 port_rc;
+ u64 reserved0;
+ u32 port_op_state;
+ u32 port_speed;
+ u32 ext_swport_op_state;
+ u32 neg_tpf_prpf;
+ u32 num_default_qps;
+ u32 reserved1;
+ u64 default_qpn_array[16];
+};
+
+/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
+#define H_PORT_CB0_ALL EHEA_BMASK_IBM(0, 7) /* Set all bits */
+#define H_PORT_CB0_MAC EHEA_BMASK_IBM(0, 0) /* MAC address */
+#define H_PORT_CB0_PRC EHEA_BMASK_IBM(1, 1) /* Port Recv Control */
+#define H_PORT_CB0_DEFQPNARRAY EHEA_BMASK_IBM(7, 7) /* Default QPN Array */
+
+/* Hcall Query Port: Returned port speed values */
+#define H_PORT_SPEED_10M_H 1 /* 10 Mbps, Half Duplex */
+#define H_PORT_SPEED_10M_F 2 /* 10 Mbps, Full Duplex */
+#define H_PORT_SPEED_100M_H 3 /* 100 Mbps, Half Duplex */
+#define H_PORT_SPEED_100M_F 4 /* 100 Mbps, Full Duplex */
+#define H_PORT_SPEED_1G_F 6 /* 1 Gbps, Full Duplex */
+#define H_PORT_SPEED_10G_F 8 /* 10 Gbps, Full Duplex */
+
+/* Port Receive Control Status Bits */
+#define PXLY_RC_VALID EHEA_BMASK_IBM(49, 49)
+#define PXLY_RC_VLAN_XTRACT EHEA_BMASK_IBM(50, 50)
+#define PXLY_RC_TCP_6_TUPLE EHEA_BMASK_IBM(51, 51)
+#define PXLY_RC_UDP_6_TUPLE EHEA_BMASK_IBM(52, 52)
+#define PXLY_RC_TCP_3_TUPLE EHEA_BMASK_IBM(53, 53)
+#define PXLY_RC_TCP_2_TUPLE EHEA_BMASK_IBM(54, 54)
+#define PXLY_RC_LLC_SNAP EHEA_BMASK_IBM(55, 55)
+#define PXLY_RC_JUMBO_FRAME EHEA_BMASK_IBM(56, 56)
+#define PXLY_RC_FRAG_IP_PKT EHEA_BMASK_IBM(57, 57)
+#define PXLY_RC_TCP_UDP_CHKSUM EHEA_BMASK_IBM(58, 58)
+#define PXLY_RC_IP_CHKSUM EHEA_BMASK_IBM(59, 59)
+#define PXLY_RC_MAC_FILTER EHEA_BMASK_IBM(60, 60)
+#define PXLY_RC_UNTAG_FILTER EHEA_BMASK_IBM(61, 61)
+#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
+
+#define PXLY_RC_VLAN_FILTER 2
+#define PXLY_RC_VLAN_PERM 0
+
+
+#define H_PORT_CB1_ALL 0x8000000000000000
+
+struct hcp_query_ehea_port_cb_1 {
+ u64 vlan_filter[64];
+};
+
+#define H_PORT_CB2_ALL 0xFFE0000000000000
+
+struct hcp_query_ehea_port_cb_2 {
+ u64 rxo;
+ u64 rxucp;
+ u64 rxufd;
+ u64 rxuerr;
+ u64 rxftl;
+ u64 rxmcp;
+ u64 rxbcp;
+ u64 txo;
+ u64 txucp;
+ u64 txmcp;
+ u64 txbcp;
+};
+
+struct hcp_query_ehea_port_cb_3 {
+ u64 vlan_bc_filter[64];
+ u64 vlan_mc_filter[64];
+ u64 vlan_un_filter[64];
+ u64 port_mac_hash_array[64];
+};
+
+#define H_PORT_CB4_ALL 0xF000000000000000
+#define H_PORT_CB4_JUMBO 0x1000000000000000
+
+struct hcp_query_ehea_port_cb_4 {
+ u32 port_speed;
+ u32 pause_frame;
+ u32 ens_port_op_state;
+ u32 jumbo_frame;
+ u32 ens_port_wrap;
+};
+
+struct hcp_query_ehea_port_cb_5 {
+ u64 prc; /* 00 */
+ u64 uaa; /* 01 */
+ u64 macvc; /* 02 */
+ u64 xpcsc; /* 03 */
+ u64 xpcsp; /* 04 */
+ u64 pcsid; /* 05 */
+ u64 xpcsst; /* 06 */
+ u64 pthlb; /* 07 */
+ u64 pthrb; /* 08 */
+ u64 pqu; /* 09 */
+ u64 pqd; /* 10 */
+ u64 prt; /* 11 */
+ u64 wsth; /* 12 */
+ u64 rcb; /* 13 */
+ u64 rcm; /* 14 */
+ u64 rcu; /* 15 */
+ u64 macc; /* 16 */
+ u64 pc; /* 17 */
+ u64 pst; /* 18 */
+ u64 ducqpn; /* 19 */
+ u64 mcqpn; /* 20 */
+ u64 mma; /* 21 */
+ u64 pmc0h; /* 22 */
+ u64 pmc0l; /* 23 */
+ u64 lbc; /* 24 */
+};
+
+#define H_PORT_CB6_ALL 0xFFFFFE7FFFFF8000
+
+struct hcp_query_ehea_port_cb_6 {
+ u64 rxo; /* 00 */
+ u64 rx64; /* 01 */
+ u64 rx65; /* 02 */
+ u64 rx128; /* 03 */
+ u64 rx256; /* 04 */
+ u64 rx512; /* 05 */
+ u64 rx1024; /* 06 */
+ u64 rxbfcs; /* 07 */
+ u64 rxime; /* 08 */
+ u64 rxrle; /* 09 */
+ u64 rxorle; /* 10 */
+ u64 rxftl; /* 11 */
+ u64 rxjab; /* 12 */
+ u64 rxse; /* 13 */
+ u64 rxce; /* 14 */
+ u64 rxrf; /* 15 */
+ u64 rxfrag; /* 16 */
+ u64 rxuoc; /* 17 */
+ u64 rxcpf; /* 18 */
+ u64 rxsb; /* 19 */
+ u64 rxfd; /* 20 */
+ u64 rxoerr; /* 21 */
+ u64 rxaln; /* 22 */
+ u64 ducqpn; /* 23 */
+ u64 reserved0; /* 24 */
+ u64 rxmcp; /* 25 */
+ u64 rxbcp; /* 26 */
+ u64 txmcp; /* 27 */
+ u64 txbcp; /* 28 */
+ u64 txo; /* 29 */
+ u64 tx64; /* 30 */
+ u64 tx65; /* 31 */
+ u64 tx128; /* 32 */
+ u64 tx256; /* 33 */
+ u64 tx512; /* 34 */
+ u64 tx1024; /* 35 */
+ u64 txbfcs; /* 36 */
+ u64 txcpf; /* 37 */
+ u64 txlf; /* 38 */
+ u64 txrf; /* 39 */
+ u64 txime; /* 40 */
+ u64 txsc; /* 41 */
+ u64 txmc; /* 42 */
+ u64 txsqe; /* 43 */
+ u64 txdef; /* 44 */
+ u64 txlcol; /* 45 */
+ u64 txexcol; /* 46 */
+ u64 txcse; /* 47 */
+ u64 txbor; /* 48 */
+};
+
+struct hcp_query_ehea_port_cb_7 {
+ u64 def_uc_qpn;
+};
+
+u64 ehea_h_query_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask,
+ void *cb_addr);
+
+u64 ehea_h_modify_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 cat,
+ const u64 qp_handle,
+ const u64 sel_mask,
+ void *cb_addr,
+ u64 * inv_attr_id,
+ u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+
+u64 ehea_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *ehea_eq,
+ struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+
+u64 ehea_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *ehea_cq,
+ struct ehea_cq_attr *cq_attr,
+ u64 * cq_handle, struct h_galpas *galpas);
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp *ehea_qp,
+ struct ehea_qp_init_attr *init_attr,
+ const u32 pd,
+ u64 * qp_handle, struct h_galpas *h_galpas);
+
+#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48,55)
+#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62,63)
+
+u64 ehea_h_register_rpage(const u64 hcp_adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 log_pageaddr, u64 count);
+
+u64 ehea_h_register_rpage_eq(const u64 hcp_adapter_handle,
+ const u64 eq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count);
+
+u64 ehea_h_register_rpage_cq(const u64 hcp_adapter_handle,
+ const u64 cq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, const struct h_galpa gal);
+
+u64 ehea_h_register_rpage_qp(const u64 hcp_adapter_handle,
+ const u64 qp_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, struct h_galpa galpa);
+
+#define H_DISABLE_GET_EHEA_WQE_P 1
+#define H_DISABLE_GET_SQ_WQE_P 2
+#define H_DISABLE_GET_RQC 3
+
+u64 ehea_h_destroy_qp(const u64 hcp_adapter_handle,
+ struct ehea_qp *qp,
+ u64 qp_handle, struct h_galpas *galpas);
+
+u64 ehea_h_destroy_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *cq,
+ u64 cq_handle, struct h_galpas *galpas);
+
+u64 ehea_h_destroy_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *eq,
+ u64 eq_handle, struct h_galpas *galpas);
+
+u64 ehea_h_free_resource_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle);
+
+
+u64 ehea_h_alloc_resource_mr(const u64 hcp_adapter_handle,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const u32 pd, u64 * mr_handle, u32 * lkey);
+
+u64 ehea_h_register_rpage_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count);
+
+u64 ehea_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr);
+
+/* output param R5 */
+#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40,47)
+#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48,63)
+
+u64 ehea_h_query_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr);
+
+u64 ehea_h_modify_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr);
+
+#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
+#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
+#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
+
+u64 ehea_h_reg_dereg_bcmc(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 reg_type,
+ const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id);
+
+u64 ehea_h_reset_events(const u64 hcp_adapter_handle,
+ const u64 neq_handle, const u64 event_mask);
+
+#endif /* __EHEA_PHYP_H__ */
^ permalink raw reply
* [PATCH 0/5] ehea: IBM eHEA Ethernet Device Driver
From: Jan-Bernd Themann @ 2006-06-08 9:55 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Hello,
thanks for your comments. It seems that yesterday's patch 1/4 has not been
delivered. We changed some things according to your comments.
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Changelog-by: Jan-Bernd Themann <themann@de.ibm.com>
Differences to patch set http://www.spinics.net/lists/netdev/msg05813.html
Changelog:
- reduce number of parameters for debug macro calls
- ehea prefix added to some non static functions
- Makefile and Kconfig improved
drivers/net/ehea/Kconfig | 6
drivers/net/ehea/Makefile | 7
drivers/net/ehea/ehea.h | 434 +++++++
drivers/net/ehea/ehea_hw.h | 319 +++++
drivers/net/ehea/ehea_main.c | 2562 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_phyp.c | 1023 +++++++++++++++++
drivers/net/ehea/ehea_phyp.h | 625 ++++++++++
drivers/net/ehea/ehea_qmr.c | 719 ++++++++++++
drivers/net/ehea/ehea_qmr.h | 390 ++++++
9 files changed, 6085 insertions(+)
^ permalink raw reply
* Re: [PATCH v2 4/7] AMSO1100 Memory Management.
From: Andrew Morton @ 2006-06-08 8:17 UTC (permalink / raw)
To: Steve Wise; +Cc: rdreier, mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <20060607200655.9259.90768.stgit@stevo-desktop>
On Wed, 07 Jun 2006 15:06:55 -0500
Steve Wise <swise@opengridcomputing.com> wrote:
>
> +void c2_free(struct c2_alloc *alloc, u32 obj)
> +{
> + spin_lock(&alloc->lock);
> + clear_bit(obj, alloc->table);
> + spin_unlock(&alloc->lock);
> +}
The spinlock is unneeded here.
What does all the code in this file do, anyway? It looks totally generic
(and hence inappropriate for drivers/infiniband/hw/amso1100/) and somewhat
similar to idr trees, perhaps.
> +int c2_array_set(struct c2_array *array, int index, void *value)
> +{
> + int p = (index * sizeof(void *)) >> PAGE_SHIFT;
> +
> + /* Allocate with GFP_ATOMIC because we'll be called with locks held. */
> + if (!array->page_list[p].page)
> + array->page_list[p].page =
> + (void **) get_zeroed_page(GFP_ATOMIC);
> +
> + if (!array->page_list[p].page)
> + return -ENOMEM;
This _will_ happen under load. What will the result of that be, in the
context of thise driver?
This function is incorrectly designed - it should receive a gfp_t argument.
Because you don't *know* that the caller will always hold a spinlock. And
GFP_KERNEL is far, far stronger than GFP_ATOMIC.
> +static int c2_alloc_mqsp_chunk(gfp_t gfp_mask, struct sp_chunk **head)
> +{
> + int i;
> + struct sp_chunk *new_head;
> +
> + new_head = (struct sp_chunk *) __get_free_page(gfp_mask | GFP_DMA);
Why is __GFP_DMA in there? Unless you've cornered the ISA bus infiniband
market, it's likely to be wrong.
^ permalink raw reply
* Re: [PATCH v2 1/2] iWARP Connection Manager.
From: Andrew Morton @ 2006-06-08 7:54 UTC (permalink / raw)
To: Steve Wise; +Cc: rdreier, mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <20060607200605.9003.25830.stgit@stevo-desktop>
On Wed, 07 Jun 2006 15:06:05 -0500
Steve Wise <swise@opengridcomputing.com> wrote:
>
> This patch provides the new files implementing the iWARP Connection
> Manager.
>
> Review Changes:
>
> - sizeof -> sizeof()
>
> - removed printks
>
> - removed TT debug code
>
> - cleaned up lock/unlock around switch statements.
>
> - waitqueue -> completion for destroy path.
>
> ...
>
> +/*
> + * This function is called on interrupt context. Schedule events on
> + * the iwcm_wq thread to allow callback functions to downcall into
> + * the CM and/or block. Events are queued to a per-CM_ID
> + * work_list. If this is the first event on the work_list, the work
> + * element is also queued on the iwcm_wq thread.
> + *
> + * Each event holds a reference on the cm_id. Until the last posted
> + * event has been delivered and processed, the cm_id cannot be
> + * deleted.
> + */
> +static void cm_event_handler(struct iw_cm_id *cm_id,
> + struct iw_cm_event *iw_event)
> +{
> + struct iwcm_work *work;
> + struct iwcm_id_private *cm_id_priv;
> + unsigned long flags;
> +
> + work = kmalloc(sizeof(*work), GFP_ATOMIC);
> + if (!work)
> + return;
This allocation _will_ fail sometimes. The driver must recover from it.
Will it do so?
> +EXPORT_SYMBOL(iw_cm_init_qp_attr);
This file exports a ton of symbols. It's usual to provide some justifying
commentary in the changelog when this happens.
> +/*
> + * Copyright (c) 2005 Network Appliance, Inc. All rights reserved.
> + * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
> + *
> + * This software is available to you under a choice of one of two
> + * licenses. You may choose to be licensed under the terms of the GNU
> + * General Public License (GPL) Version 2, available from the file
> + * COPYING in the main directory of this source tree, or the
> + * OpenIB.org BSD license below:
> + *
> + * Redistribution and use in source and binary forms, with or
> + * without modification, are permitted provided that the following
> + * conditions are met:
> + *
> + * - Redistributions of source code must retain the above
> + * copyright notice, this list of conditions and the following
> + * disclaimer.
> + *
> + * - Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the following
> + * disclaimer in the documentation and/or other materials
> + * provided with the distribution.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +#if !defined(IW_CM_PRIVATE_H)
> +#define IW_CM_PRIVATE_H
We normally use #ifndef here.
^ permalink raw reply
* [PATCH 12/12] d80211: remove procfs files
From: Jiri Benc @ 2006-06-08 7:49 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>
Remove procfs support.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/Makefile | 1
net/d80211/ieee80211.c | 7
net/d80211/ieee80211_iface.c | 3
net/d80211/ieee80211_proc.c | 768 ------------------------------------------
net/d80211/ieee80211_proc.h | 48 ---
net/d80211/ieee80211_sysfs.c | 33 ++
net/d80211/rate_control.c | 25 -
net/d80211/rate_control.h | 17 -
net/d80211/sta_info.c | 4
9 files changed, 32 insertions(+), 874 deletions(-)
delete mode 100644 net/d80211/ieee80211_proc.c
delete mode 100644 net/d80211/ieee80211_proc.h
89c13fc02b12796d1f57c33c7fae1bcf875d846b
diff --git a/net/d80211/Makefile b/net/d80211/Makefile
index 7d1ec29..c21e882 100644
--- a/net/d80211/Makefile
+++ b/net/d80211/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_D80211) += 80211.o rate_con
sta_info.o \
wep.o \
wpa.o \
- ieee80211_proc.o \
ieee80211_scan.o \
ieee80211_sta.o \
ieee80211_dev.o \
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 1a03f07..a8ca8d1 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -25,7 +25,6 @@ #include <net/d80211.h>
#include <net/d80211_common.h>
#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
-#include "ieee80211_proc.h"
#include "rate_control.h"
#include "wep.h"
#include "wpa.h"
@@ -4256,7 +4255,6 @@ int ieee80211_register_hw(struct net_dev
ieee80211_install_qdisc(dev);
ieee80211_wep_init(local);
- ieee80211_proc_init_interface(local);
/* add one default STA interface */
rtnl_lock();
@@ -4359,8 +4357,6 @@ void ieee80211_unregister_hw(struct net_
kfree(local->basic_rates[i]);
}
- ieee80211_proc_deinit_interface(local);
-
if (skb_queue_len(&local->skb_queue)
|| skb_queue_len(&local->skb_queue_unreliable))
printk(KERN_WARNING "%s: skb_queue not empty", dev->name);
@@ -4520,14 +4516,12 @@ static int __init ieee80211_init(void)
return ret;
}
- ieee80211_proc_init();
{
ret = ieee80211_wme_register();
if (ret) {
printk(KERN_DEBUG "ieee80211_init: failed to "
"initialize WME (err=%d)\n", ret);
ieee80211_sysfs_deinit();
- ieee80211_proc_deinit();
return ret;
}
}
@@ -4539,7 +4533,6 @@ static int __init ieee80211_init(void)
static void __exit ieee80211_exit(void)
{
ieee80211_wme_unregister();
- ieee80211_proc_deinit();
ieee80211_sysfs_deinit();
}
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 960a90e..5abd713 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -14,7 +14,6 @@ #include <linux/rtnetlink.h>
#include <net/d80211.h>
#include <net/d80211_mgmt.h>
#include "ieee80211_i.h"
-#include "ieee80211_proc.h"
#include "sta_info.h"
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
@@ -85,7 +84,6 @@ int ieee80211_if_add(struct net_device *
}
list_add(&sdata->list, &local->sub_if_list);
- ieee80211_proc_init_virtual(ndev);
return 0;
@@ -307,7 +305,6 @@ void __ieee80211_if_del(struct ieee80211
ieee80211_if_reinit(dev);
list_del(&sdata->list);
- ieee80211_proc_deinit_virtual(dev);
ieee80211_sysfs_remove_netdevice(dev);
unregister_netdevice(dev);
/* Except master interface, the net_device will be freed by
diff --git a/net/d80211/ieee80211_proc.c b/net/d80211/ieee80211_proc.c
deleted file mode 100644
index 4bb3179..0000000
--- a/net/d80211/ieee80211_proc.c
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright 2003-2005, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/config.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-
-#ifdef CONFIG_PROC_FS
-
-#include <net/d80211.h>
-#include <net/d80211_common.h>
-#include <net/d80211_mgmt.h>
-#include "ieee80211_i.h"
-#include "sta_info.h"
-#include "ieee80211_proc.h"
-#include "rate_control.h"
-
-
-static struct proc_dir_entry *ieee80211_proc;
-
-#define PROC_LIMIT (PAGE_SIZE - 80)
-
-
-static char * ieee80211_proc_key(char *p, struct ieee80211_key *key,
- int idx, int def_key)
-{
- int i;
- u8 *tpn, *rpn;
-
- if (!key)
- return p;
-
- p += sprintf(p, "key[%d]%s len=%d sw_encrypt=%d idx=%d hwidx=%d "
- "tx_rx_count=%d",
- idx, def_key ? "*" : "", key->keylen,
- key->force_sw_encrypt, key->keyidx, key->hw_key_idx,
- key->tx_rx_count);
- switch (key->alg) {
- case ALG_WEP:
- p += sprintf(p, " alg=WEP");
- break;
- case ALG_TKIP:
- p += sprintf(p, " alg=TKIP iv(tx)=%08x %04x",
- key->u.tkip.iv32, key->u.tkip.iv16);
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
- if (key->u.tkip.iv32_rx[i] == 0 &&
- key->u.tkip.iv16_rx[i] == 0)
- continue;
- p += sprintf(p, " iv(rx %d)=%08x %04x", i,
- key->u.tkip.iv32_rx[i],
- key->u.tkip.iv16_rx[i]);
- }
- break;
- case ALG_CCMP:
- tpn = key->u.ccmp.tx_pn;
- p += sprintf(p, " alg=CCMP PN(tx)=%02x%02x%02x%02x%02x%02x",
- tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
- rpn = key->u.ccmp.rx_pn[i];
- if (memcmp(rpn, "\x00\x00\x00\x00\x00\x00", 6) == 0)
- continue;
- p += sprintf(p, " PN(rx %d)=%02x%02x%02x%02x%02x%02x",
- i, rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
- rpn[5]);
- }
- p += sprintf(p, " replays=%u", key->u.ccmp.replays);
- break;
- default:
- break;
- }
-
- p += sprintf(p, " key=");
- for (i = 0; i < key->keylen; i++)
- p += sprintf(p, "%02x", key->key[i]);
- p += sprintf(p, "\n");
- return p;
-}
-
-
-static char * ieee80211_proc_sub_if_ap(char *p,
- struct ieee80211_if_ap *ap)
-{
- p += sprintf(p, "type=ap\n");
- if (ap->beacon_head)
- p += sprintf(p, "beacon_head_len=%d\n", ap->beacon_head_len);
- if (ap->beacon_tail)
- p += sprintf(p, "beacon_tail_len=%d\n", ap->beacon_tail_len);
- p += sprintf(p,
- "max_aid=%d\n"
- "num_sta_ps=%d\n"
- "num_buffered_multicast=%u\n"
- "dtim_period=%d\n"
- "dtim_count=%d\n"
- "num_beacons=%d\n"
- "force_unicast_rateidx=%d\n"
- "max_ratectrl_rateidx=%d\n",
- ap->max_aid, atomic_read(&ap->num_sta_ps),
- skb_queue_len(&ap->ps_bc_buf),
- ap->dtim_period, ap->dtim_count, ap->num_beacons,
- ap->force_unicast_rateidx, ap->max_ratectrl_rateidx);
- return p;
-}
-
-
-static char * ieee80211_proc_sub_if_sta(char *p, int ibss,
- struct ieee80211_if_sta *ifsta)
-{
- if (ibss)
- p += sprintf(p, "type=ibss\n");
- else
- p += sprintf(p, "type=sta\n");
- p += sprintf(p,
- "state=%d\n"
- "bssid=" MACSTR "\n"
- "prev_bssid=" MACSTR "\n"
- "ssid_len=%zd\n"
- "aid=%d\n"
- "ap_capab=0x%x\n"
- "capab=0x%x\n"
- "extra_ie_len=%zd\n"
- "auth_tries=%d\n"
- "assoc_tries=%d\n"
- "flags=%s%s%s%s%s%s%s\n"
- "auth_algs=0x%x\n"
- "auth_alg=%d\n"
- "auth_transaction=%d\n",
- ifsta->state,
- MAC2STR(ifsta->bssid),
- MAC2STR(ifsta->prev_bssid),
- ifsta->ssid_len,
- ifsta->aid,
- ifsta->ap_capab,
- ifsta->capab,
- ifsta->extra_ie_len,
- ifsta->auth_tries,
- ifsta->assoc_tries,
- ifsta->ssid_set ? "[SSID]" : "",
- ifsta->bssid_set ? "[BSSID]" : "",
- ifsta->prev_bssid_set ? "[prev BSSID" : "",
- ifsta->authenticated ? "[AUTH]" : "",
- ifsta->associated ? "[ASSOC]" : "",
- ifsta->probereq_poll ? "[PROBEREQ POLL]" : "",
- ifsta->use_protection ? "[CTS prot]" : "",
- ifsta->auth_algs,
- ifsta->auth_alg,
- ifsta->auth_transaction);
- return p;
-}
-
-
-static char * ieee80211_proc_sub_if(char *p,
- struct ieee80211_sub_if_data *sdata)
-{
- if (sdata == NULL)
- return p;
-
- if (sdata->bss)
- p += sprintf(p, "bss=%p\n", sdata->bss);
-
- switch (sdata->type) {
- case IEEE80211_IF_TYPE_AP:
- p = ieee80211_proc_sub_if_ap(p, &sdata->u.ap);
- break;
- case IEEE80211_IF_TYPE_WDS:
- p += sprintf(p, "type=wds\n");
- p += sprintf(p, "wds.peer=" MACSTR "\n",
- MAC2STR(sdata->u.wds.remote_addr));
- break;
- case IEEE80211_IF_TYPE_VLAN:
- p += sprintf(p, "type=vlan\n");
- p += sprintf(p, "vlan.id=%d\n", sdata->u.vlan.id);
- break;
- case IEEE80211_IF_TYPE_STA:
- p = ieee80211_proc_sub_if_sta(p, 0, &sdata->u.sta);
- break;
- case IEEE80211_IF_TYPE_IBSS:
- p = ieee80211_proc_sub_if_sta(p, 1, &sdata->u.sta);
- break;
- }
- p += sprintf(p, "channel_use=%d\n", sdata->channel_use);
- p += sprintf(p, "drop_unencrypted=%d\n", sdata->drop_unencrypted);
- p += sprintf(p, "eapol=%d\n", sdata->eapol);
- p += sprintf(p, "ieee802_1x=%d\n", sdata->ieee802_1x);
-
- return p;
-}
-
-
-static int ieee80211_proc_iface_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct net_device *dev = (struct net_device *) data;
- struct ieee80211_sub_if_data *sdata;
- int i;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (!sdata)
- return -1;
-
- p = ieee80211_proc_sub_if(p, sdata);
-
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->keys[i] == NULL)
- continue;
-
- p = ieee80211_proc_key(p, sdata->keys[i], i,
- sdata->keys[i] == sdata->default_key);
- }
-
- return (p - page);
-}
-
-
-static int ieee80211_proc_sta_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct sta_info *sta = (struct sta_info *) data;
- struct ieee80211_local *local;
- int inactive, i;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- if (!sta || !sta->dev)
- return -1;
-
- p += sprintf(p, "aid=%d\n", sta->aid);
- p += sprintf(p, "flags=0x%x %s%s%s%s%s%s%s%s%s%s\n", sta->flags,
- sta->flags & WLAN_STA_AUTH ? "[AUTH]" : "",
- sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : "",
- sta->flags & WLAN_STA_PS ? "[PS]" : "",
- sta->flags & WLAN_STA_TIM ? "[TIM]" : "",
- sta->flags & WLAN_STA_PERM ? "[PERM]" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : "",
- sta->flags & WLAN_STA_SHORT_PREAMBLE ?
- "[SHORT PREAMBLE]" : "",
- sta->flags & WLAN_STA_WME ? "[WME]" : "",
- sta->flags & WLAN_STA_WDS ? "[WDS]" : "",
- sta->flags & WLAN_STA_XR ? "[XR]" : "");
- p += sprintf(p, "key_idx_compression=%d\n",
- sta->key_idx_compression);
- p += sprintf(p, "dev=%s\n", sta->dev->name);
- if (sta->vlan_id > 0)
- p += sprintf(p, "vlan_id=%d\n", sta->vlan_id);
- p += sprintf(p, "rx_packets=%lu\ntx_packets=%lu\nrx_bytes=%lu\n"
- "tx_bytes=%lu\nrx_duplicates=%lu\nrx_fragments=%lu\n"
- "rx_dropped=%lu\ntx_fragments=%lu\ntx_filtered=%lu\n",
- sta->rx_packets, sta->tx_packets,
- sta->rx_bytes, sta->tx_bytes,
- sta->num_duplicates, sta->rx_fragments, sta->rx_dropped,
- sta->tx_fragments, sta->tx_filtered_count);
- p = ieee80211_proc_key(p, sta->key, 0, 1);
-
- local = (struct ieee80211_local *) sta->dev->ieee80211_ptr;
- if (sta->txrate >= 0 && sta->txrate < local->num_curr_rates) {
- p += sprintf(p, "txrate=%d\n",
- local->curr_rates[sta->txrate].rate);
- }
- if (sta->last_txrate >= 0 &&
- sta->last_txrate < local->num_curr_rates) {
- p += sprintf(p, "last_txrate=%d\n",
- local->curr_rates[sta->last_txrate].rate);
- }
- p += sprintf(p, "num_ps_buf_frames=%u\n",
- skb_queue_len(&sta->ps_tx_buf));
- p += sprintf(p, "tx_retry_failed=%lu\n", sta->tx_retry_failed);
- p += sprintf(p, "tx_retry_count=%lu\n", sta->tx_retry_count);
- p += sprintf(p, "last_rssi=%d\n", sta->last_rssi);
- p += sprintf(p, "last_ack_rssi=%d %d %d\n",
- sta->last_ack_rssi[0], sta->last_ack_rssi[1],
- sta->last_ack_rssi[2]);
- if (sta->last_ack)
- p += sprintf(p, "last_ack_ms=%d\n",
- jiffies_to_msecs(jiffies - sta->last_ack));
- inactive = jiffies - sta->last_rx;
- p += sprintf(p, "inactive_msec=%d\n", jiffies_to_msecs(inactive));
- p += sprintf(p, "channel_use=%d\n", sta->channel_use);
- p += sprintf(p, "wep_weak_iv_count=%d\n", sta->wep_weak_iv_count);
-#ifdef CONFIG_D80211_DEBUG_COUNTERS
- p += sprintf(p, "wme_rx_queue=");
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += sprintf(p, "%u ", sta->wme_rx_queue[i]);
- p += sprintf(p, "\n");
-
- p += sprintf(p, "wme_tx_queue=");
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += sprintf(p, "%u ", sta->wme_tx_queue[i]);
- p += sprintf(p, "\n");
-#endif /* CONFIG_D80211_DEBUG_COUNTERS */
- p += sprintf(p, "last_seq_ctrl=");
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
- p += sprintf(p, "%x ", sta->last_seq_ctrl[i]);
- }
- p += sprintf(p, "\n");
-
- p += rate_control_status_sta(local, sta, p);
-
- return (p - page);
-}
-
-
-static int ieee80211_proc_counters_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
- struct ieee80211_low_level_stats stats;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p,
- "TransmittedFragmentCount=%u\n"
- "MulticastTransmittedFrameCount=%u\n"
- "FailedCount=%u\n"
- "RetryCount=%u\n"
- "MultipleRetryCount=%d\n"
- "FrameDuplicateCount=%d\n"
- "ReceivedFragmentCount=%u\n"
- "MulticastReceivedFrameCount=%u\n"
- "TransmittedFrameCount=%u\n"
- "WEPUndecryptableCount=%u\n",
- local->dot11TransmittedFragmentCount,
- local->dot11MulticastTransmittedFrameCount,
- local->dot11FailedCount,
- local->dot11RetryCount,
- local->dot11MultipleRetryCount,
- local->dot11FrameDuplicateCount,
- local->dot11ReceivedFragmentCount,
- local->dot11MulticastReceivedFrameCount,
- local->dot11TransmittedFrameCount,
- local->dot11WEPUndecryptableCount);
-
- memset(&stats, 0, sizeof(stats));
- if (local->hw->get_stats &&
- local->hw->get_stats(local->mdev, &stats) == 0) {
- p += sprintf(p,
- "ACKFailureCount=%u\n"
- "RTSFailureCount=%u\n"
- "FCSErrorCount=%u\n"
- "RTSSuccessCount=%u\n",
- stats.dot11ACKFailureCount,
- stats.dot11RTSFailureCount,
- stats.dot11FCSErrorCount,
- stats.dot11RTSSuccessCount);
- }
-
- return (p - page);
-}
-
-
-static int ieee80211_proc_debug_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
-#ifdef CONFIG_D80211_DEBUG_COUNTERS
- p += sprintf(p,
- "tx_handlers_drop=%u\n"
- "tx_handlers_queued=%u\n"
- "tx_handlers_drop_unencrypted=%u\n"
- "tx_handlers_drop_fragment=%u\n"
- "tx_handlers_drop_wep=%u\n"
- "tx_handlers_drop_rate_limit=%u\n"
- "tx_handlers_drop_not_assoc=%u\n"
- "tx_handlers_drop_unauth_port=%u\n"
- "rx_handlers_drop=%u\n"
- "rx_handlers_queued=%u\n"
- "rx_handlers_drop_nullfunc=%u\n"
- "rx_handlers_drop_defrag=%u\n"
- "rx_handlers_drop_short=%u\n"
- "rx_handlers_drop_passive_scan=%u\n"
- "tx_expand_skb_head=%u\n"
- "tx_expand_skb_head_cloned=%u\n"
- "rx_expand_skb_head=%u\n"
- "rx_expand_skb_head2=%u\n"
- "rx_handlers_fragments=%u\n"
- "tx_status_drop=%u\n",
- local->tx_handlers_drop,
- local->tx_handlers_queued,
- local->tx_handlers_drop_unencrypted,
- local->tx_handlers_drop_fragment,
- local->tx_handlers_drop_wep,
- local->tx_handlers_drop_rate_limit,
- local->tx_handlers_drop_not_assoc,
- local->tx_handlers_drop_unauth_port,
- local->rx_handlers_drop,
- local->rx_handlers_queued,
- local->rx_handlers_drop_nullfunc,
- local->rx_handlers_drop_defrag,
- local->rx_handlers_drop_short,
- local->rx_handlers_drop_passive_scan,
- local->tx_expand_skb_head,
- local->tx_expand_skb_head_cloned,
- local->rx_expand_skb_head,
- local->rx_expand_skb_head2,
- local->rx_handlers_fragments,
- local->tx_status_drop);
- {
- int i;
- p += sprintf(p, "wme_rx_queue=");
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += sprintf(p, " %u", local->wme_rx_queue[i]);
- p += sprintf(p, "\n");
-
- p += sprintf(p, "wme_tx_queue=");
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += sprintf(p, " %u", local->wme_tx_queue[i]);
- p += sprintf(p, "\n");
- }
-#endif /* CONFIG_D80211_DEBUG_COUNTERS */
-
- p += sprintf(p, "num_scans=%u\n", local->scan.num_scans);
-
- return (p - page);
-}
-
-
-const char *ieee80211_mode_str_short(int mode)
-{
- switch (mode) {
- case MODE_IEEE80211A:
- return "802.11a";
- case MODE_IEEE80211B:
- return "802.11b";
- case MODE_IEEE80211G:
- return "802.11g";
- case MODE_ATHEROS_TURBO:
- return "AtherosTurbo";
- default:
- return "UNKNOWN";
- }
-}
-
-
-const char *ieee80211_mode_str(int mode)
-{
- switch (mode) {
- case MODE_IEEE80211A:
- return "IEEE 802.11a";
- case MODE_IEEE80211B:
- return "IEEE 802.11b";
- case MODE_IEEE80211G:
- return "IEEE 802.11g";
- case MODE_ATHEROS_TURBO:
- return "Atheros Turbo (5 GHz)";
- default:
- return "UNKNOWN";
- }
-}
-
-
-static int ieee80211_proc_info_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
- int m;
- struct ieee80211_hw_modes *mode;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "hw_name=%s\n", local->hw->name);
- p += sprintf(p, "modes=");
- for (m = 0; m < local->hw->num_modes; m++) {
- mode = &local->hw->modes[m];
- p += sprintf(p, "[%s]", ieee80211_mode_str_short(mode->mode));
- }
- p += sprintf(p, "\n");
- if (local->rate_ctrl && local->rate_ctrl_priv)
- p+= sprintf(p, "rate_ctrl_alg=%s\n", local->rate_ctrl->name);
- return (p - page);
-}
-
-
-static int ieee80211_proc_config_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p,
- "low_level_driver=%s\n"
- "channel=%d\n"
- "freq=%d\n"
- "mode=%s\n"
- "802.11h=%d\n"
- "wep_iv=0x%06x\n"
- "antenna_sel=%d\n"
- "calib_int=%d\n"
- "tx_power_reduction=%d.%d dBm\n"
- "bridge_packets=%d\n"
- "key_tx_rx_threshold=%d\n"
- "rts_threshold=%d\n"
- "fragmentation_threshold=%d\n"
- "short_retry_limit=%d\n"
- "long_retry_limit=%d\n"
- "total_ps_buffered=%d\n",
- local->hw->name ? local->hw->name : "N/A",
- local->conf.channel,
- local->conf.freq,
- ieee80211_mode_str(local->conf.phymode),
- local->conf.radar_detect,
- local->wep_iv & 0xffffff,
- local->conf.antenna_sel,
- local->conf.calib_int,
- local->conf.tx_power_reduction / 10,
- local->conf.tx_power_reduction % 10,
- local->bridge_packets,
- local->key_tx_rx_threshold,
- local->rts_threshold,
- local->fragmentation_threshold,
- local->short_retry_limit,
- local->long_retry_limit,
- local->total_ps_buffered);
-
- return (p - page);
-}
-
-
-static int ieee80211_proc_channels_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
- int m, c;
- struct ieee80211_hw_modes *mode;
- struct ieee80211_channel *chan;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "MODE CHAN FREQ TXPOWER ANTMAX FLAGS\n");
- for (m = 0; m < local->hw->num_modes; m++) {
- mode = &local->hw->modes[m];
- for (c = 0; c < mode->num_channels; c++) {
- chan = &mode->channels[c];
- p += sprintf(p, "%d %d %d %d %d %s%s%s\n",
- mode->mode, chan->chan, chan->freq,
- chan->power_level, chan->antenna_max,
- chan->flag & IEEE80211_CHAN_W_SCAN ?
- "[W_SCAN]" : "",
- chan->flag & IEEE80211_CHAN_W_ACTIVE_SCAN
- ? "[W_ACTIVE_SCAN]" : "",
- chan->flag & IEEE80211_CHAN_W_IBSS ?
- "[W_IBSS]" : "");
- }
- }
- return (p - page);
-}
-
-
-static int ieee80211_proc_rates_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
- int r;
- struct ieee80211_rate *rate;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- p += sprintf(p, "RATE VAL VAL2 MIN_RSSI_ACK MIN_RSSI_ACK_DELTA "
- "FLAGS\n");
- for (r = 0; r < local->num_curr_rates; r++) {
- rate = &local->curr_rates[r];
- p += sprintf(p, "%d %d %d %d %d 0x%x %s%s%s%s%s%s%s%s\n",
- rate->rate, rate->val, rate->val2,
- rate->min_rssi_ack, rate->min_rssi_ack_delta,
- rate->flags,
- rate->flags & IEEE80211_RATE_ERP ? "[ERP]" : "",
- rate->flags & IEEE80211_RATE_BASIC ?
- "[BASIC]" : "",
- rate->flags & IEEE80211_RATE_PREAMBLE2 ?
- "[PREAMBLE2]" : "",
- rate->flags & IEEE80211_RATE_SUPPORTED ?
- "[SUPPORTED]" : "",
- rate->flags & IEEE80211_RATE_OFDM ? "[OFDM]" : "",
- rate->flags & IEEE80211_RATE_CCK ? "[CCK]" : "",
- rate->flags & IEEE80211_RATE_TURBO ?
- "[TURBO]" : "",
- rate->flags & IEEE80211_RATE_MANDATORY ?
- "[MANDATORY]" : "");
- }
- return (p - page);
-}
-
-
-static int ieee80211_proc_multicast_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- struct ieee80211_local *local = (struct ieee80211_local *) data;
-
- if (off != 0) {
- *eof = 1;
- return 0;
- }
-
- return rate_control_status_global(local, p);
-
-}
-
-
-void ieee80211_proc_init_sta(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- char buf[30];
- struct proc_dir_entry *entry;
-
- sprintf(buf, MACSTR, MAC2STR(sta->addr));
-
- if (!local->proc_sta)
- return;
-
- entry = create_proc_read_entry(buf, 0, local->proc_sta,
- ieee80211_proc_sta_read, sta);
- if (entry) {
- entry->mode &= ~(S_IRWXG | S_IRWXO);
- }
-}
-
-
-void ieee80211_proc_deinit_sta(struct ieee80211_local *local,
- struct sta_info *sta)
-{
- char buf[30];
- sprintf(buf, MACSTR, MAC2STR(sta->addr));
- if (local->proc_sta) {
- remove_proc_entry(buf, local->proc_sta);
- }
-}
-
-
-void ieee80211_proc_init_virtual(struct net_device *dev)
-{
- struct proc_dir_entry *entry;
- struct ieee80211_local *local = dev->ieee80211_ptr;
-
- if (!local->proc_iface)
- return;
-
- entry = create_proc_read_entry(dev->name, 0, local->proc_iface,
- ieee80211_proc_iface_read, dev);
- if (entry)
- entry->mode &= ~(S_IRWXG | S_IRWXO);
-}
-
-
-void ieee80211_proc_deinit_virtual(struct net_device *dev)
-{
- struct ieee80211_local *local = dev->ieee80211_ptr;
-
- if (local->proc_iface)
- remove_proc_entry(dev->name, local->proc_iface);
-}
-
-
-void ieee80211_proc_init_interface(struct ieee80211_local *local)
-{
- if (!ieee80211_proc)
- return;
-
- local->proc = proc_mkdir(local->mdev->name, ieee80211_proc);
- if (!local->proc)
- return;
-
- local->proc_sta = proc_mkdir("sta", local->proc);
- local->proc_iface = proc_mkdir("iface", local->proc);
- create_proc_read_entry("counters", 0, local->proc,
- ieee80211_proc_counters_read, local);
- create_proc_read_entry("config", 0, local->proc,
- ieee80211_proc_config_read, local);
- create_proc_read_entry("channels", 0, local->proc,
- ieee80211_proc_channels_read, local);
- create_proc_read_entry("rates", 0, local->proc,
- ieee80211_proc_rates_read, local);
- create_proc_read_entry("multicast", 0, local->proc,
- ieee80211_proc_multicast_read, local);
- create_proc_read_entry("debug", 0, local->proc,
- ieee80211_proc_debug_read, local);
- create_proc_read_entry("info", 0, local->proc,
- ieee80211_proc_info_read, local);
- ieee80211_proc_init_virtual(local->mdev);
-}
-
-
-void ieee80211_proc_deinit_interface(struct ieee80211_local *local)
-{
- if (!local->proc)
- return;
-
- ieee80211_proc_deinit_virtual(local->mdev);
- remove_proc_entry("iface", local->proc);
- remove_proc_entry("sta", local->proc);
- remove_proc_entry("counters", local->proc);
- remove_proc_entry("debug", local->proc);
- remove_proc_entry("config", local->proc);
- remove_proc_entry("channels", local->proc);
- remove_proc_entry("rates", local->proc);
- remove_proc_entry("multicast", local->proc);
- remove_proc_entry("info", local->proc);
- local->proc = NULL;
- remove_proc_entry(local->mdev->name, ieee80211_proc);
-}
-
-
-void ieee80211_proc_init(void)
-{
- if (proc_net == NULL) {
- ieee80211_proc = NULL;
- return;
- }
-
- ieee80211_proc = proc_mkdir("ieee80211", proc_net);
- if (!ieee80211_proc)
- printk(KERN_WARNING "Failed to mkdir /proc/net/ieee80211\n");
-}
-
-
-void ieee80211_proc_deinit(void)
-{
- if (!ieee80211_proc)
- return;
-
- ieee80211_proc = NULL;
- remove_proc_entry("ieee80211", proc_net);
-}
-
-#endif /* CONFIG_PROC_FS */
diff --git a/net/d80211/ieee80211_proc.h b/net/d80211/ieee80211_proc.h
deleted file mode 100644
index 4519d26..0000000
--- a/net/d80211/ieee80211_proc.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2003-2004, Instant802 Networks, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef IEEE80211_PROC_H
-#define IEEE80211_PROC_H
-
-#include <linux/netdevice.h>
-#include "ieee80211_i.h"
-#include "sta_info.h"
-
-#ifdef CONFIG_PROC_FS
-
-void ieee80211_proc_init_sta(struct ieee80211_local *local,
- struct sta_info *sta);
-void ieee80211_proc_deinit_sta(struct ieee80211_local *local,
- struct sta_info *sta);
-void ieee80211_proc_init_virtual(struct net_device *dev);
-void ieee80211_proc_deinit_virtual(struct net_device *dev);
-void ieee80211_proc_init_interface(struct ieee80211_local *local);
-void ieee80211_proc_deinit_interface(struct ieee80211_local *local);
-void ieee80211_proc_init(void);
-void ieee80211_proc_deinit(void);
-
-#else /* CONFIG_PROC_FS */
-
-static inline void ieee80211_proc_init_sta(struct ieee80211_local *local,
- struct sta_info *sta) {}
-static inline void ieee80211_proc_deinit_sta(struct ieee80211_local *local,
- struct sta_info *sta) {}
-static inline void ieee80211_proc_init_virtual(struct net_device *dev) {}
-static inline void ieee80211_proc_deinit_virtual(struct net_device *dev) {}
-static inline void
-ieee80211_proc_init_interface(struct ieee80211_local *local) {}
-static inline void
-ieee80211_proc_deinit_interface(struct ieee80211_local *local) {}
-static inline void ieee80211_proc_init(void) {}
-static inline void ieee80211_proc_deinit(void) {}
-#endif /* CONFIG_PROC_FS */
-
-const char *ieee80211_mode_str(int mode);
-const char *ieee80211_mode_str_short(int mode);
-
-#endif /* IEEE80211_PROC_H */
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 10bf45c..fb1c6b5 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -14,7 +14,6 @@ #include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "ieee80211_proc.h"
#include "rate_control.h"
#define to_ieee80211_local(class) container_of(class, struct ieee80211_local, class_dev)
@@ -30,6 +29,38 @@ static inline int rtnl_lock_local(struct
return 0;
}
+static const char *ieee80211_mode_str_short(int mode)
+{
+ switch (mode) {
+ case MODE_IEEE80211A:
+ return "802.11a";
+ case MODE_IEEE80211B:
+ return "802.11b";
+ case MODE_IEEE80211G:
+ return "802.11g";
+ case MODE_ATHEROS_TURBO:
+ return "AtherosTurbo";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char *ieee80211_mode_str(int mode)
+{
+ switch (mode) {
+ case MODE_IEEE80211A:
+ return "IEEE 802.11a";
+ case MODE_IEEE80211B:
+ return "IEEE 802.11b";
+ case MODE_IEEE80211G:
+ return "IEEE 802.11g";
+ case MODE_ATHEROS_TURBO:
+ return "Atheros Turbo (5 GHz)";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/* attributes in /sys/class/ieee80211/phyX/ */
static ssize_t store_add_iface(struct class_device *dev,
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
index 33ba8e2..bf797ec 100644
--- a/net/d80211/rate_control.c
+++ b/net/d80211/rate_control.c
@@ -327,29 +327,6 @@ static void rate_control_simple_free_sta
kfree(rctrl);
}
-
-static int rate_control_simple_status_sta(struct ieee80211_local *local,
- struct sta_info *sta, char *buf)
-{
- char *p = buf;
- struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
-
- p += sprintf(p, "tx_avg_rate_sum=%d\n", srctrl->tx_avg_rate_sum);
- p += sprintf(p, "tx_avg_rate_num=%d\n", srctrl->tx_avg_rate_num);
- if (srctrl->tx_avg_rate_num)
- p += sprintf(p, "tx_avg_rate_avg=%d\n",
- srctrl->tx_avg_rate_sum /
- srctrl->tx_avg_rate_num);
- return p - buf;
-}
-
-
-static int rate_control_simple_status_global(struct ieee80211_local *local,
- char *buf)
-{
- return 0;
-}
-
static ssize_t show_sta_tx_avg_rate_sum(const struct sta_info *sta, char *buf)
{
struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
@@ -397,8 +374,6 @@ static struct rate_control_ops rate_cont
.get_rate = rate_control_simple_get_rate,
.rate_init = rate_control_simple_rate_init,
.clear = rate_control_simple_clear,
- .status_sta = rate_control_simple_status_sta,
- .status_global = rate_control_simple_status_global,
.alloc = rate_control_simple_alloc,
.free = rate_control_simple_free,
.alloc_sta = rate_control_simple_alloc_sta,
diff --git a/net/d80211/rate_control.h b/net/d80211/rate_control.h
index 7705fb2..d8bdfed 100644
--- a/net/d80211/rate_control.h
+++ b/net/d80211/rate_control.h
@@ -45,9 +45,6 @@ struct rate_control_ops {
struct rate_control_extra *extra);
void (*rate_init)(struct ieee80211_local *local, struct sta_info *sta);
void (*clear)(void *priv);
- int (*status_sta)(struct ieee80211_local *local,
- struct sta_info *sta, char *buf);
- int (*status_global)(struct ieee80211_local *local, char *buf);
void * (*alloc)(struct ieee80211_local *local);
void (*free)(void *priv);
@@ -96,20 +93,6 @@ static inline void rate_control_clear(st
}
-static inline int rate_control_status_sta(struct ieee80211_local *local,
- struct sta_info *sta, char *buf)
-{
- return local->rate_ctrl->status_sta(local, sta, buf);
-}
-
-
-static inline int rate_control_status_global(struct ieee80211_local *local,
- char *buf)
-{
- return local->rate_ctrl->status_global(local, buf);
-}
-
-
static inline void * rate_control_alloc(struct ieee80211_local *local)
{
return local->rate_ctrl->alloc(local);
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index 96e8dc4..d3b4b42 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -19,7 +19,6 @@ #include <linux/if_arp.h>
#include <net/d80211.h>
#include "ieee80211_i.h"
-#include "ieee80211_proc.h"
#include "rate_control.h"
@@ -180,7 +179,6 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
ieee80211_sta_sysfs_add(sta);
rate_control_add_sta_attrs(local, sta->rate_ctrl_priv,
&sta->kobj);
- ieee80211_proc_init_sta(local, sta);
} else {
/* procfs entry adding might sleep, so schedule process context
* task for adding proc entry for STAs that do not yet have
@@ -200,7 +198,6 @@ #ifdef CONFIG_D80211_VERBOSE_DEBUG
#endif /* CONFIG_D80211_VERBOSE_DEBUG */
rate_control_remove_sta_attrs(local, sta->rate_ctrl_priv, &sta->kobj);
- ieee80211_proc_deinit_sta(local, sta);
ieee80211_sta_sysfs_remove(sta);
sta_info_put(sta);
@@ -371,7 +368,6 @@ static void sta_info_proc_add_task(void
sta->sysfs_registered = 1;
ieee80211_sta_sysfs_add(sta);
rate_control_add_sta_attrs(local, sta->rate_ctrl_priv, &sta->kobj);
- ieee80211_proc_init_sta(local, sta);
sta_info_put(sta);
}
}
--
1.3.0
^ permalink raw reply related
* [PATCH 11/12] d80211: encryption keys sysfs attributes
From: Jiri Benc @ 2006-06-08 7:49 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>
Add /sys/class/ieee80211/phyX/sta/*/key/* and /sys/class/net/X/keys/[0-3]/*
attributes.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 33 ++++++
net/d80211/ieee80211_i.h | 11 ++
net/d80211/ieee80211_ioctl.c | 101 ++++++++++++-------
net/d80211/ieee80211_key.h | 2
net/d80211/ieee80211_sysfs.c | 12 ++
net/d80211/ieee80211_sysfs_sta.c | 206 ++++++++++++++++++++++++++++++++++++++
6 files changed, 326 insertions(+), 39 deletions(-)
9b2e2e2cc66e7fb3f1ae07d7e083ffa63dffbde7
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index e4ac701..1a03f07 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -84,15 +84,44 @@ ieee80211_key_data2conf(struct ieee80211
return conf;
}
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+ int idx, size_t key_len, gfp_t flags)
+{
+ struct ieee80211_key *key;
+ int res;
+
+ key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
+ if (!key)
+ return NULL;
+ if (sdata)
+ res = kobject_set_name(&key->kobj, "%d", idx);
+ else
+ res = kobject_set_name(&key->kobj, "key");
+ if (res) {
+ kfree(key);
+ return NULL;
+ }
+ ieee80211_key_sysfs_set_kset(key, sdata ? &sdata->key_kset : NULL);
+ kobject_init(&key->kobj);
+ return key;
+}
void ieee80211_key_free(struct ieee80211_key *key)
{
- if (key && key->alg == ALG_CCMP)
+ if (key)
+ kobject_put(&key->kobj);
+}
+
+void ieee80211_key_release(struct kobject *kobj)
+{
+ struct ieee80211_key *key;
+
+ key = container_of(kobj, struct ieee80211_key, kobj);
+ if (key->alg == ALG_CCMP)
ieee80211_aes_key_free(key->u.ccmp.tfm);
kfree(key);
}
-
static int rate_list_match(int *rate_list, int rate)
{
int i;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 212d12f..c1d7422 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -294,6 +294,7 @@ struct ieee80211_sub_if_data {
#define NUM_DEFAULT_KEYS 4
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
struct ieee80211_key *default_key;
+ struct kset key_kset;
struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
@@ -527,7 +528,10 @@ int ieee80211_if_config(struct net_devic
struct ieee80211_key_conf *
ieee80211_key_data2conf(struct ieee80211_local *local,
struct ieee80211_key *data);
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+ int idx, size_t key_len, gfp_t flags);
void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_key_release(struct kobject *kobj);
void ieee80211_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *status, u32 msg_type);
void ieee80211_prepare_rates(struct net_device *dev);
@@ -633,5 +637,12 @@ int ieee80211_sta_kset_sysfs_register(st
void ieee80211_sta_kset_sysfs_unregister(struct ieee80211_local *local);
int ieee80211_sta_sysfs_add(struct sta_info *sta);
void ieee80211_sta_sysfs_remove(struct sta_info *sta);
+int ieee80211_key_kset_sysfs_register(struct ieee80211_sub_if_data *sdata);
+void ieee80211_key_kset_sysfs_unregister(struct ieee80211_sub_if_data *sdata);
+void ieee80211_key_sysfs_set_kset(struct ieee80211_key *key, struct kset *kset);
+int ieee80211_key_sysfs_add(struct ieee80211_key *key);
+void ieee80211_key_sysfs_remove(struct ieee80211_key *key);
+int ieee80211_key_sysfs_add_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_key_sysfs_remove_default(struct ieee80211_sub_if_data *sdata);
#endif /* IEEE80211_I_H */
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 562b9f3..7c2a847 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -470,7 +470,7 @@ static int ieee80211_set_encryption(stru
struct ieee80211_local *local = dev->ieee80211_ptr;
int ret = 0;
struct sta_info *sta;
- struct ieee80211_key **key;
+ struct ieee80211_key *key, *old_key;
int try_hwaccel = 1;
struct ieee80211_key_conf *keyconf;
struct ieee80211_sub_if_data *sdata;
@@ -486,7 +486,7 @@ static int ieee80211_set_encryption(stru
dev->name, idx);
return -EINVAL;
}
- key = &sdata->keys[idx];
+ key = sdata->keys[idx];
/* Disable hwaccel for default keys when the interface is not
* the default one.
@@ -525,7 +525,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
return -ENOENT;
}
- key = &sta->key;
+ key = sta->key;
}
/* FIX:
@@ -571,8 +571,8 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
if (alg == ALG_NONE) {
keyconf = NULL;
- if (try_hwaccel && *key && local->hw->set_key &&
- (keyconf = ieee80211_key_data2conf(local, *key)) != NULL &&
+ if (try_hwaccel && key && local->hw->set_key &&
+ (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
local->hw->set_key(dev, DISABLE_KEY, sta_addr,
keyconf, sta ? sta->aid : 0)) {
if (err)
@@ -583,68 +583,101 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
}
kfree(keyconf);
- if (sdata->default_key == *key)
+ if (key && sdata->default_key == key) {
+ ieee80211_key_sysfs_remove_default(sdata);
sdata->default_key = NULL;
- ieee80211_key_free(*key);
- *key = NULL;
+ }
+ ieee80211_key_sysfs_remove(key);
+ if (sta)
+ sta->key = NULL;
+ else
+ sdata->keys[idx] = NULL;
+ ieee80211_key_free(key);
+ key = NULL;
} else {
- if (*key == NULL || (*key)->keylen < key_len) {
- ieee80211_key_free(*key);
- *key = kmalloc(sizeof(struct ieee80211_key) +
- key_len, GFP_ATOMIC);
- if (*key == NULL) {
- ret = -ENOMEM;
- goto done;
- }
+ old_key = key;
+ key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
+ GFP_KERNEL);
+ if (!key) {
+ ret = -ENOMEM;
+ goto err_out;
}
- memset(*key, 0, sizeof(struct ieee80211_key) + key_len);
+
/* default to sw encryption; low-level driver sets these if the
* requested encryption is supported */
- (*key)->hw_key_idx = HW_KEY_IDX_INVALID;
- (*key)->force_sw_encrypt = 1;
+ key->hw_key_idx = HW_KEY_IDX_INVALID;
+ key->force_sw_encrypt = 1;
- (*key)->alg = alg;
- (*key)->keyidx = idx;
- (*key)->keylen = key_len;
- memcpy((*key)->key, _key, key_len);
+ key->alg = alg;
+ key->keyidx = idx;
+ key->keylen = key_len;
+ memcpy(key->key, _key, key_len);
if (set_tx_key)
- (*key)->default_tx_key = 1;
+ key->default_tx_key = 1;
if (alg == ALG_CCMP) {
/* Initialize AES key state here as an optimization
* so that it does not need to be initialized for every
* packet. */
- (*key)->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
- (*key)->key);
- if ((*key)->u.ccmp.tfm == NULL) {
- kfree(*key);
- *key = NULL;
+ key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
+ key->key);
+ if (key->u.ccmp.tfm == NULL) {
ret = -ENOMEM;
- goto done;
+ goto err_free;
}
}
+ if (old_key && sdata->default_key == old_key) {
+ ieee80211_key_sysfs_remove_default(sdata);
+ sdata->default_key = NULL;
+ }
+ ieee80211_key_sysfs_remove(old_key);
+ if (sta)
+ sta->key = key;
+ else
+ sdata->keys[idx] = key;
+ ieee80211_key_free(old_key);
+ if (sta)
+ key->kobj.parent = &sta->kobj;
+ ret = ieee80211_key_sysfs_add(key);
+ if (ret)
+ goto err_null;
+
if (try_hwaccel &&
(alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) {
int e = ieee80211_set_hw_encryption(dev, sta, sta_addr,
- *key);
+ key);
if (err)
*err = e;
}
}
- if (set_tx_key || (sta == NULL && sdata->default_key == NULL)) {
- sdata->default_key = *key;
+ if (set_tx_key || (sta == NULL && sdata->default_key == NULL && key)) {
+ sdata->default_key = key;
+ if (ieee80211_key_sysfs_add_default(sdata))
+ printk(KERN_WARNING "%s: cannot create symlink to "
+ "default key\n", dev->name);
if (local->hw->set_key_idx &&
local->hw->set_key_idx(dev, idx))
printk(KERN_DEBUG "%s: failed to set TX key idx for "
"low-level driver\n", dev->name);
}
- done:
if (sta)
sta_info_put(sta);
+ return 0;
+
+err_null:
+ if (sta)
+ sta->key = NULL;
+ else
+ sdata->keys[idx] = NULL;
+err_free:
+ ieee80211_key_free(key);
+err_out:
+ if (sta)
+ sta_info_put(sta);
return ret;
}
diff --git a/net/d80211/ieee80211_key.h b/net/d80211/ieee80211_key.h
index 4c688cd..64f2363 100644
--- a/net/d80211/ieee80211_key.h
+++ b/net/d80211/ieee80211_key.h
@@ -40,6 +40,8 @@ #define CCMP_PN_LEN 6
#define NUM_RX_DATA_QUEUES 17
struct ieee80211_key {
+ struct kobject kobj;
+
int hw_key_idx; /* filled and used by low-level driver */
ieee80211_key_alg alg;
union {
diff --git a/net/d80211/ieee80211_sysfs.c b/net/d80211/ieee80211_sysfs.c
index 12d16fd..10bf45c 100644
--- a/net/d80211/ieee80211_sysfs.c
+++ b/net/d80211/ieee80211_sysfs.c
@@ -709,16 +709,22 @@ int ieee80211_sysfs_add_netdevice(struct
res = sysfs_create_link(&dev->class_dev.kobj, &local->class_dev.kobj,
"wiphy");
if (res)
- goto out;
+ goto err_out;
res = ieee80211_add_if_group(&dev->class_dev.kobj, dev);
if (res)
- sysfs_remove_link(&dev->class_dev.kobj, "wiphy");
-out:
+ goto err_link;
+ res = ieee80211_key_kset_sysfs_register(IEEE80211_DEV_TO_SUB_IF(dev));
+ return res;
+
+err_link:
+ sysfs_remove_link(&dev->class_dev.kobj, "wiphy");
+err_out:
return res;
}
void ieee80211_sysfs_remove_netdevice(struct net_device *dev)
{
+ ieee80211_key_kset_sysfs_unregister(IEEE80211_DEV_TO_SUB_IF(dev));
ieee80211_remove_if_group(&dev->class_dev.kobj, dev);
sysfs_remove_link(&dev->class_dev.kobj, "wiphy");
}
diff --git a/net/d80211/ieee80211_sysfs_sta.c b/net/d80211/ieee80211_sysfs_sta.c
index 07de564..94c6dd8 100644
--- a/net/d80211/ieee80211_sysfs_sta.c
+++ b/net/d80211/ieee80211_sysfs_sta.c
@@ -10,14 +10,22 @@
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include "ieee80211_i.h"
+#include "ieee80211_key.h"
#include "sta_info.h"
static ssize_t sta_sysfs_show(struct kobject *, struct attribute *, char *);
+static ssize_t key_sysfs_show(struct kobject *, struct attribute *, char *);
static struct sysfs_ops sta_ktype_ops = {
.show = sta_sysfs_show,
};
+static struct sysfs_ops key_ktype_ops = {
+ .show = key_sysfs_show,
+};
+
+/* sta attributtes */
+
#define STA_SHOW(name, field, format_string) \
static ssize_t show_sta_##name(const struct sta_info *sta, char *buf) \
{ \
@@ -183,12 +191,153 @@ #endif
NULL
};
+/* keys attributtes */
+
+struct key_attribute {
+ struct attribute attr;
+ ssize_t (*show)(const struct ieee80211_key *, char *buf);
+ ssize_t (*store)(struct ieee80211_key *, const char *buf,
+ size_t count);
+};
+
+#define KEY_SHOW(name, field, format_string) \
+static ssize_t show_key_##name(const struct ieee80211_key *key, char *buf)\
+{ \
+ return sprintf(buf, format_string, key->field); \
+}
+#define KEY_SHOW_D(name, field) KEY_SHOW(name, field, "%d\n")
+
+#define __KEY_ATTR(name) \
+static struct key_attribute key_attr_##name = \
+ __ATTR(name, S_IRUSR, show_key_##name, NULL)
+
+#define KEY_ATTR(name, field, format) \
+ KEY_SHOW_##format(name, field) \
+ __KEY_ATTR(name)
+
+KEY_ATTR(length, keylen, D);
+KEY_ATTR(sw_encrypt, force_sw_encrypt, D);
+KEY_ATTR(index, keyidx, D);
+KEY_ATTR(hw_index, hw_key_idx, D);
+KEY_ATTR(tx_rx_count, tx_rx_count, D);
+
+static ssize_t show_key_algorithm(const struct ieee80211_key *key, char *buf)
+{
+ char *alg;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ alg = "WEP";
+ break;
+ case ALG_TKIP:
+ alg = "TKIP";
+ break;
+ case ALG_CCMP:
+ alg = "CCMP";
+ break;
+ default:
+ return 0;
+ }
+ return sprintf(buf, "%s\n", alg);
+}
+__KEY_ATTR(algorithm);
+
+static ssize_t show_key_tx_spec(const struct ieee80211_key *key, char *buf)
+{
+ const u8 *tpn;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ return sprintf(buf, "\n");
+ case ALG_TKIP:
+ return sprintf(buf, "%08x %04x\n", key->u.tkip.iv32,
+ key->u.tkip.iv16);
+ case ALG_CCMP:
+ tpn = key->u.ccmp.tx_pn;
+ return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n", tpn[0],
+ tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
+ default:
+ return 0;
+ }
+}
+__KEY_ATTR(tx_spec);
+
+static ssize_t show_key_rx_spec(const struct ieee80211_key *key, char *buf)
+{
+ int i;
+ const u8 *rpn;
+ char *p = buf;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ return sprintf(buf, "\n");
+ case ALG_TKIP:
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ p += sprintf(p, "%08x %04x\n",
+ key->u.tkip.iv32_rx[i],
+ key->u.tkip.iv16_rx[i]);
+ return (p - buf);
+ case ALG_CCMP:
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+ rpn = key->u.ccmp.rx_pn[i];
+ p += sprintf(p, "%02x%02x%02x%02x%02x%02x\n", rpn[0],
+ rpn[1], rpn[2], rpn[3], rpn[4], rpn[5]);
+ }
+ return (p - buf);
+ default:
+ return 0;
+ }
+}
+__KEY_ATTR(rx_spec);
+
+static ssize_t show_key_replays(const struct ieee80211_key *key, char *buf)
+{
+ if (key->alg != ALG_CCMP)
+ return 0;
+ return sprintf(buf, "%u\n", key->u.ccmp.replays);
+}
+__KEY_ATTR(replays);
+
+static ssize_t show_key_key(const struct ieee80211_key *key, char *buf)
+{
+ int i;
+ char *p = buf;
+
+ for (i = 0; i < key->keylen; i++)
+ p += sprintf(p, "%02x", key->key[i]);
+ p += sprintf(p, "\n");
+ return (p - buf);
+}
+__KEY_ATTR(key);
+
+static struct attribute *key_ktype_attrs[] = {
+ &key_attr_length.attr,
+ &key_attr_sw_encrypt.attr,
+ &key_attr_index.attr,
+ &key_attr_hw_index.attr,
+ &key_attr_tx_rx_count.attr,
+ &key_attr_algorithm.attr,
+ &key_attr_tx_spec.attr,
+ &key_attr_rx_spec.attr,
+ &key_attr_replays.attr,
+ &key_attr_key.attr,
+ NULL
+};
+
+/* structures and functions */
+
static struct kobj_type sta_ktype = {
.release = sta_info_release,
.sysfs_ops = &sta_ktype_ops,
.default_attrs = sta_ktype_attrs,
};
+static struct kobj_type key_ktype = {
+ .release = ieee80211_key_release,
+ .sysfs_ops = &key_ktype_ops,
+ .default_attrs = key_ktype_attrs,
+};
+
static ssize_t sta_sysfs_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
@@ -200,6 +349,17 @@ static ssize_t sta_sysfs_show(struct kob
return sta_attr->show(sta, buf);
}
+static ssize_t key_sysfs_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct key_attribute *key_attr;
+ struct ieee80211_key *key;
+
+ key_attr = container_of(attr, struct key_attribute, attr);
+ key = container_of(kobj, struct ieee80211_key, kobj);
+ return key_attr->show(key, buf);
+}
+
int ieee80211_sta_kset_sysfs_register(struct ieee80211_local *local)
{
int res;
@@ -217,6 +377,23 @@ void ieee80211_sta_kset_sysfs_unregister
kset_unregister(&local->sta_kset);
}
+int ieee80211_key_kset_sysfs_register(struct ieee80211_sub_if_data *sdata)
+{
+ int res;
+
+ res = kobject_set_name(&sdata->key_kset.kobj, "keys");
+ if (res)
+ return res;
+ sdata->key_kset.kobj.parent = &sdata->dev->class_dev.kobj;
+ sdata->key_kset.ktype = &key_ktype;
+ return kset_register(&sdata->key_kset);
+}
+
+void ieee80211_key_kset_sysfs_unregister(struct ieee80211_sub_if_data *sdata)
+{
+ kset_unregister(&sdata->key_kset);
+}
+
int ieee80211_sta_sysfs_add(struct sta_info *sta)
{
return kobject_add(&sta->kobj);
@@ -226,3 +403,32 @@ void ieee80211_sta_sysfs_remove(struct s
{
kobject_del(&sta->kobj);
}
+
+void ieee80211_key_sysfs_set_kset(struct ieee80211_key *key, struct kset *kset)
+{
+ key->kobj.kset = kset;
+ if (!kset)
+ key->kobj.ktype = &key_ktype;
+}
+
+int ieee80211_key_sysfs_add(struct ieee80211_key *key)
+{
+ return kobject_add(&key->kobj);
+}
+
+void ieee80211_key_sysfs_remove(struct ieee80211_key *key)
+{
+ if (key)
+ kobject_del(&key->kobj);
+}
+
+int ieee80211_key_sysfs_add_default(struct ieee80211_sub_if_data *sdata)
+{
+ return sysfs_create_link(&sdata->key_kset.kobj,
+ &sdata->default_key->kobj, "default");
+}
+
+void ieee80211_key_sysfs_remove_default(struct ieee80211_sub_if_data *sdata)
+{
+ sysfs_remove_link(&sdata->key_kset.kobj, "default");
+}
--
1.3.0
^ permalink raw reply related
* [PATCH 10/12] d80211: rate_control sysfs attributes
From: Jiri Benc @ 2006-06-08 7:49 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>
Add support for sysfs attributes for rate_control modules.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 13 ++++++++++++-
net/d80211/rate_control.c | 42 ++++++++++++++++++++++++++++++++++++++++++
net/d80211/rate_control.h | 36 ++++++++++++++++++++++++++++++++++++
net/d80211/sta_info.c | 4 ++++
4 files changed, 94 insertions(+), 1 deletions(-)
9acfab1d1a4e4a82dace4055a089d605d5efa97f
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 75aaa99..e4ac701 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4215,6 +4215,13 @@ int ieee80211_register_hw(struct net_dev
"algorithm\n", dev->name);
goto fail_rate;
}
+ result = rate_control_add_attrs(local, local->rate_ctrl_priv,
+ &local->class_dev.kobj);
+ if (result < 0) {
+ printk(KERN_DEBUG "%s: Failed to register sysfs attributes "
+ "for rate control\n", dev->name);
+ goto fail_rate_attrs;
+ }
/* TODO: add rtnl locking around device creation and qdisc install */
ieee80211_install_qdisc(dev);
@@ -4233,6 +4240,8 @@ int ieee80211_register_hw(struct net_dev
return 0;
+fail_rate_attrs:
+ rate_control_free(local);
fail_rate:
ieee80211_sysfs_remove_netdevice(dev);
fail_if_sysfs:
@@ -4308,6 +4317,8 @@ void ieee80211_unregister_hw(struct net_
rtnl_unlock();
sta_info_stop(local);
+ rate_control_remove_attrs(local, local->rate_ctrl_priv,
+ &local->class_dev.kobj);
ieee80211_dev_sysfs_del(local);
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
@@ -4327,7 +4338,6 @@ void ieee80211_unregister_hw(struct net_
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
- rate_control_free(local);
ieee80211_dev_free_index(local);
}
@@ -4341,6 +4351,7 @@ void ieee80211_free_hw(struct net_device
void ieee80211_release_hw(struct ieee80211_local *local)
{
+ rate_control_free(local);
kfree(local);
}
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
index e7e6791..33ba8e2 100644
--- a/net/d80211/rate_control.c
+++ b/net/d80211/rate_control.c
@@ -350,6 +350,46 @@ static int rate_control_simple_status_gl
return 0;
}
+static ssize_t show_sta_tx_avg_rate_sum(const struct sta_info *sta, char *buf)
+{
+ struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
+
+ return sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
+}
+
+static ssize_t show_sta_tx_avg_rate_num(const struct sta_info *sta, char *buf)
+{
+ struct sta_rate_control *srctrl = sta->rate_ctrl_priv;
+
+ return sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
+}
+
+static struct sta_attribute sta_attr_tx_avg_rate_sum =
+ __ATTR(tx_avg_rate_sum, S_IRUSR, show_sta_tx_avg_rate_sum, NULL);
+static struct sta_attribute sta_attr_tx_avg_rate_num =
+ __ATTR(tx_avg_rate_num, S_IRUSR, show_sta_tx_avg_rate_num, NULL);
+
+static struct attribute *rate_control_simple_sta_attrs[] = {
+ &sta_attr_tx_avg_rate_sum.attr,
+ &sta_attr_tx_avg_rate_num.attr,
+ NULL,
+};
+
+static struct attribute_group rate_control_simple_sta_group = {
+ .name = "rate_control_simple",
+ .attrs = rate_control_simple_sta_attrs,
+};
+
+static int rate_control_simple_add_sta_attrs(void *priv, struct kobject *kobj)
+{
+ return sysfs_create_group(kobj, &rate_control_simple_sta_group);
+}
+
+static void rate_control_simple_remove_sta_attrs(void *priv,
+ struct kobject *kobj)
+{
+ sysfs_remove_group(kobj, &rate_control_simple_sta_group);
+}
static struct rate_control_ops rate_control_simple = {
.name = "simple",
@@ -363,6 +403,8 @@ static struct rate_control_ops rate_cont
.free = rate_control_simple_free,
.alloc_sta = rate_control_simple_alloc_sta,
.free_sta = rate_control_simple_free_sta,
+ .add_sta_attrs = rate_control_simple_add_sta_attrs,
+ .remove_sta_attrs = rate_control_simple_remove_sta_attrs,
};
diff --git a/net/d80211/rate_control.h b/net/d80211/rate_control.h
index b509539..7705fb2 100644
--- a/net/d80211/rate_control.h
+++ b/net/d80211/rate_control.h
@@ -53,6 +53,11 @@ struct rate_control_ops {
void (*free)(void *priv);
void * (*alloc_sta)(void);
void (*free_sta)(void *priv);
+
+ int (*add_attrs)(void *priv, struct kobject *kobj);
+ void (*remove_attrs)(void *priv, struct kobject *kobj);
+ int (*add_sta_attrs)(void *priv, struct kobject *kobj);
+ void (*remove_sta_attrs)(void *priv, struct kobject *kobj);
};
@@ -132,4 +137,35 @@ static inline void rate_control_free_sta
local->rate_ctrl->free_sta(priv);
}
+static inline int rate_control_add_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->add_attrs)
+ return local->rate_ctrl->add_attrs(priv, kobj);
+ return 0;
+}
+
+static inline void rate_control_remove_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->remove_attrs)
+ local->rate_ctrl->remove_attrs(priv, kobj);
+}
+
+static inline int rate_control_add_sta_attrs(struct ieee80211_local *local,
+ void *priv, struct kobject *kobj)
+{
+ if (local->rate_ctrl->add_sta_attrs)
+ return local->rate_ctrl->add_sta_attrs(priv, kobj);
+ return 0;
+}
+
+static inline void rate_control_remove_sta_attrs(struct ieee80211_local *local,
+ void *priv,
+ struct kobject *kobj)
+{
+ if (local->rate_ctrl->remove_sta_attrs)
+ local->rate_ctrl->remove_sta_attrs(priv, kobj);
+}
+
#endif /* RATE_CONTROL */
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index 9c6adaa..96e8dc4 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -178,6 +178,8 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
if (!in_interrupt()) {
sta->sysfs_registered = 1;
ieee80211_sta_sysfs_add(sta);
+ rate_control_add_sta_attrs(local, sta->rate_ctrl_priv,
+ &sta->kobj);
ieee80211_proc_init_sta(local, sta);
} else {
/* procfs entry adding might sleep, so schedule process context
@@ -197,6 +199,7 @@ #ifdef CONFIG_D80211_VERBOSE_DEBUG
local->mdev->name, MAC2STR(sta->addr));
#endif /* CONFIG_D80211_VERBOSE_DEBUG */
+ rate_control_remove_sta_attrs(local, sta->rate_ctrl_priv, &sta->kobj);
ieee80211_proc_deinit_sta(local, sta);
ieee80211_sta_sysfs_remove(sta);
@@ -367,6 +370,7 @@ static void sta_info_proc_add_task(void
sta->sysfs_registered = 1;
ieee80211_sta_sysfs_add(sta);
+ rate_control_add_sta_attrs(local, sta->rate_ctrl_priv, &sta->kobj);
ieee80211_proc_init_sta(local, sta);
sta_info_put(sta);
}
--
1.3.0
^ permalink raw reply related
* [PATCH 9/12] d80211: remove useless parameters
From: Jiri Benc @ 2006-06-08 7:49 UTC (permalink / raw)
To: netdev; +Cc: John W. Linville
In-Reply-To: <20060608094822.014829000.midnight@suse.cz>
There is no necessity for passing ieee80211_local parameter to sta_info_put
and sta_info_free now.
Signed-off-by: Jiri Benc <jbenc@suse.cz>
---
net/d80211/ieee80211.c | 18 +++++++++---------
net/d80211/ieee80211_iface.c | 4 ++--
net/d80211/ieee80211_ioctl.c | 20 ++++++++++----------
net/d80211/ieee80211_sta.c | 8 ++++----
net/d80211/rate_control.c | 4 ++--
net/d80211/sta_info.c | 16 ++++++++--------
net/d80211/sta_info.h | 5 ++---
7 files changed, 37 insertions(+), 38 deletions(-)
bc9e55deef4924f5a4ba82487747726413636df6
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 15d43f8..75aaa99 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -1153,7 +1153,7 @@ static int ieee80211_tx(struct net_devic
skb = tx.skb; /* handlers are allowed to change skb */
if (sta)
- sta_info_put(local, sta);
+ sta_info_put(sta);
if (unlikely(res == TXRX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -1373,7 +1373,7 @@ static int ieee80211_subif_start_xmit(st
fc |= WLAN_FC_STYPE_QOS_DATA << 4;
hdrlen += 2;
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
hdr.frame_control = cpu_to_le16(fc);
@@ -1743,7 +1743,7 @@ ieee80211_get_buffered_bc(struct net_dev
}
if (sta)
- sta_info_put(local, sta);
+ sta_info_put(sta);
return skb;
}
@@ -2330,7 +2330,7 @@ ieee80211_rx_h_data(struct ieee80211_txr
skb = NULL;
}
if (dsta)
- sta_info_put(local, dsta);
+ sta_info_put(dsta);
}
}
@@ -3469,7 +3469,7 @@ void __ieee80211_rx(struct net_device *d
end:
if (sta)
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
@@ -3806,7 +3806,7 @@ void ieee80211_tx_status(struct net_devi
status->excessive_retries = 0;
status->tx_filtered = 1;
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
}
@@ -3855,7 +3855,7 @@ void ieee80211_tx_status(struct net_devi
}
dev_kfree_skb(skb);
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
return;
}
} else {
@@ -3978,8 +3978,8 @@ int ieee80211_if_update_wds(struct net_d
/* Remove STA entry for the old peer */
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
- sta_info_put(local, sta);
- sta_info_free(local, sta, 0);
+ sta_info_put(sta);
+ sta_info_free(sta, 0);
} else {
printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
"peer " MACSTR "\n",
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 467dcba..960a90e 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -261,8 +261,8 @@ #endif
case IEEE80211_IF_TYPE_WDS:
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
- sta_info_put(local, sta);
- sta_info_free(local, sta, 0);
+ sta_info_put(sta);
+ sta_info_free(sta, 0);
} else {
#ifdef CONFIG_D80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Someone had deleted my STA "
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index e1bdc03..562b9f3 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -294,7 +294,7 @@ static int ieee80211_ioctl_add_sta(struc
}
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
return 0;
}
@@ -308,8 +308,8 @@ static int ieee80211_ioctl_remove_sta(st
sta = sta_info_get(local, param->sta_addr);
if (sta) {
- sta_info_put(local, sta);
- sta_info_free(local, sta, 1);
+ sta_info_put(sta);
+ sta_info_free(sta, 1);
}
return sta ? 0 : -ENOENT;
@@ -393,7 +393,7 @@ static int ieee80211_ioctl_get_info_sta(
param->u.get_info_sta.last_rssi = sta->last_rssi;
param->u.get_info_sta.last_ack_rssi = sta->last_ack_rssi[2];
- sta_info_put(local, sta);
+ sta_info_put(sta);
return 0;
}
@@ -421,7 +421,7 @@ static int ieee80211_ioctl_set_flags_sta
printk(KERN_DEBUG "%s: failed to set low-level driver "
"PAE state (unauthorized) for " MACSTR "\n",
dev->name, MAC2STR(sta->addr));
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
return sta ? 0 : -ENOENT;
@@ -563,7 +563,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
if (sta->flags & WLAN_STA_WME) {
try_hwaccel = 0;
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
sta = NULL;
}
}
@@ -643,7 +643,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
done:
if (sta)
- sta_info_put(local, sta);
+ sta_info_put(sta);
return ret;
}
@@ -813,7 +813,7 @@ static int ieee80211_ioctl_get_encryptio
}
if (sta)
- sta_info_put(local, sta);
+ sta_info_put(sta);
return ret;
}
@@ -842,7 +842,7 @@ static int ieee80211_ioctl_wpa_trigger(s
sta->wpa_trigger = param->u.wpa_trigger.trigger;
- sta_info_put(local, sta);
+ sta_info_put(sta);
return 0;
}
#endif /* CONFIG_HOSTAPD_WPA_TESTING */
@@ -1136,7 +1136,7 @@ #endif
sta->vlan_id = param->u.set_sta_vlan.vlan_id;
dev_put(new_vlan_dev);
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
return sta ? 0 : -ENOENT;
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index a42c387..37d40aa 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -730,7 +730,7 @@ static void ieee80211_associated(struct
ifsta->ssid_len);
}
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
if (disassoc) {
union iwreq_data wrqu;
@@ -1200,7 +1200,7 @@ static void ieee80211_rx_mgmt_assoc_resp
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
ieee80211_associated(dev, ifsta);
}
@@ -1443,7 +1443,7 @@ #endif /* IEEE80211_IBSS_DEBUG */
dev->name, MAC2STR(sta->addr), prev_rates,
supp_rates, sta->supp_rates);
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
if (elems.ssid == NULL)
@@ -1836,7 +1836,7 @@ static void ieee80211_sta_expire(struct
IEEE80211_IBSS_INACTIVITY_LIMIT)) {
printk(KERN_DEBUG "%s: expiring inactive STA " MACSTR
"\n", dev->name, MAC2STR(sta->addr));
- sta_info_free(local, sta, 1);
+ sta_info_free(sta, 1);
}
}
spin_unlock_bh(&local->sta_lock);
diff --git a/net/d80211/rate_control.c b/net/d80211/rate_control.c
index 9bcb8fc..e7e6791 100644
--- a/net/d80211/rate_control.c
+++ b/net/d80211/rate_control.c
@@ -209,7 +209,7 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
}
}
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
@@ -260,7 +260,7 @@ rate_control_simple_get_rate(struct net_
extra->nonerp_idx = nonerp_idx;
extra->nonerp = &local->curr_rates[extra->nonerp_idx];
- sta_info_put(local, sta);
+ sta_info_put(sta);
return &local->curr_rates[rateidx];
}
diff --git a/net/d80211/sta_info.c b/net/d80211/sta_info.c
index bba4771..9c6adaa 100644
--- a/net/d80211/sta_info.c
+++ b/net/d80211/sta_info.c
@@ -102,7 +102,7 @@ int sta_info_min_txrate_get(struct ieee8
}
-void sta_info_put(struct ieee80211_local *local, struct sta_info *sta)
+void sta_info_put(struct sta_info *sta)
{
kobject_put(&sta->kobj);
}
@@ -200,13 +200,13 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
ieee80211_proc_deinit_sta(local, sta);
ieee80211_sta_sysfs_remove(sta);
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
-void sta_info_free(struct ieee80211_local *local, struct sta_info *sta,
- int locked)
+void sta_info_free(struct sta_info *sta, int locked)
{
struct sk_buff *skb;
+ struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata;
if (!locked)
@@ -320,7 +320,7 @@ static void sta_info_cleanup(unsigned lo
struct sta_info *sta = (struct sta_info *) ptr;
__sta_info_get(sta);
sta_info_cleanup_expire_buffered(local, sta);
- sta_info_put(local, sta);
+ sta_info_put(sta);
ptr = ptr->next;
}
spin_unlock_bh(&local->sta_lock);
@@ -368,7 +368,7 @@ static void sta_info_proc_add_task(void
sta->sysfs_registered = 1;
ieee80211_sta_sysfs_add(sta);
ieee80211_proc_init_sta(local, sta);
- sta_info_put(local, sta);
+ sta_info_put(sta);
}
}
@@ -412,7 +412,7 @@ void sta_info_stop(struct ieee80211_loca
* parameter to ensure all sysfs sta entries are
* unregistered. We don't need locking at this
* point. */
- sta_info_free(local, sta, 0);
+ sta_info_free(sta, 0);
}
ieee80211_sta_kset_sysfs_unregister(local);
}
@@ -449,7 +449,7 @@ void sta_info_flush(struct ieee80211_loc
list_for_each_safe(ptr, n, &local->sta_list) {
struct sta_info *sta = list_entry(ptr, struct sta_info, list);
if (dev == NULL || dev == sta->dev)
- sta_info_free(local, sta, 1);
+ sta_info_free(sta, 1);
}
spin_unlock_bh(&local->sta_lock);
}
diff --git a/net/d80211/sta_info.h b/net/d80211/sta_info.h
index ddfe50e..70334e5 100644
--- a/net/d80211/sta_info.h
+++ b/net/d80211/sta_info.h
@@ -134,11 +134,10 @@ #define STA_INFO_CLEANUP_INTERVAL (10 *
struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
int sta_info_min_txrate_get(struct ieee80211_local *local);
-void sta_info_put(struct ieee80211_local *local, struct sta_info *sta);
+void sta_info_put(struct sta_info *sta);
struct sta_info * sta_info_add(struct ieee80211_local *local,
struct net_device *dev, u8 *addr);
-void sta_info_free(struct ieee80211_local *local, struct sta_info *sta,
- int locked);
+void sta_info_free(struct sta_info *sta, int locked);
void sta_info_release(struct kobject *kobj);
void sta_info_init(struct ieee80211_local *local);
int sta_info_start(struct ieee80211_local *local);
--
1.3.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox