[PATCH] e100: Render e100 NAPI state machine
Render e100 NAPI state machine to be similar to the non-NAPI one. Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com> Signed-off-by: Ganesh Venkatesan <ganesh.venkatesan@intel.com> Signed-off-by: John Ronciak <john.ronciak@intel.com>
This commit is contained in:
Родитель
2acdb1e05c
Коммит
1f53367d5d
|
@ -269,6 +269,12 @@ enum scb_status {
|
||||||
rus_mask = 0x3C,
|
rus_mask = 0x3C,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ru_state {
|
||||||
|
RU_SUSPENDED = 0,
|
||||||
|
RU_RUNNING = 1,
|
||||||
|
RU_UNINITIALIZED = -1,
|
||||||
|
};
|
||||||
|
|
||||||
enum scb_stat_ack {
|
enum scb_stat_ack {
|
||||||
stat_ack_not_ours = 0x00,
|
stat_ack_not_ours = 0x00,
|
||||||
stat_ack_sw_gen = 0x04,
|
stat_ack_sw_gen = 0x04,
|
||||||
|
@ -510,7 +516,7 @@ struct nic {
|
||||||
struct rx *rx_to_use;
|
struct rx *rx_to_use;
|
||||||
struct rx *rx_to_clean;
|
struct rx *rx_to_clean;
|
||||||
struct rfd blank_rfd;
|
struct rfd blank_rfd;
|
||||||
int ru_running;
|
enum ru_state ru_running;
|
||||||
|
|
||||||
spinlock_t cb_lock ____cacheline_aligned;
|
spinlock_t cb_lock ____cacheline_aligned;
|
||||||
spinlock_t cmd_lock;
|
spinlock_t cmd_lock;
|
||||||
|
@ -1204,7 +1210,9 @@ static void e100_update_stats(struct nic *nic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e100_exec_cmd(nic, cuc_dump_reset, 0);
|
|
||||||
|
if(e100_exec_cmd(nic, cuc_dump_reset, 0))
|
||||||
|
DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
|
static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
|
||||||
|
@ -1298,7 +1306,8 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
||||||
/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
|
/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
|
||||||
Issue a NOP command followed by a 1us delay before
|
Issue a NOP command followed by a 1us delay before
|
||||||
issuing the Tx command. */
|
issuing the Tx command. */
|
||||||
e100_exec_cmd(nic, cuc_nop, 0);
|
if(e100_exec_cmd(nic, cuc_nop, 0))
|
||||||
|
DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
|
||||||
udelay(1);
|
udelay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1416,12 +1425,18 @@ static int e100_alloc_cbs(struct nic *nic)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void e100_start_receiver(struct nic *nic)
|
static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
|
||||||
{
|
{
|
||||||
|
if(!nic->rxs) return;
|
||||||
|
if(RU_SUSPENDED != nic->ru_running) return;
|
||||||
|
|
||||||
|
/* handle init time starts */
|
||||||
|
if(!rx) rx = nic->rxs;
|
||||||
|
|
||||||
/* (Re)start RU if suspended or idle and RFA is non-NULL */
|
/* (Re)start RU if suspended or idle and RFA is non-NULL */
|
||||||
if(!nic->ru_running && nic->rx_to_clean->skb) {
|
if(rx->skb) {
|
||||||
e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
|
e100_exec_cmd(nic, ruc_start, rx->dma_addr);
|
||||||
nic->ru_running = 1;
|
nic->ru_running = RU_RUNNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1438,6 +1453,13 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
|
||||||
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
|
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
|
||||||
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
|
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
|
if(pci_dma_mapping_error(rx->dma_addr)) {
|
||||||
|
dev_kfree_skb_any(rx->skb);
|
||||||
|
rx->skb = 0;
|
||||||
|
rx->dma_addr = 0;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
/* Link the RFD to end of RFA by linking previous RFD to
|
/* Link the RFD to end of RFA by linking previous RFD to
|
||||||
* this one, and clearing EL bit of previous. */
|
* this one, and clearing EL bit of previous. */
|
||||||
if(rx->prev->skb) {
|
if(rx->prev->skb) {
|
||||||
|
@ -1472,7 +1494,7 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
|
||||||
|
|
||||||
/* If data isn't ready, nothing to indicate */
|
/* If data isn't ready, nothing to indicate */
|
||||||
if(unlikely(!(rfd_status & cb_complete)))
|
if(unlikely(!(rfd_status & cb_complete)))
|
||||||
return -EAGAIN;
|
return -ENODATA;
|
||||||
|
|
||||||
/* Get actual data size */
|
/* Get actual data size */
|
||||||
actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
|
actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
|
||||||
|
@ -1483,6 +1505,10 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
|
||||||
pci_unmap_single(nic->pdev, rx->dma_addr,
|
pci_unmap_single(nic->pdev, rx->dma_addr,
|
||||||
RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
|
RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
|
||||||
|
|
||||||
|
/* this allows for a fast restart without re-enabling interrupts */
|
||||||
|
if(le16_to_cpu(rfd->command) & cb_el)
|
||||||
|
nic->ru_running = RU_SUSPENDED;
|
||||||
|
|
||||||
/* Pull off the RFD and put the actual data (minus eth hdr) */
|
/* Pull off the RFD and put the actual data (minus eth hdr) */
|
||||||
skb_reserve(skb, sizeof(struct rfd));
|
skb_reserve(skb, sizeof(struct rfd));
|
||||||
skb_put(skb, actual_size);
|
skb_put(skb, actual_size);
|
||||||
|
@ -1515,20 +1541,45 @@ static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
|
||||||
unsigned int work_to_do)
|
unsigned int work_to_do)
|
||||||
{
|
{
|
||||||
struct rx *rx;
|
struct rx *rx;
|
||||||
|
int restart_required = 0;
|
||||||
|
struct rx *rx_to_start = NULL;
|
||||||
|
|
||||||
|
/* are we already rnr? then pay attention!!! this ensures that
|
||||||
|
* the state machine progression never allows a start with a
|
||||||
|
* partially cleaned list, avoiding a race between hardware
|
||||||
|
* and rx_to_clean when in NAPI mode */
|
||||||
|
if(RU_SUSPENDED == nic->ru_running)
|
||||||
|
restart_required = 1;
|
||||||
|
|
||||||
/* Indicate newly arrived packets */
|
/* Indicate newly arrived packets */
|
||||||
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
|
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
|
||||||
if(e100_rx_indicate(nic, rx, work_done, work_to_do))
|
int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
|
||||||
|
if(-EAGAIN == err) {
|
||||||
|
/* hit quota so have more work to do, restart once
|
||||||
|
* cleanup is complete */
|
||||||
|
restart_required = 0;
|
||||||
|
break;
|
||||||
|
} else if(-ENODATA == err)
|
||||||
break; /* No more to clean */
|
break; /* No more to clean */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save our starting point as the place we'll restart the receiver */
|
||||||
|
if(restart_required)
|
||||||
|
rx_to_start = nic->rx_to_clean;
|
||||||
|
|
||||||
/* Alloc new skbs to refill list */
|
/* Alloc new skbs to refill list */
|
||||||
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
|
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
|
||||||
if(unlikely(e100_rx_alloc_skb(nic, rx)))
|
if(unlikely(e100_rx_alloc_skb(nic, rx)))
|
||||||
break; /* Better luck next time (see watchdog) */
|
break; /* Better luck next time (see watchdog) */
|
||||||
}
|
}
|
||||||
|
|
||||||
e100_start_receiver(nic);
|
if(restart_required) {
|
||||||
|
// ack the rnr?
|
||||||
|
writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
|
||||||
|
e100_start_receiver(nic, rx_to_start);
|
||||||
|
if(work_done)
|
||||||
|
(*work_done)++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void e100_rx_clean_list(struct nic *nic)
|
static void e100_rx_clean_list(struct nic *nic)
|
||||||
|
@ -1536,6 +1587,8 @@ static void e100_rx_clean_list(struct nic *nic)
|
||||||
struct rx *rx;
|
struct rx *rx;
|
||||||
unsigned int i, count = nic->params.rfds.count;
|
unsigned int i, count = nic->params.rfds.count;
|
||||||
|
|
||||||
|
nic->ru_running = RU_UNINITIALIZED;
|
||||||
|
|
||||||
if(nic->rxs) {
|
if(nic->rxs) {
|
||||||
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
|
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
|
||||||
if(rx->skb) {
|
if(rx->skb) {
|
||||||
|
@ -1549,7 +1602,6 @@ static void e100_rx_clean_list(struct nic *nic)
|
||||||
}
|
}
|
||||||
|
|
||||||
nic->rx_to_use = nic->rx_to_clean = NULL;
|
nic->rx_to_use = nic->rx_to_clean = NULL;
|
||||||
nic->ru_running = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int e100_rx_alloc_list(struct nic *nic)
|
static int e100_rx_alloc_list(struct nic *nic)
|
||||||
|
@ -1558,6 +1610,7 @@ static int e100_rx_alloc_list(struct nic *nic)
|
||||||
unsigned int i, count = nic->params.rfds.count;
|
unsigned int i, count = nic->params.rfds.count;
|
||||||
|
|
||||||
nic->rx_to_use = nic->rx_to_clean = NULL;
|
nic->rx_to_use = nic->rx_to_clean = NULL;
|
||||||
|
nic->ru_running = RU_UNINITIALIZED;
|
||||||
|
|
||||||
if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
|
if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1573,6 +1626,7 @@ static int e100_rx_alloc_list(struct nic *nic)
|
||||||
}
|
}
|
||||||
|
|
||||||
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
|
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
|
||||||
|
nic->ru_running = RU_SUSPENDED;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1594,7 +1648,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
|
|
||||||
/* We hit Receive No Resource (RNR); restart RU after cleaning */
|
/* We hit Receive No Resource (RNR); restart RU after cleaning */
|
||||||
if(stat_ack & stat_ack_rnr)
|
if(stat_ack & stat_ack_rnr)
|
||||||
nic->ru_running = 0;
|
nic->ru_running = RU_SUSPENDED;
|
||||||
|
|
||||||
e100_disable_irq(nic);
|
e100_disable_irq(nic);
|
||||||
netif_rx_schedule(netdev);
|
netif_rx_schedule(netdev);
|
||||||
|
@ -1684,7 +1738,7 @@ static int e100_up(struct nic *nic)
|
||||||
if((err = e100_hw_init(nic)))
|
if((err = e100_hw_init(nic)))
|
||||||
goto err_clean_cbs;
|
goto err_clean_cbs;
|
||||||
e100_set_multicast_list(nic->netdev);
|
e100_set_multicast_list(nic->netdev);
|
||||||
e100_start_receiver(nic);
|
e100_start_receiver(nic, 0);
|
||||||
mod_timer(&nic->watchdog, jiffies);
|
mod_timer(&nic->watchdog, jiffies);
|
||||||
if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
|
if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
|
||||||
nic->netdev->name, nic->netdev)))
|
nic->netdev->name, nic->netdev)))
|
||||||
|
@ -1759,7 +1813,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
|
||||||
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
|
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
|
||||||
BMCR_LOOPBACK);
|
BMCR_LOOPBACK);
|
||||||
|
|
||||||
e100_start_receiver(nic);
|
e100_start_receiver(nic, 0);
|
||||||
|
|
||||||
if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
|
if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
@ -2233,6 +2287,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
|
||||||
|
|
||||||
e100_get_defaults(nic);
|
e100_get_defaults(nic);
|
||||||
|
|
||||||
|
/* locks must be initialized before calling hw_reset */
|
||||||
spin_lock_init(&nic->cb_lock);
|
spin_lock_init(&nic->cb_lock);
|
||||||
spin_lock_init(&nic->cmd_lock);
|
spin_lock_init(&nic->cmd_lock);
|
||||||
|
|
||||||
|
@ -2348,7 +2403,8 @@ static int e100_resume(struct pci_dev *pdev)
|
||||||
|
|
||||||
pci_set_power_state(pdev, PCI_D0);
|
pci_set_power_state(pdev, PCI_D0);
|
||||||
pci_restore_state(pdev);
|
pci_restore_state(pdev);
|
||||||
e100_hw_init(nic);
|
if(e100_hw_init(nic))
|
||||||
|
DPRINTK(HW, ERR, "e100_hw_init failed\n");
|
||||||
|
|
||||||
netif_device_attach(netdev);
|
netif_device_attach(netdev);
|
||||||
if(netif_running(netdev))
|
if(netif_running(netdev))
|
||||||
|
|
Загрузка…
Ссылка в новой задаче