diff options
Diffstat (limited to 'drivers')
42 files changed, 768 insertions, 984 deletions
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 1247846c538f..2fdb6f766e44 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -15,12 +15,6 @@ * * Things not working yet: * - * o We're only set up to compile as a module currently. i.e. - * you should put the source in drivers/atm/lanai.c and then - * just do "make drivers/atm/lanai.o" from the main - * source directory. This will produce a drivers/atm/lanai.o - * file suitable for insmod'ing - * * o We don't support the Speedstream 3060 yet - this card has * an on-board DSL modem chip by Alcatel and the driver will * need some extra code added to handle it @@ -245,9 +239,6 @@ struct lanai_vcc { struct atm_vcc *atmvcc; /* atm_vcc who is transmitter */ int endptr; /* last endptr from service entry */ struct sk_buff_head backlog; - struct sk_buff *inprogress; /* We're streaming this PDU */ - unsigned char *pptr; /* Where we are in above */ - int inprogleft; /* Bytes left to send "inprogress" */ void (*unqueue)(struct lanai_dev *, struct lanai_vcc *, int); } tx; }; @@ -268,8 +259,6 @@ struct lanai_dev_stats { unsigned pcierr_m_target_abort; unsigned pcierr_s_target_abort; unsigned pcierr_master_parity; - unsigned service_novcc_rx; - unsigned service_novcc_tx; unsigned service_notx; unsigned service_norx; unsigned service_rxnotaal5; @@ -297,7 +286,7 @@ struct lanai_dev { struct lanai_buffer aal0buf; /* AAL0 RX buffers */ u32 conf1, conf2; /* CONFIG[12] registers */ u32 status; /* STATUS register */ - spinlock_t txlock; + spinlock_t endtxlock; spinlock_t servicelock; struct atm_vcc *cbrvcc; int number; @@ -501,7 +490,6 @@ static inline void reg_write(const struct lanai_dev *lanai, u32 val, RWDEBUG("W [0x%08X] 0x%02X < 0x%08X\n", (unsigned int) lanai->base, (int) reg, val); writel(val, reg_addr(lanai, reg)); - mdelay(1); } static inline void conf1_write(const struct lanai_dev *lanai) @@ -537,63 +525,6 @@ static inline void reset_board(const struct lanai_dev *lanai) udelay(5); } -/* -------------------- VCC LIST LOCK: */ - -/* - * The linux-atm code disables local IRQs while managing the list of - * VCCs on a card. This is good, but it doesn't save us against - * SMP. Unfortunately, fixing this will require changes in the - * API which will have to wait a little bit. It's a hard race to - * trigger accidentally, so it isn't TOO horrible so far. - * - * One possible solution would be to have an rwlock which is - * always grabbed _irq-style on writing. This would automatically - * be grabbed (for writing) by the higher layers on things that - * would result in a change in the vcc list (_open, _close, - * probably _change_qos) - thus it would also protect the - * higher-level list of vccs on each device (atm_dev->vccs). - * The driver would be responsible for grabbing it as a read_lock - * anytime it wants to consult its table of vccs - for instance - * when handling an incoming PDU. This also explains why we would - * probably want the write_lock while in _change_qos - to prevent - * handling of PDUs while possibly in an inconsistent state. - * Also, _send would grab the lock for reading. - * - * One problem with this is that _open and _close could no longer - * do anything that might provoke a schedule. First, it would - * force us to use GFP_ATOMIC memory (which is bad), but also - * some devices pretty much require scheduling due to long - * delays (see lanai_close for an example). So in this case - * we need a way to schedule without losing the spinlock. - * The cleanest way to do this is probably have a way to mark a - * VCC as "in progress" so that the interrupt handler can - * still disregard any traffic for it while _open or _close - * are sleeping on it. Then it will need to be _open and - * _close's job to relinquish the write_lock. Thus, the - * lock could be dropped around the times that scheduling - * might occur. Perhaps the _READY flag can be used for - * this purpose. - * - * One short note about this "upper layer grabs, driver - * relinquishes" write lock - since this needs to be - * an _irq lock we're going to have problem saving - * and restoring flags (_irqsave/_irqrestore). This - * shouldn't be a problem, however - we must just - * require that those syscalls are never called with - * interrupts disabled so we can use the non-flags-saving - * versions. - * - * Anyway, all of the above is vaporware currently - fixing - * this right will require changes in the API and all of - * the drivers - this will wait until 2.5.x most likely. - * The following NOP macros are just here to mark where - * the locks will be needed in the future. - */ -#define vcclist_read_lock() do {} while (0) -#define vcclist_read_unlock() do {} while (0) -#define vcclist_write_lock() do {} while (0) -#define vcclist_write_unlock() do {} while (0) - /* -------------------- CARD SRAM UTILITIES: */ /* The SRAM is mapped into normal PCI memory space - the only catch is @@ -851,36 +782,39 @@ static void lanai_shutdown_tx_vci(struct lanai_dev *lanai, if (lvcc->vbase == 0) /* We were never bound to a VCI */ return; /* 15.2.1 - wait for queue to drain */ - spin_lock_irqsave(&lanai->txlock, flags); - if (lvcc->tx.inprogress != NULL) { - lanai_free_skb(lvcc->tx.atmvcc, lvcc->tx.inprogress); - lvcc->tx.inprogress = NULL; - } while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL) lanai_free_skb(lvcc->tx.atmvcc, skb); + read_lock_irqsave(&vcc_sklist_lock, flags); __clear_bit(lvcc->vci, lanai->backlog_vccs); - spin_unlock_irqrestore(&lanai->txlock, flags); - timeout = jiffies + ((lanai_buf_size(&lvcc->tx.buf) * HZ) >> 17); + read_unlock_irqrestore(&vcc_sklist_lock, flags); + /* + * We need to wait for the VCC to drain but don't wait forever. We + * give each 1K of buffer size 1/128th of a second to clear out. + * TODO: maybe disable CBR if we're about to timeout? + */ + timeout = jiffies + + (((lanai_buf_size(&lvcc->tx.buf) / 1024) * HZ) >> 7); write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr)); - goto start; - while (time_before_eq(jiffies, timeout)) { - schedule_timeout(HZ / 25); - start: + for (;;) { read = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); if (read == write && /* Is TX buffer empty? */ (lvcc->tx.atmvcc->qos.txtp.traffic_class != ATM_CBR || (cardvcc_read(lvcc, vcc_txcbr_next) & TXCBR_NEXT_BOZO) == 0)) - goto done; + break; if (read != lastread) { /* Has there been any progress? */ lastread = read; timeout += HZ / 10; } + if (unlikely(time_after(jiffies, timeout))) { + printk(KERN_ERR DEV_LABEL "(itf %d): Timed out on " + "backlog closing vci %d\n", + lvcc->tx.atmvcc->dev->number, lvcc->vci); + DPRINTK("read, write = %d, %d\n", read, write); + break; + } + schedule_timeout(HZ / 25); } - printk(KERN_ERR DEV_LABEL "(itf %d): Timed out on backlog closing " - "vci %d\n", lvcc->tx.atmvcc->dev->number, lvcc->vci); - DPRINTK("read, write = %d, %d\n", read, write); - done: /* 15.2.2 - clear out all tx registers */ cardvcc_write(lvcc, 0, vcc_txreadptr); cardvcc_write(lvcc, 0, vcc_txwriteptr); @@ -1226,8 +1160,7 @@ static inline int vcc_tx_space(const struct lanai_vcc *lvcc, int endptr) /* test if VCC is currently backlogged */ static inline int vcc_is_backlogged(/*const*/ struct lanai_vcc *lvcc) { - return lvcc->tx.inprogress != NULL || - !skb_queue_empty(&lvcc->tx.backlog); + return !skb_queue_empty(&lvcc->tx.backlog); } /* Bit fields in the segmentation buffer descriptor */ @@ -1264,11 +1197,11 @@ static inline void vcc_tx_add_aal5_descriptor(struct lanai_vcc *lvcc, } /* Add 32-bit AAL5 trailer and leave room for its CRC */ -static inline void vcc_tx_add_aal5trailer(struct lanai_vcc *lvcc, +static inline void vcc_tx_add_aal5_trailer(struct lanai_vcc *lvcc, int len, int cpi, int uu) { APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 8, - "vcc_tx_add_aal5_descriptor: bad ptr=%p\n", lvcc->tx.buf.ptr); + "vcc_tx_add_aal5_trailer: bad ptr=%p\n", lvcc->tx.buf.ptr); lvcc->tx.buf.ptr += 2; lvcc->tx.buf.ptr[-2] = cpu_to_be32((uu << 24) | (cpi << 16) | len); if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end) @@ -1311,7 +1244,7 @@ static inline void vcc_tx_memzero(struct lanai_vcc *lvcc, int n) } /* Update "butt" register to specify new WritePtr */ -static inline void lanai_endtx(const struct lanai_dev *lanai, +static inline void lanai_endtx(struct lanai_dev *lanai, const struct lanai_vcc *lvcc) { int i, ptr = ((unsigned char *) lvcc->tx.buf.ptr) - @@ -1320,6 +1253,14 @@ static inline void lanai_endtx(const struct lanai_dev *lanai, "lanai_endtx: bad ptr (%d), vci=%d, start,ptr,end=%p,%p,%p\n", ptr, lvcc->vci, lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end); + + /* + * Since the "butt register" is a shared resounce on the card we + * serialize all accesses to it through this spinlock. This is + * mostly just paranoia sicne the register is rarely "busy" anyway + * but is needed for correctness. + */ + spin_lock(&lanai->endtxlock); /* * We need to check if the "butt busy" bit is set before * updating the butt register. In theory this should @@ -1334,131 +1275,86 @@ static inline void lanai_endtx(const struct lanai_dev *lanai, } udelay(5); } + /* + * Before we tall the card to start work we need to be sure 100% of + * the info in the service buffer has been written before we tell + * the card about it + */ + wmb(); reg_write(lanai, (ptr << 12) | lvcc->vci, Butt_Reg); + spin_unlock(&lanai->endtxlock); +} + +/* + * Add one AAL5 PDU to lvcc's transmit buffer. Caller garauntees there's + * space available. "pdusize" is the number of bytes the PDU will take + */ +static void lanai_send_one_aal5(struct lanai_dev *lanai, + struct lanai_vcc *lvcc, struct sk_buff *skb, int pdusize) +{ + int pad; + APRINTK(pdusize == aal5_size(skb->len), + "lanai_send_one_aal5: wrong size packet (%d != %d)\n", + pdusize, aal5_size(skb->len)); + vcc_tx_add_aal5_descriptor(lvcc, 0, pdusize); + pad = pdusize - skb->len - 8; + APRINTK(pad >= 0, "pad is negative (%d)\n", pad); + APRINTK(pad < 48, "pad is too big (%d)\n", pad); + vcc_tx_memcpy(lvcc, skb->data, skb->len); + vcc_tx_memzero(lvcc, pad); + vcc_tx_add_aal5_trailer(lvcc, skb->len, 0, 0); + lanai_endtx(lanai, lvcc); + lanai_free_skb(lvcc->tx.atmvcc, skb); + atomic_inc(&lvcc->tx.atmvcc->stats->tx); } /* Try to fill the buffer - don't call unless there is backlog */ static void vcc_tx_unqueue_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc, int endptr) { - int pad, n; + int n; struct sk_buff *skb; int space = vcc_tx_space(lvcc, endptr); APRINTK(vcc_is_backlogged(lvcc), "vcc_tx_unqueue() called with empty backlog (vci=%d)\n", lvcc->vci); - if (space < 64) - return; /* No space for even 1 cell+descriptor */ - if (lvcc->tx.inprogress != NULL) { - APRINTK((lvcc->tx.inprogleft % 48) == 0, - "vcc_tx_unqueue_aal5: bad progleft=%d\n", - lvcc->tx.inprogleft); - if (lvcc->tx.inprogleft + 16 > space) { /* Can't send all? */ - n = aal5_spacefor(space - 16); /* Bytes to send */ - vcc_tx_add_aal5_descriptor(lvcc, - DESCRIPTOR_AAL5_STREAM, n); - pad = lvcc->tx.pptr + n - lvcc->tx.inprogress->tail; - if (pad < 0) - pad = 0; - vcc_tx_memcpy(lvcc, lvcc->tx.pptr, n - pad); - vcc_tx_memzero(lvcc, pad); - lvcc->tx.pptr += n; - lvcc->tx.inprogleft -= n; - goto end; /* Buffer is now full */ - } - /* OK, there's at least space for all of "inprogress" skb */ - vcc_tx_add_aal5_descriptor(lvcc, 0, - lvcc->tx.inprogleft); - pad = lvcc->tx.pptr + lvcc->tx.inprogleft - - lvcc->tx.inprogress->tail; - if (pad >= lvcc->tx.inprogleft) { /* Nothing but pad left */ - APRINTK(lvcc->tx.inprogleft == 48, - "vcc_tx_unqueue_aal5: bad pure-pad=%d\n", - lvcc->tx.inprogleft); - pad = 48; - } else - vcc_tx_memcpy(lvcc, lvcc->tx.pptr, - lvcc->tx.inprogleft - pad); - vcc_tx_memzero(lvcc, pad - 8); - vcc_tx_add_aal5trailer(lvcc, lvcc->tx.inprogress->len, 0, 0); - lanai_free_skb(lvcc->tx.atmvcc, lvcc->tx.inprogress); - lvcc->tx.inprogress = NULL; - space -= lvcc->tx.inprogleft + 16; - atomic_inc(&lvcc->tx.atmvcc->stats->tx); - } while (space >= 64) { - if ((skb = skb_dequeue(&lvcc->tx.backlog)) == NULL) - break; + skb = skb_dequeue(&lvcc->tx.backlog); + if (skb == NULL) + goto no_backlog; n = aal5_size(skb->len); - if (n + 16 > space) { /* Can only send part */ - int m = aal5_spacefor(space - 16); /* Bytes to send */ - vcc_tx_add_aal5_descriptor(lvcc, - DESCRIPTOR_AAL5_STREAM, m); - lvcc->tx.pptr = skb->data + m; - pad = lvcc->tx.pptr - skb->tail; - if (pad < 0) - pad = 0; - vcc_tx_memcpy(lvcc, skb->data, m - pad); - vcc_tx_memzero(lvcc, pad); - lvcc->tx.inprogleft = n - m; - lvcc->tx.inprogress = skb; - goto end; + if (n + 16 > space) { + /* No room for this packet - put it back on queue */ + skb_queue_head(&lvcc->tx.backlog, skb); + return; } - vcc_tx_add_aal5_descriptor(lvcc, 0, n); - pad = n - skb->len - 8; - vcc_tx_memcpy(lvcc, skb->data, skb->len); - vcc_tx_memzero(lvcc, pad); - lanai_free_skb(lvcc->tx.atmvcc, skb); - vcc_tx_add_aal5trailer(lvcc, skb->len, 0, 0); + lanai_send_one_aal5(lanai, lvcc, skb, n); space -= n + 16; - atomic_inc(&lvcc->tx.atmvcc->stats->tx); } - if (skb_queue_empty(&lvcc->tx.backlog)) + if (!vcc_is_backlogged(lvcc)) { + no_backlog: __clear_bit(lvcc->vci, lanai->backlog_vccs); - end: - lanai_endtx(lanai, lvcc); + } } /* Given an skb that we want to transmit either send it now or queue */ static void vcc_tx_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc, struct sk_buff *skb) { - int space, n, pad; + int space, n; if (vcc_is_backlogged(lvcc)) /* Already backlogged */ goto queue_it; - space = vcc_tx_space(lvcc, TXREADPTR_GET_PTR(cardvcc_read(lvcc, - vcc_txreadptr))); - if (space < 64) { /* No space at all */ - __set_bit(lvcc->vci, lanai->backlog_vccs); - goto queue_it; - } - if (space >= 16 + (n = aal5_size(skb->len))) { - /* We can send the whole thing now */ - vcc_tx_add_aal5_descriptor(lvcc, 0, n); - pad = n - skb->len; - vcc_tx_memcpy(lvcc, skb->data, skb->len); - vcc_tx_memzero(lvcc, pad - 8); - vcc_tx_add_aal5trailer(lvcc, skb->len, 0, 0); - lanai_free_skb(lvcc->tx.atmvcc, skb); - atomic_inc(&lvcc->tx.atmvcc->stats->tx); - } else { /* Space for only part of skb */ - int bytes = aal5_spacefor(space - 16); /* Bytes to send */ - vcc_tx_add_aal5_descriptor(lvcc, - DESCRIPTOR_AAL5_STREAM, bytes); - pad = bytes - skb->len; - if (pad < 0) - pad = 0; - vcc_tx_memcpy(lvcc, skb->data, bytes - pad); - vcc_tx_memzero(lvcc, pad); - lvcc->tx.inprogress = skb; - lvcc->tx.inprogleft = n - bytes; - lvcc->tx.pptr = skb->data + bytes; + space = vcc_tx_space(lvcc, + TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr))); + n = aal5_size(skb->len); + APRINTK(n + 16 >= 64, "vcc_tx_aal5: n too small (%d)\n", n); + if (space < n + 16) { /* No space for this PDU */ __set_bit(lvcc->vci, lanai->backlog_vccs); + queue_it: + skb_queue_tail(&lvcc->tx.backlog, skb); + return; } - lanai_endtx(lanai, lvcc); - return; - queue_it: - skb_queue_tail(&lvcc->tx.backlog, skb); + lanai_send_one_aal5(lanai, lvcc, skb, n); } static void vcc_tx_unqueue_aal0(struct lanai_dev *lanai, @@ -1476,28 +1372,6 @@ static void vcc_tx_aal0(struct lanai_dev *lanai, struct lanai_vcc *lvcc, lanai_free_skb(lvcc->tx.atmvcc, skb); } -/* Try to undequeue 1 backlogged vcc */ -static void iter_dequeue(struct lanai_dev *lanai, vci_t vci) -{ - struct lanai_vcc *lvcc = lanai->vccs[vci]; - int endptr; - if (lvcc == NULL || !vcc_is_backlogged(lvcc)) { - __clear_bit(vci, lanai->backlog_vccs); - return; - } - endptr = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); - lvcc->tx.unqueue(lanai, lvcc, endptr); -} - -/* Try a dequeue on all backlogged connections */ -static inline void vcc_tx_dequeue_all(struct lanai_dev *lanai) -{ - unsigned long flags; - spin_lock_irqsave(&lanai->txlock, flags); - vci_bitfield_iterate(lanai, lanai->backlog_vccs, iter_dequeue); - spin_unlock_irqrestore(&lanai->txlock, flags); -} - /* -------------------- VCC RX BUFFER UTILITIES: */ /* unlike the _tx_ cousins, this doesn't update ptr */ @@ -1510,6 +1384,8 @@ static inline void vcc_rx_memcpy(unsigned char *dest, m = 0; memcpy(dest, lvcc->rx.buf.ptr, n - m); memcpy(dest + n - m, lvcc->rx.buf.start, m); + /* Make sure that these copies don't get reordered */ + barrier(); } /* Receive AAL5 data on a VCC with a particular endptr */ @@ -1527,6 +1403,11 @@ static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) /* Recover the second-to-last word to get true pdu length */ if ((x = &end[-2]) < lvcc->rx.buf.start) x = &lvcc->rx.buf.end[-2]; + /* + * Before we actually read from the buffer, make sure the memory + * changes have arrived + */ + rmb(); size = be32_to_cpup(x) & 0xffff; if (unlikely(n != aal5_size(size))) { /* Make sure size matches padding */ @@ -1542,9 +1423,9 @@ static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) goto out; } skb_put(skb, size); + vcc_rx_memcpy(skb->data, lvcc, size); ATM_SKB(skb)->vcc = lvcc->rx.atmvcc; do_gettimeofday(&skb->stamp); - vcc_rx_memcpy(skb->data, lvcc, size); lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb); atomic_inc(&lvcc->rx.atmvcc->stats->rx); out: @@ -1555,7 +1436,7 @@ static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) static void vcc_rx_aal0(struct lanai_dev *lanai) { printk(KERN_INFO DEV_LABEL ": vcc_rx_aal0: not implemented\n"); - /* Remember to get vcclist_read_lock while looking up VC */ + /* Remember to get read_lock(&vcc_sklist_lock) while looking up VC */ /* Remember to increment lvcc->rx.atmvcc->stats->rx */ } @@ -1606,7 +1487,6 @@ static inline struct lanai_vcc *new_lanai_vcc(void) memset(&lvcc->stats, 0, sizeof lvcc->stats); lvcc->rx.buf.start = lvcc->tx.buf.start = NULL; skb_queue_head_init(&lvcc->tx.backlog); - lvcc->tx.inprogress = NULL; #ifdef DEBUG lvcc->tx.unqueue = NULL; lvcc->vci = -1; @@ -1617,14 +1497,14 @@ static inline struct lanai_vcc *new_lanai_vcc(void) static int lanai_get_sized_buffer(struct lanai_dev *lanai, struct lanai_buffer *buf, int max_sdu, int multiplier, - int min, const char *name) + const char *name) { int size; if (unlikely(max_sdu < 1)) max_sdu = 1; max_sdu = aal5_size(max_sdu); size = (max_sdu + 16) * multiplier + 16; - lanai_buf_allocate(buf, size, min, lanai->pci); + lanai_buf_allocate(buf, size, max_sdu + 32, lanai->pci); if (unlikely(buf->start == NULL)) return -ENOMEM; if (unlikely(lanai_buf_size(buf) < size)) @@ -1640,8 +1520,7 @@ static inline int lanai_setup_rx_vci_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc, const struct atm_qos *qos) { return lanai_get_sized_buffer(lanai, &lvcc->rx.buf, - qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, qos->rxtp.max_sdu + 32, - "RX"); + qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, "RX"); } /* Setup a TX buffer for a currently unbound AAL5 vci */ @@ -1659,7 +1538,7 @@ static int lanai_setup_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc, multiplier = AAL5_TX_MULTIPLIER; } return lanai_get_sized_buffer(lanai, &lvcc->tx.buf, max_sdu, - multiplier, 80, "TX"); + multiplier, "TX"); } static inline void host_vcc_bind(struct lanai_dev *lanai, @@ -1759,21 +1638,21 @@ static int handle_service(struct lanai_dev *lanai, u32 s) { vci_t vci = SERVICE_GET_VCI(s); struct lanai_vcc *lvcc; - vcclist_read_lock(); + read_lock(&vcc_sklist_lock); lvcc = lanai->vccs[vci]; if (unlikely(lvcc == NULL)) { - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); DPRINTK("(itf %d) got service entry 0x%X for nonexistent " "vcc %d\n", lanai->number, (unsigned int) s, vci); if (s & SERVICE_TX) - lanai->stats.service_novcc_tx++; + lanai->stats.service_notx++; else - lanai->stats.service_novcc_rx++; + lanai->stats.service_norx++; return 0; } if (s & SERVICE_TX) { /* segmentation interrupt */ if (unlikely(lvcc->tx.atmvcc == NULL)) { - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); DPRINTK("(itf %d) got service entry 0x%X for non-TX " "vcc %d\n", lanai->number, (unsigned int) s, vci); lanai->stats.service_notx++; @@ -1781,18 +1660,18 @@ static int handle_service(struct lanai_dev *lanai, u32 s) } __set_bit(vci, lanai->transmit_ready); lvcc->tx.endptr = SERVICE_GET_END(s); - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); return 1; } if (unlikely(lvcc->rx.atmvcc == NULL)) { - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); DPRINTK("(itf %d) got service entry 0x%X for non-RX " "vcc %d\n", lanai->number, (unsigned int) s, vci); lanai->stats.service_norx++; return 0; } if (unlikely(lvcc->rx.atmvcc->qos.aal != ATM_AAL5)) { - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 " "vcc %d\n", lanai->number, (unsigned int) s, vci); lanai->stats.service_rxnotaal5++; @@ -1801,12 +1680,12 @@ static int handle_service(struct lanai_dev *lanai, u32 s) } if (likely(!(s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)))) { vcc_rx_aal5(lvcc, SERVICE_GET_END(s)); - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); return 0; } if (s & SERVICE_TRASH) { int bytes; - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); DPRINTK("got trashed rx pdu on vci %d\n", vci); atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); lvcc->stats.x.aal5.service_trash++; @@ -1819,7 +1698,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) return 0; } if (s & SERVICE_STREAM) { - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); lvcc->stats.x.aal5.service_stream++; printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream " @@ -1832,7 +1711,7 @@ static int handle_service(struct lanai_dev *lanai, u32 s) lvcc->stats.x.aal5.service_rxcrc++; lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4]; cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr); - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); return 0; } @@ -1840,9 +1719,8 @@ static int handle_service(struct lanai_dev *lanai, u32 s) static void iter_transmit(struct lanai_dev *lanai, vci_t vci) { struct lanai_vcc *lvcc = lanai->vccs[vci]; - if (!vcc_is_backlogged(lvcc)) - return; - lvcc->tx.unqueue(lanai, lvcc, lvcc->tx.endptr); + if (vcc_is_backlogged(lvcc)) + lvcc->tx.unqueue(lanai, lvcc, lvcc->tx.endptr); } /* Run service queue -- called from interrupt context or with @@ -1862,13 +1740,11 @@ static void run_service(struct lanai_dev *lanai) } reg_write(lanai, wreg, ServRead_Reg); if (ntx != 0) { - spin_lock(&lanai->txlock); - vcclist_read_lock(); + read_lock(&vcc_sklist_lock); vci_bitfield_iterate(lanai, lanai->transmit_ready, iter_transmit); CLEAR_BITMAP(&lanai->transmit_ready, NUM_VCI); - vcclist_read_unlock(); - spin_unlock(&lanai->txlock); + read_unlock(&vcc_sklist_lock); } } @@ -1885,22 +1761,47 @@ static void get_statistics(struct lanai_dev *lanai) /* -------------------- POLLING TIMER: */ +#ifndef DEBUG_RW +/* Try to undequeue 1 backlogged vcc */ +static void iter_dequeue(struct lanai_dev *lanai, vci_t vci) +{ + struct lanai_vcc *lvcc = lanai->vccs[vci]; + int endptr; + if (lvcc == NULL || lvcc->tx.atmvcc == NULL || + !vcc_is_backlogged(lvcc)) { + __clear_bit(vci, lanai->backlog_vccs); + return; + } + endptr = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); + lvcc->tx.unqueue(lanai, lvcc, endptr); +} +#endif /* !DEBUG_RW */ + static void lanai_timed_poll(unsigned long arg) { -#ifndef DEBUG_RW struct lanai_dev *lanai = (struct lanai_dev *) arg; +#ifndef DEBUG_RW unsigned long flags; #ifdef USE_POWERDOWN if (lanai->conf1 & CONFIG1_POWERDOWN) return; -#endif - spin_lock_irqsave(&lanai->servicelock, flags); - run_service(lanai); - spin_unlock_irqrestore(&lanai->servicelock, flags); - vcc_tx_dequeue_all(lanai); +#endif /* USE_POWERDOWN */ + local_irq_save(flags); + /* If we can grab the spinlock, check if any services need to be run */ + if (spin_trylock(&lanai->servicelock)) { + run_service(lanai); + spin_unlock(&lanai->servicelock); + } + /* ...and see if any backlogged VCs can make progress */ + /* unfortunately linux has no read_trylock() currently */ + read_lock(&vcc_sklist_lock); + vci_bitfield_iterate(lanai, lanai->backlog_vccs, iter_dequeue); + read_unlock(&vcc_sklist_lock); + local_irq_restore(flags); + get_statistics(lanai); +#endif /* !DEBUG_RW */ mod_timer(&lanai->timer, jiffies + LANAI_POLL_PERIOD); -#endif /* DEBUG_RW */ } static inline void lanai_timed_poll_start(struct lanai_dev *lanai) @@ -1914,7 +1815,7 @@ static inline void lanai_timed_poll_start(struct lanai_dev *lanai) static inline void lanai_timed_poll_stop(struct lanai_dev *lanai) { - del_timer(&lanai->timer); + del_timer_sync(&lanai->timer); } /* -------------------- INTERRUPT SERVICE: */ @@ -2265,13 +2166,13 @@ static int __init lanai_dev_open(struct atm_dev *atmdev) #endif lanai->cbrvcc = NULL; memset(&lanai->stats, 0, sizeof lanai->stats); - spin_lock_init(&lanai->txlock); + spin_lock_init(&lanai->endtxlock); spin_lock_init(&lanai->servicelock); atmdev->ci_range.vpi_bits = 0; atmdev->ci_range.vci_bits = 0; while (1 << atmdev->ci_range.vci_bits < lanai->num_vci) atmdev->ci_range.vci_bits++; - atmdev->link_rate = ((25600000 / 8 - 8000) / 54); + atmdev->link_rate = ATM_25_PCR; /* 3.2: PCI initialization */ if ((result = lanai_pci_start(lanai)) != 0) @@ -2342,6 +2243,7 @@ static int __init lanai_dev_open(struct atm_dev *atmdev) goto error_vcctable; } MOD_INC_USE_COUNT; /* At this point we can't fail */ + mb(); /* Make sure that all that made it */ intr_enable(lanai, INT_ALL & ~(INT_PING | INT_WAKE)); /* 3.11: initialize loop mode (i.e. turn looping off) */ lanai->conf1 = (lanai->conf1 & ~CONFIG1_MASK_LOOPMODE) | @@ -2466,16 +2368,11 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci) atmvcc->vpi = vpi; atmvcc->vci = vci; set_bit(ATM_VF_ADDR, &atmvcc->flags); - lvcc = lanai->vccs[vci]; if (atmvcc->qos.aal != ATM_AAL0 && atmvcc->qos.aal != ATM_AAL5) return -EINVAL; -#if 0 - DPRINTK(DEV_LABEL "(itf %d): open %d.%d flags=0x%lX\n", - lanai->number, (int) vpi, vci, (unsigned long) atmvcc->flags); -#else DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n", lanai->number, (int) vpi, vci); -#endif + lvcc = lanai->vccs[vci]; if (lvcc == NULL) { lvcc = new_lanai_vcc(); if (unlikely(lvcc == NULL)) @@ -2517,6 +2414,11 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci) } } host_vcc_bind(lanai, lvcc, vci); + /* + * Make sure everything made it to RAM before we tell the card about + * the VCC + */ + wmb(); if (atmvcc == lvcc->rx.atmvcc) host_vcc_start_rx(lvcc); if (atmvcc == lvcc->tx.atmvcc) { @@ -2549,9 +2451,6 @@ static int lanai_ioctl(struct atm_dev *atmdev, unsigned int cmd, void *arg) run_service(lanai); spin_unlock_irqrestore(&lanai->servicelock, flags); return 0; } - case 2200001: - vcc_tx_dequeue_all(lanai); - return 0; case 2200002: get_statistics(lanai); return 0; @@ -2644,18 +2543,18 @@ static int lanai_send(struct atm_vcc *atmvcc, struct sk_buff *skb) ATM_SKB(skb)->vcc = atmvcc; switch (atmvcc->qos.aal) { case ATM_AAL5: - spin_lock_irqsave(&lanai->txlock, flags); + read_lock_irqsave(&vcc_sklist_lock, flags); vcc_tx_aal5(lanai, lvcc, skb); - spin_unlock_irqrestore(&lanai->txlock, flags); + read_unlock_irqrestore(&vcc_sklist_lock, flags); return 0; case ATM_AAL0: if (unlikely(skb->len != ATM_CELL_SIZE-1)) goto einval; /* NOTE - this next line is technically invalid - we haven't unshared skb */ cpu_to_be32s((u32 *) skb->data); - spin_lock_irqsave(&lanai->txlock, flags); + read_lock_irqsave(&vcc_sklist_lock, flags); vcc_tx_aal0(lanai, lvcc, skb); - spin_unlock_irqrestore(&lanai->txlock, flags); + read_unlock_irqrestore(&vcc_sklist_lock, flags); return 0; } DPRINTK("lanai_send: bad aal=%d on vci=%d\n", (int) atmvcc->qos.aal, @@ -2725,10 +2624,6 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) "master_parity=%u\n", lanai->stats.pcierr_s_target_abort, lanai->stats.pcierr_master_parity); if (left-- == 0) - return sprintf(page, "service list errors: no_vcc_rx=%u, " - "no_vcc_tx=%u,\n", lanai->stats.service_novcc_rx, - lanai->stats.service_novcc_tx); - if (left-- == 0) return sprintf(page, " no_tx=%u, " "no_rx=%u, bad_rx_aal=%u\n", lanai->stats.service_norx, lanai->stats.service_notx, @@ -2737,7 +2632,7 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) return sprintf(page, "resets: dma=%u, card=%u\n", lanai->stats.dma_reenable, lanai->stats.card_reset); /* At this point, "left" should be the VCI we're looking for */ - vcclist_read_lock(); + read_lock(&vcc_sklist_lock); for (; ; left++) { if (left >= NUM_VCI) { left = 0; @@ -2773,7 +2668,7 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) page[left++] = '\n'; page[left] = '\0'; out: - vcclist_read_unlock(); + read_unlock(&vcc_sklist_lock); return left; } #endif /* CONFIG_PROC_FS */ diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index df5f96439afa..74fd4100332b 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -604,7 +604,7 @@ out1: pnp_device_detach(idev); #endif out: - kfree(dev); + free_netdev(dev); return err; } diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 4e3eabe1e5ea..572de917454d 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1468,7 +1468,7 @@ free_ring: free_region: if (vp->must_free_region) release_region(ioaddr, vci->io_size); - kfree (dev); + free_netdev(dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); out: return retval; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index a49241c1ae23..fc3c04c6c7bc 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1768,7 +1768,7 @@ err_out_mwi: err_out_disable: pci_disable_device(pdev); err_out_free: - kfree(dev); + free_netdev(dev); return rc; } diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 46777c8dcf18..1963e60de0b2 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -32,14 +32,13 @@ */ #include <linux/config.h> #include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/trdevice.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/netlink.h> #include <linux/divert.h> -#define NEXT_DEV NULL - - /* A unified ethernet device probe. This is the easiest way to have every ethernet adaptor have the name "eth[0123...]". */ @@ -98,6 +97,15 @@ extern int macsonic_probe(struct net_device *dev); extern int mac8390_probe(struct net_device *dev); extern int mac89x0_probe(struct net_device *dev); extern int mc32_probe(struct net_device *dev); +#ifdef CONFIG_SDLA +extern struct net_device *sdla_init(void); +#endif +#ifdef CONFIG_COPS +extern struct net_device *cops_probe(int unit); +#endif +#ifdef CONFIG_LTPC +extern struct net_device *ltpc_probe(void); +#endif /* Detachable devices ("pocket adaptors") */ extern int de620_probe(struct net_device *); @@ -106,7 +114,7 @@ extern int de620_probe(struct net_device *); extern int iph5526_probe(struct net_device *dev); /* SBNI adapters */ -extern int sbni_probe(struct net_device *); +extern int sbni_probe(void); struct devprobe { @@ -352,124 +360,43 @@ static struct devprobe mips_probes[] __initdata = { * per bus interface. This drives the legacy devices only for now. */ -static int __init ethif_probe(struct net_device *dev) +static int __init ethif_probe(void) { - unsigned long base_addr = dev->base_addr; + struct net_device *dev; + int err = -ENODEV; + + dev = alloc_etherdev(0); + if (!dev) + return -ENOMEM; + + netdev_boot_setup_check(dev); /* * Backwards compatibility - historically an I/O base of 1 was * used to indicate not to probe for this ethN interface */ - if (base_addr == 1) - return 1; /* ENXIO */ + if (dev->base_addr == 1) { + free_netdev(dev); + return -ENXIO; + } /* * The arch specific probes are 1st so that any on-board ethernet * will be probed before other ISA/EISA/MCA/PCI bus cards. */ - if (probe_list(dev, m68k_probes) == 0) - return 0; - if (probe_list(dev, mips_probes) == 0) - return 0; - if (probe_list(dev, eisa_probes) == 0) - return 0; - if (probe_list(dev, mca_probes) == 0) - return 0; - if (probe_list(dev, isa_probes) == 0) - return 0; - if (probe_list(dev, parport_probes) == 0) - return 0; - return -ENODEV; -} - -#ifdef CONFIG_SDLA -extern int sdla_init(struct net_device *); -static struct net_device sdla0_dev = { - .name = "sdla0", - .next = NEXT_DEV, - .init = sdla_init, -}; -#undef NEXT_DEV -#define NEXT_DEV (&sdla0_dev) -#endif - -#if defined(CONFIG_LTPC) -extern int ltpc_probe(struct net_device *); -static struct net_device dev_ltpc = { - .name = "lt0", - .next = NEXT_DEV, - .init = ltpc_probe -}; -#undef NEXT_DEV -#define NEXT_DEV (&dev_ltpc) -#endif /* LTPC */ - -#if defined(CONFIG_COPS) -extern int cops_probe(struct net_device *); -static struct net_device cops2_dev = { - .name = "lt2", - .next = NEXT_DEV, - .init = cops_probe, -}; -static struct net_device cops1_dev = { - .name = "lt1", - .next = &cops2_dev, - .init = cops_probe, -}; -static struct net_device cops0_dev = { - .name = "lt0", - .next = &cops1_dev, - .init = cops_probe, -}; -#undef NEXT_DEV -#define NEXT_DEV (&cops0_dev) -#endif /* COPS */ - -static struct net_device eth7_dev = { - .name = "eth%d", - .next = NEXT_DEV, - .init = ethif_probe, -}; -static struct net_device eth6_dev = { - .name = "eth%d", - .next = ð7_dev, - .init = ethif_probe, -}; -static struct net_device eth5_dev = { - .name = "eth%d", - .next = ð6_dev, - .init = ethif_probe, -}; -static struct net_device eth4_dev = { - .name = "eth%d", - .next = ð5_dev, - .init = ethif_probe, -}; -static struct net_device eth3_dev = { - .name = "eth%d", - .next = ð4_dev, - .init = ethif_probe, -}; -static struct net_device eth2_dev = { - .name = "eth%d", - .next = ð3_dev, - .init = ethif_probe, -}; -static struct net_device eth1_dev = { - .name = "eth%d", - .next = ð2_dev, - .init = ethif_probe, -}; -static struct net_device eth0_dev = { - .name = "eth%d", - .next = ð1_dev, - .init = ethif_probe, -}; - -#undef NEXT_DEV -#define NEXT_DEV (ð0_dev) - + if (probe_list(dev, m68k_probes) == 0 || + probe_list(dev, mips_probes) == 0 || + probe_list(dev, eisa_probes) == 0 || + probe_list(dev, mca_probes) == 0 || + probe_list(dev, isa_probes) == 0 || + probe_list(dev, parport_probes) == 0) + err = register_netdev(dev); + + if (err) + free_netdev(dev); + return err; +} #ifdef CONFIG_TR /* Token-ring device probe */ @@ -478,129 +405,82 @@ extern int sk_isa_probe(struct net_device *); extern int proteon_probe(struct net_device *); extern int smctr_probe(struct net_device *); -static int -trif_probe(struct net_device *dev) +static __init int trif_probe(void) { - if (1 + struct net_device *dev; + int err = -ENODEV; + + dev = alloc_trdev(0); + if (!dev) + return -ENOMEM; + + netdev_boot_setup_check(dev); + if ( #ifdef CONFIG_IBMTR - && ibmtr_probe(dev) + ibmtr_probe(dev) == 0 || #endif #ifdef CONFIG_SKISA - && sk_isa_probe(dev) + sk_isa_probe(dev) == 0 || #endif #ifdef CONFIG_PROTEON - && proteon_probe(dev) + proteon_probe(dev) == 0 || #endif #ifdef CONFIG_SMCTR - && smctr_probe(dev) + smctr_probe(dev) == 0 || #endif - && 1 ) { - return 1; /* -ENODEV or -EAGAIN would be more accurate. */ - } - return 0; -} -static struct net_device tr7_dev = { - .name = "tr%d", - .next = NEXT_DEV, - .init = trif_probe, -}; -static struct net_device tr6_dev = { - .name = "tr%d", - .next = &tr7_dev, - .init = trif_probe, -}; -static struct net_device tr5_dev = { - .name = "tr%d", - .next = &tr6_dev, - .init = trif_probe, -}; -static struct net_device tr4_dev = { - .name = "tr%d", - .next = &tr5_dev, - .init = trif_probe, -}; -static struct net_device tr3_dev = { - .name = "tr%d", - .next = &tr4_dev, - .init = trif_probe, -}; -static struct net_device tr2_dev = { - .name = "tr%d", - .next = &tr3_dev, - .init = trif_probe, -}; -static struct net_device tr1_dev = { - .name = "tr%d", - .next = &tr2_dev, - .init = trif_probe, -}; -static struct net_device tr0_dev = { - .name = "tr%d", - .next = &tr1_dev, - .init = trif_probe, -}; -#undef NEXT_DEV -#define NEXT_DEV (&tr0_dev) + 0 ) + err = register_netdev(dev); + + if (err) + free_netdev(dev); + return err; -#endif - -#ifdef CONFIG_SBNI -static struct net_device sbni7_dev = { - .name = "sbni7", - .next = NEXT_DEV, - .init = sbni_probe, -}; -static struct net_device sbni6_dev = { - .name = "sbni6", - .next = &sbni7_dev, - .init = sbni_probe, -}; -static struct net_device sbni5_dev = { - .name = "sbni5", - .next = &sbni6_dev, - .init = sbni_probe, -}; -static struct net_device sbni4_dev = { - .name = "sbni4", - .next = &sbni5_dev, - .init = sbni_probe, -}; -static struct net_device sbni3_dev = { - .name = "sbni3", - .next = &sbni4_dev, - .init = sbni_probe, -}; -static struct net_device sbni2_dev = { - .name = "sbni2", - .next = &sbni3_dev, - .init = sbni_probe, -}; -static struct net_device sbni1_dev = { - .name = "sbni1", - .next = &sbni2_dev, - .init = sbni_probe, -}; -static struct net_device sbni0_dev = { - .name = "sbni0", - .next = &sbni1_dev, - .init = sbni_probe, -}; +} +#endif -#undef NEXT_DEV -#define NEXT_DEV (&sbni0_dev) -#endif /* * The loopback device is global so it can be directly referenced * by the network code. Also, it must be first on device list. */ +extern int loopback_init(void); -extern int loopback_init(struct net_device *dev); -struct net_device loopback_dev = { - .name = "lo", - .next = NEXT_DEV, - .init = loopback_init -}; +/* Statically configured drivers -- order matters here. */ +void __init probe_old_netdevs(void) +{ + int num; + + if (loopback_init()) { + printk(KERN_ERR "Network loopback device setup failed\n"); + } + + +#ifdef CONFIG_SBNI + for (num = 0; num < 8; ++num) + if (sbni_probe()) + break; +#endif +#ifdef CONFIG_TR + for (num = 0; num < 8; ++num) + if (trif_probe()) + break; +#endif + for (num = 0; num < 8; ++num) + if (ethif_probe()) + break; +#ifdef CONFIG_COPS + cops_probe(0); + cops_probe(1); + cops_probe(2); +#endif +#ifdef CONFIG_LTPC + ltpc_probe(); +#endif +#ifdef CONFIG_SDLA + sdla_init(); +#endif + +} /* * The @dev_base list is protected by @dev_base_lock and the rtln @@ -621,6 +501,6 @@ struct net_device loopback_dev = { * unregister_netdevice(), which must be called with the rtnl * semaphore held. */ -struct net_device *dev_base = &loopback_dev; +struct net_device *dev_base; rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index d6a4fdcec957..3350a70c2103 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -685,7 +685,7 @@ int __devinit acenic_probe (ACE_PROBE_ARG) } if (pci_enable_device(pdev)) { - kfree(dev); + free_netdev(dev); continue; } @@ -733,7 +733,7 @@ int __devinit acenic_probe (ACE_PROBE_ARG) if (register_netdev(dev)) { printk(KERN_ERR "acenic: device registration failed\n"); - kfree(dev); + free_netdev(dev); continue; } @@ -793,7 +793,7 @@ int __devinit acenic_probe (ACE_PROBE_ARG) printk(KERN_ERR "%s: Driver compiled without Tigon I" " support - NIC disabled\n", dev->name); ace_init_cleanup(dev); - kfree(dev); + free_netdev(dev); continue; } #endif @@ -803,7 +803,7 @@ int __devinit acenic_probe (ACE_PROBE_ARG) * ace_allocate_descriptors() calls * ace_init_cleanup() on error. */ - kfree(dev); + free_netdev(dev); continue; } @@ -820,7 +820,7 @@ int __devinit acenic_probe (ACE_PROBE_ARG) /* * ace_init() calls ace_init_cleanup() on error. */ - kfree(dev); + free_netdev(dev); continue; } diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 19464a83fdfb..bc9e1bfc7220 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1927,7 +1927,7 @@ err_iounmap: iounmap((void *) lp->mmio); err_free_dev: - kfree(dev); + free_netdev(dev); err_free_reg: pci_release_regions(pdev); diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index cb8dac24f286..579cf0d2ee5b 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -92,12 +92,8 @@ static int board_type = DAYNA; /* Module exported */ static int board_type = TANGENT; #endif -#ifdef MODULE static int io = 0x240; /* Default IO for Dayna */ static int irq = 5; /* Default IRQ */ -#else -static int io; /* Default IO for Dayna */ -#endif /* * COPS Autoprobe information. @@ -146,7 +142,7 @@ static int io; /* Default IO for Dayna */ * Zero terminated list of IO ports to probe. */ -static unsigned int cops_portlist[] = { +static unsigned int ports[] = { 0x240, 0x340, 0x200, 0x210, 0x220, 0x230, 0x260, 0x2A0, 0x300, 0x310, 0x320, 0x330, 0x350, 0x360, 0 @@ -184,7 +180,6 @@ struct cops_local }; /* Index to functions, as function prototypes. */ -extern int cops_probe (struct net_device *dev); static int cops_probe1 (struct net_device *dev, int ioaddr); static int cops_irq (int ioaddr, int board); @@ -208,6 +203,12 @@ static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static int cops_close (struct net_device *dev); static struct net_device_stats *cops_get_stats (struct net_device *dev); +static void cleanup_card(struct net_device *dev) +{ + if (dev->irq) + free_irq(dev->irq, dev); + release_region(dev->base_addr, COPS_IO_EXTENT); +} /* * Check for a network adaptor of this type, and return '0' iff one exists. @@ -215,31 +216,54 @@ static struct net_device_stats *cops_get_stats (struct net_device *dev); * If dev->base_addr in [1..0x1ff], always return failure. * otherwise go with what we pass in. */ -int __init cops_probe(struct net_device *dev) +struct net_device * __init cops_probe(int unit) { - int i; - int base_addr = dev->base_addr; + struct net_device *dev; + unsigned *port; + int base_addr; + int err = 0; + + dev = alloc_netdev(sizeof(struct cops_local), "lt%d", ltalk_setup); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "lt%d", unit); + netdev_boot_setup_check(dev); + irq = dev->irq; + base_addr = dev->base_addr; + } else { + base_addr = dev->base_addr = io; + } SET_MODULE_OWNER(dev); - if(base_addr == 0 && io) - base_addr=io; - - if(base_addr > 0x1ff) /* Check a single specified location. */ - return cops_probe1(dev, base_addr); - else if(base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - /* FIXME Does this really work for cards which generate irq? - * It's definitely N.G. for polled Tangent. sh - * Dayna cards don't autoprobe well at all, but if your card is - * at IRQ 5 & IO 0x240 we find it every time. ;) JS - */ - for(i=0; cops_portlist[i]; i++) - if(cops_probe1(dev, cops_portlist[i]) == 0) - return 0; - - return -ENODEV; + if (base_addr > 0x1ff) { /* Check a single specified location. */ + err = cops_probe1(dev, base_addr); + } else if (base_addr != 0) { /* Don't probe at all. */ + err = -ENXIO; + } else { + /* FIXME Does this really work for cards which generate irq? + * It's definitely N.G. for polled Tangent. sh + * Dayna cards don't autoprobe well at all, but if your card is + * at IRQ 5 & IO 0x240 we find it every time. ;) JS + */ + for (port = ports; *port && cops_probe1(dev, *port) < 0; port++) + ; + if (!*port) + err = -ENODEV; + } + if (err) + goto out; + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + cleanup_card(dev); +out: + kfree(dev); + return ERR_PTR(err); } /* @@ -268,16 +292,15 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) * interrupts are typically not reported by the boards, and we must * used AutoIRQ to find them. */ + dev->irq = irq; switch (dev->irq) { case 0: /* COPS AutoIRQ routine */ dev->irq = cops_irq(ioaddr, board); - if(!dev->irq) { - retval = -EINVAL; /* No IRQ found on this port */ - goto err_out; - } - + if (dev->irq) + break; + /* No IRQ found on this port, fallthrough */ case 1: retval = -EINVAL; goto err_out; @@ -302,22 +325,13 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) } /* Reserve any actual interrupt. */ - if(dev->irq) { + if (dev->irq) { retval = request_irq(dev->irq, &cops_interrupt, 0, dev->name, dev); if (retval) goto err_out; } - dev->base_addr = ioaddr; - - /* Initialize the private device structure. */ - dev->priv = kmalloc(sizeof(struct cops_local), GFP_KERNEL); - if(dev->priv == NULL) { - if (dev->irq) - free_irq(dev->irq, dev); - retval = -ENOMEM; - goto err_out; - } + dev->base_addr = ioaddr; lp = (struct cops_local *)dev->priv; memset(lp, 0, sizeof(struct cops_local)); @@ -326,9 +340,6 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr) /* Copy local board variable to lp struct. */ lp->board = board; - /* Fill in the fields of the device structure with LocalTalk values. */ - ltalk_setup(dev); - dev->hard_start_xmit = cops_send_packet; dev->tx_timeout = cops_timeout; dev->watchdog_timeo = HZ * 2; @@ -1013,7 +1024,7 @@ static struct net_device_stats *cops_get_stats(struct net_device *dev) } #ifdef MODULE -static struct net_device cops0_dev = { .init = cops_probe }; +static struct net_device *cops_dev; MODULE_LICENSE("GPL"); MODULE_PARM(io, "i"); @@ -1022,33 +1033,20 @@ MODULE_PARM(board_type, "i"); int init_module(void) { - int result, err; - - if(io == 0) + if (io == 0) printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n", cardname); - - /* Copy the parameters from insmod into the device structure. */ - cops0_dev.base_addr = io; - cops0_dev.irq = irq; - - err=dev_alloc_name(&cops0_dev, "lt%d"); - if(err < 0) - return err; - - if((result = register_netdev(&cops0_dev)) != 0) - return result; - + cops_dev = cops_probe(-1); + if (IS_ERR(cops_dev)) + return PTR_ERR(cops_dev); return 0; } void cleanup_module(void) { - unregister_netdev(&cops0_dev); - kfree(cops0_dev.priv); - if(cops0_dev.irq) - free_irq(cops0_dev.irq, &cops0_dev); - release_region(cops0_dev.base_addr, COPS_IO_EXTENT); + unregister_netdev(cops_dev); + cleanup_card(cops_dev); + free_netdev(cops_dev); } #endif /* MODULE */ diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index ddbd4f765b12..1b10bc14867c 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -879,34 +879,6 @@ static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, return 0; } -static int ltpc_init(struct net_device *dev) -{ - /* Initialize the device structure. */ - - /* Fill in the fields of the device structure with ethernet-generic values. */ - ltalk_setup(dev); - dev->hard_start_xmit = ltpc_xmit; - dev->hard_header = ltpc_hard_header; - - dev->priv = kmalloc(sizeof(struct ltpc_private), GFP_KERNEL); - if(!dev->priv) - { - printk(KERN_INFO "%s: could not allocate statistics buffer\n", dev->name); - return -ENOMEM; - } - - memset(dev->priv, 0, sizeof(struct ltpc_private)); - dev->get_stats = ltpc_get_stats; - - /* add the ltpc-specific things */ - dev->do_ioctl = <pc_ioctl; - - dev->set_multicast_list = &set_multicast_list; - dev->mc_list = NULL; - - return 0; -} - static int ltpc_poll_counter; static void ltpc_poll(unsigned long l) @@ -983,35 +955,40 @@ static struct net_device_stats *ltpc_get_stats(struct net_device *dev) /* initialization stuff */ -static int __init ltpc_probe_dma(int base) +static int __init ltpc_probe_dma(int base, int dma) { - int dma = 0; + int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3; unsigned long timeout; unsigned long f; - if (!request_dma(1,"ltpc")) { - f=claim_dma_lock(); - disable_dma(1); - clear_dma_ff(1); - set_dma_mode(1,DMA_MODE_WRITE); - set_dma_addr(1,virt_to_bus(ltdmabuf)); - set_dma_count(1,sizeof(struct lt_mem)); - enable_dma(1); - release_dma_lock(f); - dma|=1; + if (want & 1) { + if (request_dma(1,"ltpc")) { + want &= ~1; + } else { + f=claim_dma_lock(); + disable_dma(1); + clear_dma_ff(1); + set_dma_mode(1,DMA_MODE_WRITE); + set_dma_addr(1,virt_to_bus(ltdmabuf)); + set_dma_count(1,sizeof(struct lt_mem)); + enable_dma(1); + release_dma_lock(f); + } } - if (!request_dma(3,"ltpc")) { - f=claim_dma_lock(); - disable_dma(3); - clear_dma_ff(3); - set_dma_mode(3,DMA_MODE_WRITE); - set_dma_addr(3,virt_to_bus(ltdmabuf)); - set_dma_count(3,sizeof(struct lt_mem)); - enable_dma(3); - release_dma_lock(f); - dma|=2; + if (want & 2) { + if (request_dma(3,"ltpc")) { + want &= ~2; + } else { + f=claim_dma_lock(); + disable_dma(3); + clear_dma_ff(3); + set_dma_mode(3,DMA_MODE_WRITE); + set_dma_addr(3,virt_to_bus(ltdmabuf)); + set_dma_count(3,sizeof(struct lt_mem)); + enable_dma(3); + release_dma_lock(f); + } } - /* set up request */ /* FIXME -- do timings better! */ @@ -1037,65 +1014,62 @@ static int __init ltpc_probe_dma(int base) /* release the other dma channel (if we opened both of them) */ - if ( (dma&0x2) && (get_dma_residue(3)==sizeof(struct lt_mem)) ){ - dma&=1; + if ((want & 2) && (get_dma_residue(3)==sizeof(struct lt_mem))) { + want &= ~2; free_dma(3); } - - if ( (dma&0x1) && (get_dma_residue(1)==sizeof(struct lt_mem)) ){ - dma&=0x2; + + if ((want & 1) && (get_dma_residue(1)==sizeof(struct lt_mem))) { + want &= ~1; free_dma(1); } - /* fix up dma number */ - dma|=1; + if (!want) + return 0; - return dma; + return (want & 2) ? 3 : 1; } -int __init ltpc_probe(struct net_device *dev) +struct net_device * __init ltpc_probe(void) { - int err; + struct net_device *dev; + int err = -ENOMEM; int x=0,y=0; int autoirq; unsigned long f; - int portfound=0; unsigned long timeout; + dev = alloc_netdev(sizeof(struct ltpc_private), "lt%d", ltalk_setup); + if (!dev) + goto out; + SET_MODULE_OWNER(dev); /* probe for the I/O port address */ + if (io != 0x240 && request_region(0x220,8,"ltpc")) { x = inb_p(0x220+6); if ( (x!=0xff) && (x>=0xf0) ) { io = 0x220; - portfound=1; - } - else { - release_region(0x220,8); + goto got_port; } + release_region(0x220,8); } - if (io != 0x220 && request_region(0x240,8,"ltpc")) { y = inb_p(0x240+6); if ( (y!=0xff) && (y>=0xf0) ){ io = 0x240; - portfound=1; - } - else { - release_region(0x240,8); + goto got_port; } + release_region(0x240,8); } - if(io && !portfound && request_region(io,8,"ltpc")){ - portfound = 1; - } - if(!portfound) { - /* give up in despair */ - printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y); - return -1; - } + /* give up in despair */ + printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y); + err = -ENODEV; + goto out1; + got_port: /* probe for the IRQ line */ if (irq < 2) { unsigned long irq_mask; @@ -1111,22 +1085,21 @@ int __init ltpc_probe(struct net_device *dev) if (autoirq == 0) { printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io); - } - else { + } else { irq = autoirq; } } /* allocate a DMA buffer */ ltdmabuf = (unsigned char *) dma_mem_alloc(1000); - - if (ltdmabuf) ltdmacbuf = <dmabuf[800]; - if (!ltdmabuf) { printk(KERN_ERR "ltpc: mem alloc failed\n"); - return -1; + err = -ENOMEM; + goto out2; } + ltdmacbuf = <dmabuf[800]; + if(debug & DEBUG_VERBOSE) { printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf); } @@ -1154,25 +1127,29 @@ int __init ltpc_probe(struct net_device *dev) already been specified */ /* well, 0 is a legal DMA channel, but the LTPC card doesn't use it... */ - if (dma == 0) { - dma = ltpc_probe_dma(io); - if (!dma) { /* no dma channel */ - printk(KERN_ERR "No DMA channel found on ltpc card.\n"); - return -1; - } + dma = ltpc_probe_dma(io, dma); + if (!dma) { /* no dma channel */ + printk(KERN_ERR "No DMA channel found on ltpc card.\n"); + err = -ENODEV; + goto out3; } /* print out friendly message */ - if(irq) printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma); else printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d. Using polled mode.\n",io,dma); - /* seems more logical to do this *after* probing the card... */ - err = ltpc_init(dev); - if (err) return err; + /* Fill in the fields of the device structure with ethernet-generic values. */ + dev->hard_start_xmit = ltpc_xmit; + dev->hard_header = ltpc_hard_header; + dev->get_stats = ltpc_get_stats; + /* add the ltpc-specific things */ + dev->do_ioctl = <pc_ioctl; + + dev->set_multicast_list = &set_multicast_list; + dev->mc_list = NULL; dev->base_addr = io; dev->irq = irq; dev->dma = dma; @@ -1212,6 +1189,7 @@ int __init ltpc_probe(struct net_device *dev) } else { if( irq ) printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n"); + dev->irq = 0; /* polled mode -- 20 times per second */ /* this is really, really slow... should it poll more often? */ init_timer(<pc_timer); @@ -1221,8 +1199,23 @@ int __init ltpc_probe(struct net_device *dev) ltpc_timer.expires = jiffies + HZ/20; add_timer(<pc_timer); } + err = register_netdev(dev); + if (err) + goto out4; return 0; +out4: + del_timer_sync(<pc_timer); + if (dev->irq) + free_irq(dev->irq, dev); +out3: + free_pages((unsigned long)ltdmabuf, get_order(1000)); +out2: + release_region(io, 8); +out1: + kfree(dev); +out: + return ERR_PTR(err); } #ifndef MODULE @@ -1259,7 +1252,7 @@ static int __init ltpc_setup(char *str) __setup("ltpc=", ltpc_setup); #endif /* MODULE */ -static struct net_device dev_ltpc; +static struct net_device *dev_ltpc; #ifdef MODULE @@ -1272,79 +1265,47 @@ MODULE_PARM(dma, "i"); int __init init_module(void) { - int err, result; - if(io == 0) printk(KERN_NOTICE "ltpc: Autoprobing is not recommended for modules\n"); - /* Find a name for this unit */ - dev_ltpc.init = ltpc_probe; - err=dev_alloc_name(&dev_ltpc,"lt%d"); - - if(err<0) - return err; - - if ((result = register_netdev(&dev_ltpc)) != 0) { - printk(KERN_DEBUG "could not register Localtalk-PC device\n"); - return result; - } else { - if(debug & DEBUG_VERBOSE) printk("0 from register_netdev\n"); - return 0; - } + dev_ltpc = ltpc_probe(); + if (IS_ERR(dev_ltpc)) + return PTR_ERR(dev_ltpc); + return 0; } #endif static void __exit ltpc_cleanup(void) { - unsigned long timeout; + + if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n"); + unregister_netdev(dev_ltpc); ltpc_timer.data = 0; /* signal the poll routine that we're done */ + del_timer_sync(<pc_timer); + if(debug & DEBUG_VERBOSE) printk("freeing irq\n"); - if(dev_ltpc.irq) { - free_irq(dev_ltpc.irq,&dev_ltpc); - dev_ltpc.irq = 0; - } - - if(del_timer(<pc_timer)) - { - /* either the poll was never started, or a poll is in process */ - if(debug & DEBUG_VERBOSE) printk("waiting\n"); - /* if it's in process, wait a bit for it to finish */ - timeout = jiffies+HZ; - add_timer(<pc_timer); - while(del_timer(<pc_timer) && time_after(timeout, jiffies)) - { - add_timer(<pc_timer); - schedule(); - } - } + if (dev_ltpc->irq) + free_irq(dev_ltpc->irq, dev_ltpc); if(debug & DEBUG_VERBOSE) printk("freeing dma\n"); - if(dev_ltpc.dma) { - free_dma(dev_ltpc.dma); - dev_ltpc.dma = 0; - } + if (dev_ltpc->dma) + free_dma(dev_ltpc->dma); if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n"); - if(dev_ltpc.base_addr) { - release_region(dev_ltpc.base_addr,8); - dev_ltpc.base_addr = 0; - } + if (dev_ltpc->base_addr) + release_region(dev_ltpc->base_addr,8); + + free_netdev(dev_ltpc); if(debug & DEBUG_VERBOSE) printk("free_pages\n"); free_pages( (unsigned long) ltdmabuf, get_order(1000)); - ltdmabuf=NULL; - ltdmacbuf=NULL; - - if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n"); - - unregister_netdev(&dev_ltpc); if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n"); } diff --git a/drivers/net/b44.c b/drivers/net/b44.c index b759af47913d..ef10d16fd679 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1834,7 +1834,7 @@ err_out_iounmap: iounmap((void *) bp->regs); err_out_free_dev: - kfree(dev); + free_netdev(dev); err_out_free_res: pci_release_regions(pdev); diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index ed7874f4fe4e..27bc8ed937cf 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1462,7 +1462,7 @@ out2: release_OF_resource(bp->node, 0); out1: pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); - kfree(dev); + free_netdev(dev); } static int bmac_open(struct net_device *dev) diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 00ddd19e0fd2..d28d864cbaa5 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1275,7 +1275,7 @@ dgrs_found_device( SET_MODULE_OWNER(dev); if (register_netdev(dev) != 0) { - kfree(dev); + free_netdev(dev); return -EIO; } @@ -1322,7 +1322,7 @@ dgrs_found_device( ret = -EIO; if (register_netdev(devN)) { - kfree(devN); + free_netdev(devN); goto fail; } privN->chan = i+1; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index d0fba4cb4df4..76f1d66eb6c1 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -319,7 +319,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) err_out_dev: #endif - kfree (dev); + free_netdev (dev); err_out_res: pci_release_regions (pdev); diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 2a14f46f6014..02c2db84f603 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -894,7 +894,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev, err_free_unlock: rtnl_unlock(); - kfree(dev); + free_netdev(dev); return -1; } diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 93fdb1469a0c..00bbf4b7baea 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -565,7 +565,7 @@ err_out_free_res: #endif pci_release_regions(pdev); err_out_free_netdev: - kfree(dev); + free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index de914dfc56f8..ee1e45180f86 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -689,7 +689,7 @@ err_out_free_tx: err_out_free_rx: pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); err_out_free_dev: - kfree(dev); + free_netdev(dev); err_out_unmap: #ifndef USE_IO_OPS iounmap((void *)ioaddr); diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 36e7074c2bd8..ab87588a7ff3 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -785,7 +785,7 @@ err_out_unmap_tx: pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring, hmp->tx_ring_dma); err_out_cleardev: - kfree (dev); + free_netdev (dev); err_out_iounmap: iounmap((char *)ioaddr); err_out_release: diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index c3b4e5f1353d..d93767489ff0 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1512,7 +1512,7 @@ out_stop: out_res: pci_release_regions(pdev); out_free: - kfree(dev); + free_netdev(dev); return err; } diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index b3045c467da8..6f8c223bf68e 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -1543,7 +1543,7 @@ lan_init_chip(struct parisc_device *dev) retval = register_netdev(netdevice); if (retval) { printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); - kfree(netdevice); + free_netdev(netdevice); return -ENODEV; }; if (dev->id.sversion == 0x72) { diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 7382804af6b0..5dd2b3393edc 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -55,6 +55,7 @@ #include <linux/ip.h> #include <linux/tcp.h> + #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) /* KISS: just allocate small chunks and copy bits. @@ -152,10 +153,12 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) } dev->last_rx = jiffies; - stats->rx_bytes+=skb->len; - stats->tx_bytes+=skb->len; - stats->rx_packets++; - stats->tx_packets++; + if (likely(stats)) { + stats->rx_bytes+=skb->len; + stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->tx_packets++; + } netif_rx(skb); @@ -167,36 +170,35 @@ static struct net_device_stats *get_stats(struct net_device *dev) return (struct net_device_stats *)dev->priv; } -/* Initialize the rest of the LOOPBACK device. */ -int __init loopback_init(struct net_device *dev) -{ - dev->mtu = (16 * 1024) + 20 + 20 + 12; - dev->hard_start_xmit = loopback_xmit; - dev->hard_header = eth_header; - dev->hard_header_cache = eth_header_cache; - dev->header_cache_update= eth_header_cache_update; - dev->hard_header_len = ETH_HLEN; /* 14 */ - dev->addr_len = ETH_ALEN; /* 6 */ - dev->tx_queue_len = 0; - dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ - dev->rebuild_header = eth_rebuild_header; - dev->flags = IFF_LOOPBACK; - dev->features = NETIF_F_SG|NETIF_F_FRAGLIST|NETIF_F_NO_CSUM|NETIF_F_HIGHDMA; - - /* Current netfilter will die with oom linearizing large skbs, - * however this will be cured before 2.5.x is done. - */ - dev->features |= NETIF_F_TSO; - - dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_device_stats)); - dev->get_stats = get_stats; +struct net_device loopback_dev = { + .name = "lo", + .mtu = (16 * 1024) + 20 + 20 + 12, + .hard_start_xmit = loopback_xmit, + .hard_header = eth_header, + .hard_header_cache = eth_header_cache, + .header_cache_update = eth_header_cache_update, + .hard_header_len = ETH_HLEN, /* 14 */ + .addr_len = ETH_ALEN, /* 6 */ + .tx_queue_len = 0, + .type = ARPHRD_LOOPBACK, /* 0x0001*/ + .rebuild_header = eth_rebuild_header, + .flags = IFF_LOOPBACK, + .features = NETIF_F_SG|NETIF_F_FRAGLIST + |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA|NETIF_F_TSO, +}; - /* - * Fill in the generic fields of the device structure. - */ - - return(0); +/* Setup and register the of the LOOPBACK device. */ +int __init loopback_init(void) +{ + struct net_device_stats *stats; + + /* Can survive without statistics */ + stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (stats) { + memset(stats, 0, sizeof(struct net_device_stats)); + loopback_dev.priv = stats; + loopback_dev.get_stats = &get_stats; + } + + return register_netdev(&loopback_dev); }; diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index fe1e255a576c..3e687d9cbd41 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1324,7 +1324,7 @@ static int __init lp486e_init_module(void) { dev->base_addr = io; dev->init = lp486e_probe; if (register_netdev(dev) != 0) { - kfree(dev); + free_netdev(dev); return -EIO; } dev_lp486e = dev; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index b95d3030e465..14fbbef63fb6 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -766,7 +766,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, i = pci_request_regions(pdev, dev->name); if (i) { - kfree(dev); + free_netdev(dev); return i; } @@ -774,7 +774,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, void *mmio = ioremap (ioaddr, iosize); if (!mmio) { pci_release_regions(pdev); - kfree(dev); + free_netdev(dev); return -ENOMEM; } ioaddr = (unsigned long) mmio; @@ -838,7 +838,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (i) { pci_release_regions(pdev); unregister_netdev(dev); - kfree(dev); + free_netdev(dev); pci_set_drvdata(pdev, NULL); return i; } diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index ad6281ef7a83..2d519b696533 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -529,6 +529,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, struct net_device *dev; struct pcnet32_access *a = NULL; u8 promaddr[6]; + int ret = -ENODEV; /* reset the chip */ pcnet32_wio_reset(ioaddr); @@ -540,19 +541,15 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, pcnet32_dwio_reset(ioaddr); if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; - } else { - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENODEV; - } + } else + goto err_release_region; } chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); if (pcnet32_debug > 2) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) { - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENODEV; - } + if ((chip_version & 0xfff) != 0x003) + goto err_release_region; /* initialize variables */ fdx = mii = fset = dxsuflo = ltint = 0; @@ -614,8 +611,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, default: printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", chip_version); - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENODEV; + goto err_release_region; } /* @@ -635,8 +631,8 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, dev = alloc_etherdev(0); if(!dev) { - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENOMEM; + ret = -ENOMEM; + goto err_release_region; } SET_NETDEV_DEV(dev, &pdev->dev); @@ -708,8 +704,8 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, dev->base_addr = ioaddr; /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENOMEM; + ret = -ENOMEM; + goto err_free_netdev; } memset(lp, 0, sizeof(*lp)); @@ -741,9 +737,8 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, if (!a) { printk(KERN_ERR PFX "No access methods\n"); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENODEV; + ret = -ENODEV; + goto err_free_consistent; } lp->a = *a; @@ -785,14 +780,12 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, mdelay (1); dev->irq = probe_irq_off (irq_mask); - if (dev->irq) - printk(", probed IRQ %d.\n", dev->irq); - else { + if (!dev->irq) { printk(", failed to detect IRQ line.\n"); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return -ENODEV; + ret = -ENODEV; + goto err_free_consistent; } + printk(", probed IRQ %d.\n", dev->irq); } /* Set the mii phy_id so that we can query the link state */ @@ -821,6 +814,14 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared, printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name); cards_found++; return 0; + +err_free_consistent: + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); +err_free_netdev: + free_netdev(dev); +err_release_region: + release_region(ioaddr, PCNET32_TOTAL_SIZE); + return ret; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a0b4b659aa0e..c11b83e6adeb 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -454,7 +454,7 @@ err_out_disable: pci_disable_device(pdev); err_out: - kfree(dev); + free_netdev(dev); return rc; } @@ -514,7 +514,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) iounmap(ioaddr); pci_release_regions(pdev); pci_disable_device(pdev); - kfree(dev); + free_netdev(dev); return rc; } diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index f5cdead40f14..e7e1a9f2d71a 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -269,7 +269,7 @@ err_out_free_msgbuf: pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf, pDpa->msgbuf_dma); err_out_free_dev: - kfree (dev); + free_netdev (dev); err_out: card_idx--; return error; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index d0153f60a036..5326dee62c74 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -213,9 +213,11 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) error = register_netdev(dev); if (error) - goto out_release_regions; + goto out_free_netdev; return 0; + out_free_netdev: + free_netdev(dev); out_release_regions: release_region(ioaddr[1], 16); out_release_region0: diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 1c79e7b9c34e..9f421480b233 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -470,7 +470,7 @@ SiS190_init_board(struct pci_dev *pdev, struct net_device **dev_out, rc = pci_set_dma_mask(pdev, 0xffffffffULL); if (rc) - goto err_out; + goto err_out_disable; mmio_start = pci_resource_start(pdev, 0); mmio_end = pci_resource_end(pdev, 0); @@ -482,18 +482,18 @@ SiS190_init_board(struct pci_dev *pdev, struct net_device **dev_out, printk(KERN_ERR PFX "region #0 not an MMIO resource, aborting\n"); rc = -ENODEV; - goto err_out; + goto err_out_disable; } // check for weird/broken PCI region reporting if (mmio_len < SiS190_MIN_IO_SIZE) { printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; - goto err_out; + goto err_out_disable; } rc = pci_request_regions(pdev, dev->name); if (rc) - goto err_out; + goto err_out_disable; // enable PCI bus-mastering pci_set_master(pdev); @@ -521,9 +521,10 @@ SiS190_init_board(struct pci_dev *pdev, struct net_device **dev_out, err_out_free_res: pci_release_regions(pdev); -err_out: +err_out_disable: pci_disable_device(pdev); - kfree(dev); +err_out: + free_netdev(dev); return rc; } @@ -603,7 +604,7 @@ SiS190_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) iounmap(ioaddr); pci_release_regions(pdev); pci_disable_device(pdev); - kfree(dev); + free_netdev(dev); return rc; } diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index b5853f1a9fbd..6422eb2a4208 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -503,7 +503,7 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_dev pci_set_drvdata(pci_dev, NULL); pci_release_regions(pci_dev); err_out: - kfree(net_dev); + free_netdev(net_dev); return ret; } diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index e33c7a2a2f7f..c5a085707302 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -132,7 +132,7 @@ int __init ultramca_probe(struct device *gen_dev) struct mca_device *mca_dev = to_mca_device(gen_dev); char slot = mca_dev->slot; unsigned char pos2 = 0xff, pos3 = 0xff, pos4 = 0xff, pos5 = 0xff; - int i; + int i, rc; int adapter = mca_dev->index; int tbase = 0; int tirq = 0; @@ -209,8 +209,9 @@ int __init ultramca_probe(struct device *gen_dev) SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gen_dev); - if((i = register_netdev(dev)) != 0) - return i; + rc = register_netdev(dev); + if (rc) + goto err_free_netdev; printk(KERN_INFO "%s: %s found in slot %d\n", dev->name, smc_mca_adapter_names[adapter], slot + 1); @@ -262,11 +263,15 @@ int __init ultramca_probe(struct device *gen_dev) } } - if (dev->mem_start == 0) /* sanity check, shouldn't happen */ - return -ENODEV; + /* sanity check, shouldn't happen */ + if (dev->mem_start == 0) { + rc = -ENODEV; + goto err_unregister_netdev; + } - if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name)) - return -EBUSY; + rc = request_region(ioaddr, ULTRA_IO_EXTENT, dev->name); + if (rc) + goto err_unregister_netdev; reg4 = inb(ioaddr + 4) & 0x7f; outb(reg4, ioaddr + 4); @@ -296,10 +301,10 @@ int __init ultramca_probe(struct device *gen_dev) /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { + rc = ethdev_init(dev); + if (rc) { printk (", no memory for dev->priv.\n"); - release_region(ioaddr, ULTRA_IO_EXTENT); - return -ENOMEM; + goto err_release_region; } gen_dev->driver_data = dev; @@ -334,6 +339,14 @@ int __init ultramca_probe(struct device *gen_dev) NS8390_init(dev, 0); return 0; + +err_release_region: + release_region(ioaddr, ULTRA_IO_EXTENT); +err_unregister_netdev: + unregister_netdev(dev); +err_free_netdev: + free_netdev(dev); + return rc; } static int ultramca_open(struct net_device *dev) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index dcf1db7ea6ef..c2bddf1f1700 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1070,7 +1070,7 @@ err_out_cleardev: err_out_free_res: pci_release_regions (pdev); err_out_free_netdev: - kfree(dev); + free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 5bd8be316547..aad877c5400b 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -734,7 +734,7 @@ err_out_res: #endif pci_release_regions(pdev); err_out_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index a452e5942b52..a346fd1d4dba 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2416,13 +2416,6 @@ static int gem_nway_reset(struct net_device *dev) return 0; } -static u32 gem_get_link(struct net_device *dev) -{ - struct gem *gp = dev->priv; - - return (gp->lstate == link_up); -} - static u32 gem_get_msglevel(struct net_device *dev) { struct gem *gp = dev->priv; @@ -2441,7 +2434,6 @@ static struct ethtool_ops gem_ethtool_ops = { .get_settings = gem_get_settings, .set_settings = gem_set_settings, .nway_reset = gem_nway_reset, - .get_link = gem_get_link, .get_msglevel = gem_get_msglevel, .set_msglevel = gem_set_msglevel, }; @@ -2630,7 +2622,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " "aborting.\n"); - return err; + goto err_disable_device; } pci_using_dac = 0; } @@ -2641,20 +2633,23 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { printk(KERN_ERR PFX "Cannot find proper PCI device " "base address, aborting.\n"); - return -ENODEV; + err = -ENODEV; + goto err_disable_device; } dev = alloc_etherdev(sizeof(*gp)); if (!dev) { printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_disable_device; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); gp = dev->priv; - if (pci_request_regions(pdev, dev->name)) { + err = pci_request_regions(pdev, dev->name); + if (err) { printk(KERN_ERR PFX "Cannot obtain PCI resources, " "aborting.\n"); goto err_out_free_netdev; @@ -2688,6 +2683,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if (gp->regs == 0UL) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); + err = -EIO; goto err_out_free_res; } @@ -2711,8 +2707,10 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* By default, we start with autoneg */ gp->want_autoneg = 1; - if (gem_check_invariants(gp)) + if (gem_check_invariants(gp)) { + err = -ENODEV; goto err_out_iounmap; + } /* It is guaranteed that the returned buffer will be at least * PAGE_SIZE aligned. @@ -2723,6 +2721,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if (!gp->init_block) { printk(KERN_ERR PFX "Cannot allocate init block, " "aborting.\n"); + err = -ENOMEM; goto err_out_iounmap; } @@ -2735,6 +2734,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if (register_netdev(dev)) { printk(KERN_ERR PFX "Cannot register net device, " "aborting.\n"); + err = -ENOMEM; goto err_out_free_consistent; } @@ -2804,9 +2804,10 @@ err_out_free_res: pci_release_regions(pdev); err_out_free_netdev: - kfree(dev); - - return -ENODEV; + free_netdev(dev); +err_disable_device: + pci_disable_device(pdev); + return err; } diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 8c786ab7b3c5..b91f7d0199bf 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2895,7 +2895,7 @@ err_out_iounmap: sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); err_out_free_netdev: - kfree(dev); + free_netdev(dev); err_out: return err; @@ -3247,7 +3247,7 @@ err_out_clear_quattro: if (qp != NULL) qp->happy_meals[qfe_slot] = NULL; - kfree(dev); + free_netdev(dev); err_out: return err; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index b5d8879c2035..5116b5152e8a 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -949,7 +949,7 @@ out1: i = 4; out: while (i--) - kfree(qe_devs[i]); + free_netdev(qe_devs[i]); return res; } diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c31dc44a6fd2..3ebedccf00b3 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7740,7 +7740,7 @@ err_out_iounmap: iounmap((void *) tp->regs); err_out_free_dev: - kfree(dev); + free_netdev(dev); err_out_free_res: pci_release_regions(pdev); diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 5a45900a816e..c5b6999712fb 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -670,7 +670,7 @@ err_out_uninit: pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); err_out_free_dev: - kfree(dev); + free_netdev(dev); err_out_regions: if (pdev) pci_release_regions(pdev); @@ -695,7 +695,7 @@ static void TLan_Eisa_Cleanup(void) release_region( dev->base_addr, 0x10); unregister_netdev( dev ); TLan_Eisa_Devices = priv->nextDevice; - kfree( dev ); + free_netdev( dev ); tlan_have_eisa--; } } diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index e83372b7adbb..f30b72218b30 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2455,7 +2455,7 @@ error_out_remap: error_out_regions: pci_release_regions(pdev); error_out_dev: - kfree(dev); + free_netdev(dev); error_out: return err; } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index c247af6bf6ad..3059d04aaf0d 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -868,7 +868,7 @@ err_out_free_res: #endif pci_release_regions(pdev); err_out_free_netdev: - kfree (dev); + free_netdev (dev); err_out: return -ENODEV; } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 5aab67436cc7..380bb830d738 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -55,14 +55,13 @@ #include <asm/dma.h> #include <asm/uaccess.h> -static const char devname[] = "dlci"; static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org"; -static struct net_device *open_dev[CONFIG_DLCI_COUNT]; - +static LIST_HEAD(dlci_devs); +static spinlock_t dlci_dev_lock = SPIN_LOCK_UNLOCKED; static char *basename[16]; -int dlci_init(struct net_device *dev); +static void dlci_setup(struct net_device *); /* allow FRAD's to register their name as a valid FRAD */ int register_frad(const char *name) @@ -115,6 +114,7 @@ int unregister_frad(const char *name) return(0); } +EXPORT_SYMBOL(unregister_frad); /* * these encapsulate the RFC 1490 requirements as well as @@ -168,6 +168,14 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) int process, header; dlp = dev->priv; + if (!pskb_may_pull(skb, sizeof(*hdr))) { + printk(KERN_NOTICE "%s: invalid data no header\n", + dev->name); + dlp->stats.rx_errors++; + kfree_skb(skb); + return; + } + hdr = (struct frhdr *) skb->data; process = 0; header = 0; @@ -277,7 +285,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) return(ret); } -int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get) +static int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get) { struct dlci_conf config; struct dlci_local *dlp; @@ -311,7 +319,7 @@ int dlci_config(struct net_device *dev, struct dlci_conf *conf, int get) return(0); } -int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dlci_local *dlp; @@ -401,21 +409,23 @@ static struct net_device_stats *dlci_get_stats(struct net_device *dev) return(&dlp->stats); } -int dlci_add(struct dlci_add *dlci) +static int dlci_add(struct dlci_add *dlci) { - struct net_device *master, *slave; + struct net_device *master, *slave; struct dlci_local *dlp; struct frad_local *flp; int err, i; - char buf[10]; + /* validate slave device */ - slave = __dev_get_by_name(dlci->devname); + slave = dev_get_by_name(dlci->devname); if (!slave) return(-ENODEV); - if (slave->type != ARPHRD_FRAD) + if (slave->type != ARPHRD_FRAD) { + dev_put(slave); return(-EINVAL); + } /* check for registration */ for (i=0;i<sizeof(basename) / sizeof(char *); i++) @@ -424,33 +434,22 @@ int dlci_add(struct dlci_add *dlci) (strlen(dlci->devname) > strlen(basename[i]))) break; - if (i == sizeof(basename) / sizeof(char *)) + if (i == sizeof(basename) / sizeof(char *)) { + dev_put(slave); return(-EINVAL); - - /* check for too many open devices : should this be dynamic ? */ - for(i=0;i<CONFIG_DLCI_COUNT;i++) - if (!open_dev[i]) - break; - - if (i == CONFIG_DLCI_COUNT) - return(-ENOSPC); /* #### Alan: Comments on this?? */ + } /* create device name */ - sprintf(buf, "%s%02i", devname, i); - - master = kmalloc(sizeof(*master), GFP_KERNEL); - if (!master) + master = alloc_netdev( sizeof(struct dlci_local), "dlci%d", + dlci_setup); + if (!master) { + dev_put(slave); return(-ENOMEM); - - memset(master, 0, sizeof(*master)); - - strcpy(master->name, buf); - master->init = dlci_init; - master->flags = 0; + } err = register_netdev(master); - if (err < 0) - { + if (err < 0) { + dev_put(slave); kfree(master); return(err); } @@ -459,64 +458,65 @@ int dlci_add(struct dlci_add *dlci) dlp = (struct dlci_local *) master->priv; dlp->slave = slave; + dlp->master = master; flp = slave->priv; err = flp ? (*flp->assoc)(slave, master) : -EINVAL; if (err < 0) { unregister_netdev(master); - kfree(master->priv); - kfree(master); + dev_put(slave); + free_netdev(master); return(err); } - strcpy(dlci->devname, buf); - open_dev[i] = master; - MOD_INC_USE_COUNT; + strcpy(dlci->devname, master->name); + + spin_lock_bh(&dlci_dev_lock); + list_add(&dlp->list, &dlci_devs); + spin_unlock_bh(&dlci_dev_lock); + return(0); } -int dlci_del(struct dlci_add *dlci) +static int dlci_del(struct dlci_add *dlci) { struct dlci_local *dlp; struct frad_local *flp; - struct net_device *master, *slave; - int i, err; + struct net_device *master, *slave; + int err; /* validate slave device */ master = __dev_get_by_name(dlci->devname); if (!master) return(-ENODEV); - if (netif_running(master)) + if (netif_running(master)) { return(-EBUSY); + } dlp = master->priv; slave = dlp->slave; flp = slave->priv; err = (*flp->deassoc)(slave, master); - if (err) + if (err) return(err); - unregister_netdev(master); - for(i=0;i<CONFIG_DLCI_COUNT;i++) - if (master == open_dev[i]) - break; + spin_lock_bh(&dlci_dev_lock); + list_del(&dlp->list); + spin_unlock_bh(&dlci_dev_lock); - if (i<CONFIG_DLCI_COUNT) - open_dev[i] = NULL; + unregister_netdev(master); - kfree(master->priv); + dev_put(slave); free_netdev(master); - MOD_DEC_USE_COUNT; - return(0); } -int dlci_ioctl(unsigned int cmd, void *arg) +static int dlci_ioctl(unsigned int cmd, void *arg) { struct dlci_add add; int err; @@ -548,16 +548,9 @@ int dlci_ioctl(unsigned int cmd, void *arg) return(err); } -int dlci_init(struct net_device *dev) +static void dlci_setup(struct net_device *dev) { - struct dlci_local *dlp; - - dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL); - if (!dev->priv) - return(-ENOMEM); - - memset(dev->priv, 0, sizeof(struct dlci_local)); - dlp = dev->priv; + struct dlci_local *dlp = dev->priv; dev->flags = 0; dev->open = dlci_open; @@ -573,9 +566,7 @@ int dlci_init(struct net_device *dev) dev->type = ARPHRD_DLCI; dev->hard_header_len = sizeof(struct frhdr); dev->addr_len = sizeof(short); - memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); - return(0); } int __init init_dlci(void) @@ -584,9 +575,6 @@ int __init init_dlci(void) dlci_ioctl_set(dlci_ioctl); printk("%s.\n", version); - - for(i=0;i<CONFIG_DLCI_COUNT;i++) - open_dev[i] = NULL; for(i=0;i<sizeof(basename) / sizeof(char *);i++) basename[i] = NULL; @@ -596,7 +584,16 @@ int __init init_dlci(void) void __exit dlci_exit(void) { + struct dlci_local *dlp, *nxt; + dlci_ioctl_set(NULL); + + list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) { + unregister_netdev(dlp->master); + dev_put(dlp->slave); + free_netdev(dlp->master); + } + } module_init(init_dlci); diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 349400d4d95a..81b2f271036c 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -140,6 +140,7 @@ static void change_level( struct net_device * ); static void timeout_change_level( struct net_device * ); static u32 calc_crc32( u32, u8 *, u32 ); static struct sk_buff * get_rx_buf( struct net_device * ); +static int sbni_init( struct net_device * ); #ifdef CONFIG_SBNI_MULTILINE static int enslave( struct net_device *, struct net_device * ); @@ -205,23 +206,44 @@ sbni_isa_probe( struct net_device *dev ) } } - -int __init -sbni_probe( struct net_device *dev ) +static void __init sbni_devsetup(struct net_device *dev) { - int i; + ether_setup( dev ); + dev->init = &sbni_init; + dev->open = &sbni_open; + dev->stop = &sbni_close; + dev->hard_start_xmit = &sbni_start_xmit; + dev->get_stats = &sbni_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &sbni_ioctl; + + SET_MODULE_OWNER( dev ); +} +int __init sbni_probe(void) +{ + struct net_device *dev; static unsigned version_printed __initdata = 0; + if( version_printed++ == 0 ) printk( KERN_INFO "%s", version ); - if( !dev ) { /* simple sanity check */ - printk( KERN_ERR "sbni: NULL device!\n" ); - return -ENODEV; - } + dev = alloc_netdev(sizeof(struct net_local), "sbni%d", sbni_devsetup); + if (!dev) + return -ENOMEM; - SET_MODULE_OWNER( dev ); + netdev_boot_setup_check(dev); + + if (register_netdev(dev)) { + kfree(dev); + return -ENODEV; + } + return 0; +} +static int __init sbni_init(struct net_device *dev) +{ + int i; if( dev->base_addr ) return sbni_isa_probe( dev ); /* otherwise we have to perform search our adapter */ @@ -338,7 +360,7 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) dev->base_addr = ioaddr; /* Allocate dev->priv and fill in sbni-specific dev fields. */ - nl = (struct net_local *) kmalloc(sizeof(struct net_local), GFP_KERNEL); + nl = dev->priv; if( !nl ) { printk( KERN_ERR "%s: unable to get memory!\n", dev->name ); release_region( ioaddr, SBNI_IO_EXTENT ); @@ -389,14 +411,6 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) nl->link = NULL; #endif - dev->open = &sbni_open; - dev->stop = &sbni_close; - dev->hard_start_xmit = &sbni_start_xmit; - dev->get_stats = &sbni_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &sbni_ioctl; - ether_setup( dev ); - sbni_cards[ num++ ] = dev; return dev; } @@ -1478,15 +1492,15 @@ init_module( void ) struct net_device *dev; while( num < SBNI_MAX_NUM_CARDS ) { - if( !(dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) ){ + dev = alloc_netdev(sizeof(struct net_local), + "sbni%d", sbni_devsetup); + if( !dev) { printk( KERN_ERR "sbni: unable to allocate device!\n" ); return -ENOMEM; } - memset( dev, 0, sizeof(struct net_device) ); sprintf( dev->name, "sbni%d", num ); - dev->init = sbni_probe; if( register_netdev( dev ) ) { kfree( dev ); break; @@ -1506,7 +1520,6 @@ cleanup_module( void ) if( (dev = sbni_cards[ num ]) != NULL ) { unregister_netdev( dev ); release_region( dev->base_addr, SBNI_IO_EXTENT ); - kfree( dev->priv ); free_netdev( dev ); } } diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 8079d8b5ddee..c91e59da2ed9 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -71,6 +71,8 @@ static unsigned int valid_mem[] __initdata = { 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000}; +static spinlock_t sdla_lock = SPIN_LOCK_UNLOCKED; + /********************************************************* * * these are the core routines that access the card itself @@ -79,10 +81,10 @@ static unsigned int valid_mem[] __initdata = { #define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW) -static void sdla_read(struct net_device *dev, int addr, void *buf, short len) +static void __sdla_read(struct net_device *dev, int addr, void *buf, short len) { - unsigned long flags; - char *temp, *base; + char *temp; + const void *base; int offset, bytes; temp = buf; @@ -90,13 +92,10 @@ static void sdla_read(struct net_device *dev, int addr, void *buf, short len) { offset = addr & SDLA_ADDR_MASK; bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len; - base = (void *) (dev->mem_start + offset); + base = (const void *) (dev->mem_start + offset); - save_flags(flags); - cli(); SDLA_WINDOW(dev, addr); memcpy(temp, base, bytes); - restore_flags(flags); addr += bytes; temp += bytes; @@ -104,10 +103,19 @@ static void sdla_read(struct net_device *dev, int addr, void *buf, short len) } } -static void sdla_write(struct net_device *dev, int addr, void *buf, short len) +static void sdla_read(struct net_device *dev, int addr, void *buf, short len) { unsigned long flags; - char *temp, *base; + spin_lock_irqsave(&sdla_lock, flags); + __sdla_read(dev, addr, buf, len); + spin_unlock_irqrestore(&sdla_lock, flags); +} + +static void __sdla_write(struct net_device *dev, int addr, + const void *buf, short len) +{ + const char *temp; + void *base; int offset, bytes; temp = buf; @@ -116,17 +124,27 @@ static void sdla_write(struct net_device *dev, int addr, void *buf, short len) offset = addr & SDLA_ADDR_MASK; bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len; base = (void *) (dev->mem_start + offset); - save_flags(flags); - cli(); + SDLA_WINDOW(dev, addr); memcpy(base, temp, bytes); - restore_flags(flags); + addr += bytes; temp += bytes; len -= bytes; } } +static void sdla_write(struct net_device *dev, int addr, + const void *buf, short len) +{ + unsigned long flags; + + spin_lock_irqsave(&sdla_lock, flags); + __sdla_write(dev, addr, buf, len); + spin_unlock_irqrestore(&sdla_lock, flags); +} + + static void sdla_clear(struct net_device *dev) { unsigned long flags; @@ -138,8 +156,7 @@ static void sdla_clear(struct net_device *dev) bytes = SDLA_WINDOW_SIZE; base = (void *) dev->mem_start; - save_flags(flags); - cli(); + spin_lock_irqsave(&sdla_lock, flags); while(len) { SDLA_WINDOW(dev, addr); @@ -148,7 +165,8 @@ static void sdla_clear(struct net_device *dev) addr += bytes; len -= bytes; } - restore_flags(flags); + spin_unlock_irqrestore(&sdla_lock, flags); + } static char sdla_byte(struct net_device *dev, int addr) @@ -158,11 +176,10 @@ static char sdla_byte(struct net_device *dev, int addr) temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK)); - save_flags(flags); - cli(); + spin_lock_irqsave(&sdla_lock, flags); SDLA_WINDOW(dev, addr); byte = *temp; - restore_flags(flags); + spin_unlock_irqrestore(&sdla_lock, flags); return(byte); } @@ -414,7 +431,8 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, struct frad_local *flp; struct sdla_cmd *cmd_buf; unsigned long pflags; - int jiffs, ret, waiting, len; + unsigned long jiffs; + int ret, waiting, len; long window; flp = dev->priv; @@ -423,8 +441,8 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, ret = 0; len = 0; jiffs = jiffies + HZ; /* 1 second is plenty */ - save_flags(pflags); - cli(); + + spin_lock_irqsave(&sdla_lock, pflags); SDLA_WINDOW(dev, window); cmd_buf->cmd = cmd; cmd_buf->dlci = dlci; @@ -436,7 +454,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, cmd_buf->length = inlen; cmd_buf->opp_flag = 1; - restore_flags(pflags); + spin_unlock_irqrestore(&sdla_lock, pflags); waiting = 1; len = 0; @@ -444,18 +462,17 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, { if (waiting++ % 3) { - save_flags(pflags); - cli(); + spin_lock_irqsave(&sdla_lock, pflags); SDLA_WINDOW(dev, window); waiting = ((volatile int)(cmd_buf->opp_flag)); - restore_flags(pflags); + spin_unlock_irqrestore(&sdla_lock, pflags); } } if (!waiting) { - save_flags(pflags); - cli(); + + spin_lock_irqsave(&sdla_lock, pflags); SDLA_WINDOW(dev, window); ret = cmd_buf->retval; len = cmd_buf->length; @@ -471,7 +488,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, if (ret) memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len); - restore_flags(pflags); + spin_unlock_irqrestore(&sdla_lock, pflags); } else ret = SDLA_RET_TIMEOUT; @@ -555,7 +572,6 @@ int sdla_assoc(struct net_device *slave, struct net_device *master) if (i == CONFIG_DLCI_MAX) return(-EMLINK); /* #### Alan: Comments on this ?? */ - MOD_INC_USE_COUNT; flp->master[i] = master; flp->dlci[i] = -*(short *)(master->dev_addr); @@ -588,7 +604,6 @@ int sdla_deassoc(struct net_device *slave, struct net_device *master) flp->master[i] = NULL; flp->dlci[i] = 0; - MOD_DEC_USE_COUNT; if (netif_running(slave)) { if (flp->config.station == FRAD_STATION_CPE) @@ -688,14 +703,14 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size); if (ret == SDLA_RET_OK) { - save_flags(flags); - cli(); + + spin_lock_irqsave(&sdla_lock, flags); SDLA_WINDOW(dev, addr); pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK)); - sdla_write(dev, pbuf->buf_addr, skb->data, skb->len); - SDLA_WINDOW(dev, addr); + __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len); + SDLA_WINDOW(dev, addr); pbuf->opp_flag = 1; - restore_flags(flags); + spin_unlock_irqrestore(&sdla_lock, flags); } break; } @@ -753,8 +768,7 @@ static void sdla_receive(struct net_device *dev) pbufi = NULL; pbuf = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&sdla_lock, flags); switch (flp->type) { @@ -821,7 +835,7 @@ static void sdla_receive(struct net_device *dev) case SDLA_S502A: case SDLA_S502E: if (success) - sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len); + __sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len); SDLA_WINDOW(dev, SDLA_502_RCV_BUF); cmd->opp_flag = 0; @@ -834,9 +848,9 @@ static void sdla_receive(struct net_device *dev) split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0; len2 = len - split; - sdla_read(dev, addr, skb_put(skb, len2), len2); + __sdla_read(dev, addr, skb_put(skb, len2), len2); if (split) - sdla_read(dev, buf_base, skb_put(skb, split), split); + __sdla_read(dev, buf_base, skb_put(skb, split), split); } /* increment the buffer we're looking at */ @@ -853,7 +867,7 @@ static void sdla_receive(struct net_device *dev) (*dlp->receive)(skb, master); } - restore_flags(flags); + spin_unlock_irqrestore(&sdla_lock, flags); } static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs) @@ -979,8 +993,6 @@ static int sdla_close(struct net_device *dev) netif_stop_queue(dev); - MOD_DEC_USE_COUNT; - return(0); } @@ -1082,8 +1094,6 @@ static int sdla_open(struct net_device *dev) netif_start_queue(dev); - MOD_INC_USE_COUNT; - return(0); } @@ -1614,19 +1624,30 @@ static struct net_device_stats *sdla_stats(struct net_device *dev) return(&flp->stats); } -int __init sdla_init(struct net_device *dev) +static void setup_sdla(struct net_device *dev) { + dev->flags = 0; + dev->type = 0xFFFF; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->mtu = SDLA_MAX_MTU; +} + +struct net_device * __init sdla_init(void) +{ + struct net_device *dev; struct frad_local *flp; + int err = -ENOMEM; - /* allocate the private data structure */ - flp = kmalloc(sizeof(struct frad_local), GFP_KERNEL); - if (!flp) - return(-ENOMEM); + dev = alloc_netdev(sizeof(struct frad_local), "sdla0", setup_sdla); + if (!dev) + goto out; - memset(flp, 0, sizeof(struct frad_local)); - dev->priv = flp; + SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); + + flp = dev->priv; - dev->flags = 0; dev->open = sdla_open; dev->stop = sdla_close; dev->do_ioctl = sdla_ioctl; @@ -1635,12 +1656,6 @@ int __init sdla_init(struct net_device *dev) dev->hard_start_xmit = sdla_transmit; dev->change_mtu = sdla_change_mtu; - dev->type = 0xFFFF; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->mtu = SDLA_MAX_MTU; - SET_MODULE_OWNER(dev); - flp->activate = sdla_activate; flp->deactivate = sdla_deactivate; flp->assoc = sdla_assoc; @@ -1652,7 +1667,14 @@ int __init sdla_init(struct net_device *dev) flp->timer.data = (unsigned long) dev; flp->timer.function = sdla_poll; - return(0); + err = register_netdev(dev); + if (err) + goto out1; + return dev; +out1: + kfree(dev); +out: + return ERR_PTR(err); } int __init sdla_c_setup(void) @@ -1663,10 +1685,7 @@ int __init sdla_c_setup(void) } #ifdef MODULE -static struct net_device sdla0 = { - .name = "sdla0", - .init = sdla_init -}; +static struct net_device *sdla0; #endif /* MODULE */ static int __init init_sdla(void) @@ -1675,7 +1694,9 @@ static int __init init_sdla(void) sdla_c_setup(); #ifdef MODULE - result = register_netdev(&sdla0); + sdla0 = sdla_init(); + if (IS_ERR(sdla0)) + result = PTR_ERR(sdla0); #endif return result; } @@ -1683,11 +1704,10 @@ static int __init init_sdla(void) static void __exit exit_sdla(void) { #ifdef MODULE - unregister_netdev(&sdla0); - if (sdla0.priv) - kfree(sdla0.priv); - if (sdla0.irq) - free_irq(sdla0.irq, &sdla0); + unregister_netdev(sdla0); + if (sdla0->irq) + free_irq(sdla0->irq, sdla0); + free_netdev(sdla0); #endif } diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 8a3328687d1f..c22ca46b0d81 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -577,7 +577,7 @@ err_out_free_res: #endif pci_release_regions(pdev); err_out_free_netdev: - kfree (dev); + free_netdev (dev); return -ENODEV; } |
