View
220
Download
2
Embed Size (px)
Citation preview
Introduce
NIC
Ring buffer
Ring buffer
Driver
Transmit
receive
DriverISR
DriverISR CPU
Memory
Memory
Pending queue
While complete
Interrupt
Transfer until buffer is empty
Device busy
Code survey
• static int __init ipw_init(void)• static void __exit ipw_exit(void)• static int ipw_pci_resume(struct pci_dev *pdev)• static int ipw_pci_suspend(struct pci_dev *pdev,
pm_message_t state)• static void ipw_pci_remove(struct pci_dev *pdev)• static int ipw_pci_probe(struct pci_dev *pdev, co
nst struct pci_device_id *ent)• static irqreturn_t ipw_isr(int irq, void *data, struc
t pt_regs *regs)• static void ipw_rx(struct ipw_priv *priv)
Code survey• Struct ipw_priv {
/* ieee device used by generic ieee processing code */struct ieee80211_device *ieee;spinlock_t lock;spinlock_t irq_lock;struct mutex mutex; /* basic pci-network driver stuff */
struct pci_dev *pci_dev;struct net_device *net_dev;
#ifdef CONFIG_IPW2200_PROMISCUOUS/* Promiscuous mode */struct ipw_prom_priv *prom_priv;struct net_device *prom_net_dev;
#endif/* pci hardware address support */
• ……………
• See ipw2200.h line 1187
Code survey• static int __init ipw_init(void){
int ret;printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");ret = pci_module_init(&ipw_driver);if (ret) {
IPW_ERROR("Unable to initialize PCI module\n");return ret;
}ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);if (ret) {
IPW_ERROR("Unable to create driver sysfs file\n");pci_unregister_driver(&ipw_driver);return ret;
}return ret;
}
Code survey
• static void __exit ipw_exit(void){
driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);pci_unregister_driver(&ipw_driver);
}
Code surveystatic int ipw_pci_resume(struct pci_dev *pdev){
struct ipw_priv *priv = pci_get_drvdata(pdev);struct net_device *dev = priv->net_dev;u32 val;printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)pci_set_power_state(pdev, 0);
#elsepci_set_power_state(pdev, PCI_D0);
#endifpci_enable_device(pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)pci_restore_state(pdev, priv->pm_state);
#else pci_restore_state(pdev);#endif
pci_read_config_dword(pdev, 0x40, &val);if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);netif_device_attach(dev);/* Bring the device back up */queue_work(priv->workqueue, &priv->up);return 0;
}
Code surveystatic int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)#endif{
struct ipw_priv *priv = pci_get_drvdata(pdev);struct net_device *dev = priv->net_dev;printk(KERN_INFO "%s: Going into suspend...\n", dev->name);/* Take down the device; powers it off, etc. */ipw_down(priv);/* Remove the PRESENT state of the device */netif_device_detach(dev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)pci_save_state(pdev, priv->pm_state);
#elsepci_save_state(pdev);
#endifpci_disable_device(pdev);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)pci_set_power_state(pdev, state);
#elsepci_set_power_state(pdev, pci_choose_state(pdev, state));
#endifreturn 0;
}
Code surveystatic void ipw_pci_remove(struct pci_dev *pdev){
struct ipw_priv *priv = pci_get_drvdata(pdev);struct list_head *p, *q; int i;if (!priv)
return;mutex_lock(&priv->mutex);priv->status |= STATUS_EXIT_PENDING;ipw_down(priv);sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);mutex_unlock(&priv->mutex);unregister_netdev(priv->net_dev);if (priv->rxq) {
ipw_rx_queue_free(priv, priv->rxq);priv->rxq = NULL;
}ipw_tx_queue_free(priv);if (priv->cmdlog) {
kfree(priv->cmdlog);priv->cmdlog = NULL;
}
………… see ipw2200.c line 12360
Code surveystatic int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en
t){
int err = 0;struct net_device *net_dev;void __iomem *base;u32 length, val;struct ipw_priv *priv; int i;net_dev = alloc_ieee80211(sizeof(struct ipw_priv));if (net_dev == NULL) {
err = -ENOMEM;goto out;
} priv = ieee80211_priv(net_dev);priv->ieee = netdev_priv(net_dev);priv->net_dev = net_dev;priv->pci_dev = pdev;ipw_debug_level = debug;spin_lock_init(&priv->lock);spin_lock_init(&priv->irq_lock);
………… see ipw2200.c line 12182
Code survey
static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs){
struct ipw_priv *priv = data;u32 inta, inta_mask;if (!priv)
return IRQ_NONE;spin_lock(&priv->irq_lock);if (!(priv->status & STATUS_INT_ENABLED)) {
/* Shared IRQ */goto none;
}inta = ipw_read32(priv, IPW_INTA_RW);inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
……… see ipw2200.c line 11070
Code surveystatic void ipw_rx(struct ipw_priv *priv){
struct ipw_rx_mem_buffer *rxb;struct ipw_rx_packet *pkt;struct ieee80211_hdr_4addr *header;u32 r, w, i;u8 network_packet;r = ipw_read32(priv, IPW_RX_READ_INDEX);w = ipw_read32(priv, IPW_RX_WRITE_INDEX);i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;while (i != r) {
rxb = priv->rxq->queue[i];if (unlikely(rxb == NULL)) {
printk(KERN_CRIT "Queue not allocated!\n");break;
}priv->rxq->queue[i] = NULL;pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
pkt = (struct ipw_rx_packet *)rxb->skb->data;
………… see ipw2200.c line 8714
Code survey
• Rx theory of operation * Driver sequence: * ipw_rx_queue_alloc() ipw_rx_queue_replenish() ipw_rx_queue_restock() * -- enable interrupts -- *
ISR - ipw_rx()