#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/string.h>
#include <linux/firmware.h>
+#include <linux/rtnetlink.h>
#include <asm/unaligned.h>
#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
-static struct pci_device_id e100_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(e100_id_table) = {
INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
struct mem *mem;
dma_addr_t dma_addr;
+ struct pci_pool *cbs_pool;
dma_addr_t cbs_dma_addr;
u8 adaptive_ifs;
u8 tx_threshold;
u16 eeprom_wc;
__le16 eeprom[256];
spinlock_t mdio_lock;
+ const struct firmware *fw;
};
static inline void e100_write_flush(struct nic *nic)
static const struct firmware *e100_request_firmware(struct nic *nic)
{
const char *fw_name;
- const struct firmware *fw;
+ const struct firmware *fw = nic->fw;
u8 timer, bundle, min_size;
- int err;
+ int err = 0;
/* do not load u-code for ICH devices */
if (nic->flags & ich)
else /* No ucode on other devices */
return NULL;
- err = request_firmware(&fw, fw_name, &nic->pdev->dev);
+ /* If the firmware has not previously been loaded, request a pointer
+ * to it. If it was previously loaded, we are reinitializing the
+ * adapter, possibly in a resume from hibernate, in which case
+ * request_firmware() cannot be used.
+ */
+ if (!fw)
+ err = request_firmware(&fw, fw_name, &nic->pdev->dev);
+
if (err) {
DPRINTK(PROBE, ERR, "Failed to load firmware \"%s\": %d\n",
fw_name, err);
return ERR_PTR(err);
}
+
/* Firmware should be precisely UCODE_SIZE (words) plus three bytes
indicating the offsets for BUNDLESMALL, BUNDLEMAX, INTDELAY */
if (fw->size != UCODE_SIZE * 4 + 3) {
release_firmware(fw);
return ERR_PTR(-EINVAL);
}
- /* OK, firmware is validated and ready to use... */
+
+ /* OK, firmware is validated and ready to use. Save a pointer
+ * to it in the nic */
+ nic->fw = fw;
return fw;
}
} else
DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
- /* Isolate all the PHY ids */
- for (addr = 0; addr < 32; addr++)
- mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
- /* Select the discovered PHY */
- bmcr &= ~BMCR_ISOLATE;
- mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
-
/* Get phy ID */
id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);
nic->phy = (u32)id_hi << 16 | (u32)id_lo;
DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
+ /* Select the phy and isolate the rest */
+ for (addr = 0; addr < 32; addr++) {
+ if (addr != nic->mii.phy_id) {
+ mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
+ } else if (nic->phy != phy_82552_v) {
+ bmcr = mdio_read(netdev, addr, MII_BMCR);
+ mdio_write(netdev, addr, MII_BMCR,
+ bmcr & ~BMCR_ISOLATE);
+ }
+ }
+ /*
+ * Workaround for 82552:
+ * Clear the ISOLATE bit on selected phy_id last (mirrored on all
+ * other phy_id's) using bmcr value from addr discovery loop above.
+ */
+ if (nic->phy == phy_82552_v)
+ mdio_write(netdev, nic->mii.phy_id, MII_BMCR,
+ bmcr & ~BMCR_ISOLATE);
+
/* Handle National tx phys */
#define NCS_PHY_MODEL_MASK 0xFFF0FFFF
if ((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {
static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
struct net_device *netdev = nic->netdev;
- struct dev_mc_list *list = netdev->mc_list;
- u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS);
+ struct dev_mc_list *list;
+ u16 i, count = min(netdev_mc_count(netdev), E100_MAX_MULTICAST_ADDRS);
cb->command = cpu_to_le16(cb_multi);
cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
- for (i = 0; list && i < count; i++, list = list->next)
- memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,
+ i = 0;
+ netdev_for_each_mc_addr(list, netdev) {
+ if (i == count)
+ break;
+ memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &list->dmi_addr,
ETH_ALEN);
+ }
}
static void e100_set_multicast_list(struct net_device *netdev)
struct nic *nic = netdev_priv(netdev);
DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
- netdev->mc_count, netdev->flags);
+ netdev_mc_count(netdev), netdev->flags);
if (netdev->flags & IFF_PROMISC)
nic->flags |= promiscuous;
nic->flags &= ~promiscuous;
if (netdev->flags & IFF_ALLMULTI ||
- netdev->mc_count > E100_MAX_MULTICAST_ADDRS)
+ netdev_mc_count(netdev) > E100_MAX_MULTICAST_ADDRS)
nic->flags |= multicast_all;
else
nic->flags &= ~multicast_all;
cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
}
-static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
+ struct net_device *netdev)
{
struct nic *nic = netdev_priv(netdev);
int err;
nic->cb_to_clean = nic->cb_to_clean->next;
nic->cbs_avail++;
}
- pci_free_consistent(nic->pdev,
- sizeof(struct cb) * nic->params.cbs.count,
- nic->cbs, nic->cbs_dma_addr);
+ pci_pool_free(nic->cbs_pool, nic->cbs, nic->cbs_dma_addr);
nic->cbs = NULL;
nic->cbs_avail = 0;
}
nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;
nic->cbs_avail = 0;
- nic->cbs = pci_alloc_consistent(nic->pdev,
- sizeof(struct cb) * count, &nic->cbs_dma_addr);
+ nic->cbs = pci_pool_alloc(nic->cbs_pool, GFP_KERNEL,
+ &nic->cbs_dma_addr);
if (!nic->cbs)
return -ENOMEM;
+ memset(nic->cbs, 0, count * sizeof(struct cb));
for (cb = nic->cbs, i = 0; i < count; cb++, i++) {
cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
cb->link = cpu_to_le32(nic->cbs_dma_addr +
((i+1) % count) * sizeof(struct cb));
- cb->skb = NULL;
}
nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
{
- if (!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
+ if (!(rx->skb = netdev_alloc_skb_ip_align(nic->netdev, RFD_BUF_LEN)))
return -ENOMEM;
- /* Align, init, and map the RFD. */
- skb_reserve(rx->skb, NET_IP_ALIGN);
+ /* Init, and map the RFD. */
skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd));
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
if (ioread8(&nic->csr->scb.status) & rus_no_res)
nic->ru_running = RU_SUSPENDED;
+ pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
+ sizeof(struct rfd),
+ PCI_DMA_FROMDEVICE);
return -ENODATA;
}
DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
ioread8(&nic->csr->scb.status));
- e100_down(netdev_priv(netdev));
- e100_up(netdev_priv(netdev));
+
+ rtnl_lock();
+ if (netif_running(netdev)) {
+ e100_down(netdev_priv(netdev));
+ e100_up(netdev_priv(netdev));
+ }
+ rtnl_unlock();
}
static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
goto err_out_free;
}
-
+ nic->cbs_pool = pci_pool_create(netdev->name,
+ nic->pdev,
+ nic->params.cbs.max * sizeof(struct cb),
+ sizeof(u32),
+ 0);
DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
pdev->irq, netdev->dev_addr);
unregister_netdev(netdev);
e100_free(nic);
pci_iounmap(pdev, nic->csr);
+ pci_pool_destroy(nic->cbs_pool);
free_netdev(netdev);
pci_release_regions(pdev);
pci_disable_device(pdev);