patch-2.3.99-pre8 linux/drivers/net/skfp/skfddi.c
Next file: linux/drivers/net/tokenring/ibmtr.c
Previous file: linux/drivers/net/skfp/hwmtm.c
Back to the patch index
Back to the overall index
- Lines: 438
- Date:
Fri May 12 11:43:26 2000
- Orig file:
v2.3.99-pre7/linux/drivers/net/skfp/skfddi.c
- Orig date:
Thu May 11 15:30:07 2000
diff -u --recursive --new-file v2.3.99-pre7/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c
@@ -19,6 +19,9 @@
* Maintainers:
* CG Christoph Goos (cgoos@syskonnect.de)
*
+ * Contributors:
+ * DM David S. Miller
+ *
* Address all question to:
* linux@syskonnect.de
*
@@ -52,20 +55,20 @@
* 26-Oct-99 CG Fixed compilation error on 2.2.13
* 12-Nov-99 CG Source code release
* 22-Nov-99 CG Included in kernel source.
+ * 07-May-00 DM 64 bit fixes, new dma interface
*
* Compilation options (-Dxxx):
* DRIVERDEBUG print lots of messages to log file
* DUMPPACKETS print received/transmitted packets to logfile
*
- * Limitations:
- * I changed the driver to support memory mapped I/O, so it
- * might run on non-x86 architectures (not tested).
- * But the hardware module does not yet support 64 bit OS'es.
+ * Tested cpu architectures:
+ * - i386
+ * - sparc64
*/
/* Version information string - should be updated prior to */
/* each new release!!! */
-#define VERSION "2.05"
+#define VERSION "2.06"
static const char *boot_msg =
"SysKonnect FDDI PCI Adapter driver v" VERSION " for\n"
@@ -666,18 +669,28 @@
spin_lock_init(&bp->DriverLock);
+ // Allocate invalid frame
+ bp->LocalRxBuffer = pci_alloc_consistent(&bp->pdev, MAX_FRAME_SIZE, &bp->LocalRxBufferDMA);
+ if (!bp->LocalRxBuffer) {
+ printk("could not allocate mem for ");
+ printk("LocalRxBuffer: %d byte\n", MAX_FRAME_SIZE);
+ goto fail;
+ }
+
// Determine the required size of the 'shared' memory area.
bp->SharedMemSize = mac_drv_check_space();
PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize);
if (bp->SharedMemSize > 0) {
bp->SharedMemSize += 16; // for descriptor alignment
- bp->SharedMemAddr = kmalloc(bp->SharedMemSize, GFP_KERNEL);
+ bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev,
+ bp->SharedMemSize,
+ &bp->SharedMemDMA);
if (!bp->SharedMemSize) {
printk("could not allocate mem for ");
printk("hardware module: %ld byte\n",
bp->SharedMemSize);
- return (-1);
+ goto fail;
}
bp->SharedMemHeap = 0; // Nothing used yet.
@@ -693,7 +706,7 @@
PRINTK(KERN_INFO "mac_drv_init()..\n");
if (mac_drv_init(smc) != 0) {
PRINTK(KERN_INFO "mac_drv_init() failed.\n");
- return (-1);
+ goto fail;
}
read_address(smc, NULL);
PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
@@ -708,6 +721,21 @@
smt_reset_defaults(smc, 0);
return (0);
+
+fail:
+ if (bp->SharedMemAddr) {
+ pci_free_consistent(&bp->pdev,
+ bp->SharedMemSize,
+ bp->SharedMemAddr,
+ bp->SharedMemDMA);
+ bp->SharedMemAddr = NULL;
+ }
+ if (bp->LocalRxBuffer) {
+ pci_free_consistent(&bp->pdev, MAX_FRAME_SIZE,
+ bp->LocalRxBuffer, bp->LocalRxBufferDMA);
+ bp->LocalRxBuffer = NULL;
+ }
+ return (-1);
} // skfp_driver_init
@@ -1282,7 +1310,7 @@
* is contained in a single physically contiguous buffer
* in which the virtual address of the start of packet
* (skb->data) can be converted to a physical address
- * by using virt_to_bus().
+ * by using pci_map_single().
*
* We have an internal queue for packets we can not send
* immediately. Packets in this queue can be given to the
@@ -1378,6 +1406,7 @@
unsigned char fc;
int queue;
struct s_smt_fp_txd *txd; // Current TxD.
+ dma_addr_t dma_address;
unsigned long Flags;
int frame_status; // HWM tx frame status.
@@ -1442,13 +1471,18 @@
txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue);
+ dma_address = pci_map_single(&bp->pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
if (frame_status & LAN_TX) {
- txd->txd_os.skb = skb; // save skb
+ txd->txd_os.skb = skb; // save skb
+ txd->txd_os.dma_addr = dma_address; // save dma mapping
}
- hwm_tx_frag(smc, skb->data, virt_to_bus(skb->data), skb->len,
+ hwm_tx_frag(smc, skb->data, dma_address, skb->len,
frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF);
if (!(frame_status & LAN_TX)) { // local only frame
+ pci_unmap_single(&bp->pdev, dma_address,
+ skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
}
spin_unlock_irqrestore(&bp->DriverLock, Flags);
@@ -1571,7 +1605,7 @@
{
void *virt;
- PRINTK(KERN_INFO "mac_drv_get_space\n");
+ PRINTK(KERN_INFO "mac_drv_get_space (%d bytes), ", size);
virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap);
if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) {
@@ -1581,8 +1615,10 @@
smc->os.SharedMemHeap += size; // Move heap pointer.
PRINTK(KERN_INFO "mac_drv_get_space end\n");
- PRINTK(KERN_INFO "virt addr: %08lx\n", (ulong) virt);
- PRINTK(KERN_INFO "bus addr: %08lx\n", (ulong) virt_to_bus(virt));
+ PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt);
+ PRINTK(KERN_INFO "bus addr: %lx\n", (ulong)
+ (smc->os.SharedMemDMA +
+ ((char *) virt - (char *)smc->os.SharedMemAddr)));
return (virt);
} // mac_drv_get_space
@@ -1616,7 +1652,7 @@
virt = mac_drv_get_space(smc, size);
- size = (u_int) ((0 - (unsigned int) virt) & 15);
+ size = (u_int) ((0 - (unsigned long) virt) & 15UL);
PRINTK("Allocate %u bytes alignment gap ", size);
PRINTK("for descriptor memory.\n");
@@ -1644,7 +1680,8 @@
************************/
unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
{
- return virt_to_bus(virt);
+ return (smc->os.SharedMemDMA +
+ ((char *) virt - (char *)smc->os.SharedMemAddr));
} // mac_drv_virt2phys
@@ -1657,7 +1694,8 @@
* for the DMA transfer, it should do it in this function.
*
* The hardware module calls this dma_master if it wants to send an SMT
- * frame.
+ * frame. This means that the virt address passed in here is part of
+ * the 'shared' memory area.
* Args
* smc - A pointer to the SMT context struct.
*
@@ -1677,7 +1715,8 @@
************************/
u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
{
- return (virt_to_bus(virt));
+ return (smc->os.SharedMemDMA +
+ ((char *) virt - (char *)smc->os.SharedMemAddr));
} // dma_master
@@ -1704,7 +1743,31 @@
************************/
void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag)
{
- return;
+ /* For TX buffers, there are two cases. If it is an SMT transmit
+ * buffer, there is nothing to do since we use consistent memory
+ * for the 'shared' memory area. The other case is for normal
+ * transmit packets given to us by the networking stack, and in
+ * that case we cleanup the PCI DMA mapping in mac_drv_tx_complete
+ * below.
+ *
+ * For RX buffers, we have to unmap dynamic PCI DMA mappings here
+ * because the hardware module is about to potentially look at
+ * the contents of the buffer. If we did not call the PCI DMA
+ * unmap first, the hardware module could read inconsistent data.
+ */
+ if (flag & DMA_WR) {
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+ volatile struct s_smt_fp_rxd *r = &descr->r;
+
+ /* If SKB is NULL, we used the local buffer. */
+ if (r->rxd_os.skb && r->rxd_os.dma_addr) {
+ int MaxFrameSize = bp->MaxFrameSize;
+
+ pci_unmap_single(&bp->pdev, r->rxd_os.dma_addr,
+ MaxFrameSize, PCI_DMA_FROMDEVICE);
+ r->rxd_os.dma_addr = 0;
+ }
+ }
} // dma_complete
@@ -1735,6 +1798,11 @@
}
txd->txd_os.skb = NULL;
+ // release the DMA mapping
+ pci_unmap_single(&smc->os.pdev, txd->txd_os.dma_addr,
+ skb->len, PCI_DMA_TODEVICE);
+ txd->txd_os.dma_addr = 0;
+
smc->os.MacStat.tx_packets++; // Count transmitted packets.
smc->os.MacStat.tx_bytes+=skb->len; // Count bytes
@@ -1823,6 +1891,8 @@
}
virt = skb->data;
+ // The DMA mapping was released in dma_complete above.
+
dump_data(skb->data, len);
/*
@@ -1923,7 +1993,7 @@
struct sk_buff *skb;
int MaxFrameSize;
unsigned char *v_addr;
- unsigned long b_addr;
+ dma_addr_t b_addr;
if (frag_count != 1) // This is not allowed to happen.
@@ -1939,25 +2009,34 @@
if (skb == NULL) { // this should not happen
PRINTK("Requeue with no skb in rxd!\n");
- skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+ skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC);
if (skb) {
// we got a skb
rxd->rxd_os.skb = skb;
+ skb_reserve(skb, 3);
skb_put(skb, MaxFrameSize);
v_addr = skb->data;
- b_addr = virt_to_bus(v_addr);
+ b_addr = pci_map_single(&smc->os.pdev,
+ v_addr,
+ MaxFrameSize,
+ PCI_DMA_FROMDEVICE);
+ rxd->rxd_os.dma_addr = b_addr;
} else {
// no skb available, use local buffer
PRINTK("Queueing invalid buffer!\n");
rxd->rxd_os.skb = NULL;
v_addr = smc->os.LocalRxBuffer;
- b_addr = virt_to_bus(v_addr);
+ b_addr = smc->os.LocalRxBufferDMA;
}
} else {
// we use skb from old rxd
rxd->rxd_os.skb = skb;
v_addr = skb->data;
- b_addr = virt_to_bus(v_addr);
+ b_addr = pci_map_single(&smc->os.pdev,
+ v_addr,
+ MaxFrameSize,
+ PCI_DMA_FROMDEVICE);
+ rxd->rxd_os.dma_addr = b_addr;
}
hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
FIRST_FRAG | LAST_FRAG);
@@ -2002,12 +2081,17 @@
PRINTK(KERN_INFO ".\n");
rxd = HWM_GET_CURR_RXD(smc);
- skb = alloc_skb(MaxFrameSize, GFP_ATOMIC);
+ skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC);
if (skb) {
// we got a skb
+ skb_reserve(skb, 3);
skb_put(skb, MaxFrameSize);
v_addr = skb->data;
- b_addr = virt_to_bus(v_addr);
+ b_addr = pci_map_single(&smc->os.pdev,
+ v_addr,
+ MaxFrameSize,
+ PCI_DMA_FROMDEVICE);
+ rxd->rxd_os.dma_addr = b_addr;
} else {
// no skb available, use local buffer
// System has run out of buffer memory, but we want to
@@ -2016,7 +2100,7 @@
// so data in it must be considered invalid.
PRINTK("Queueing invalid buffer!\n");
v_addr = smc->os.LocalRxBuffer;
- b_addr = virt_to_bus(v_addr);
+ b_addr = smc->os.LocalRxBufferDMA;
}
rxd->rxd_os.skb = skb;
@@ -2060,6 +2144,12 @@
for (; frag_count > 0; frag_count--) {
skb = rxd->rxd_os.skb;
if (skb != NULL) {
+ skfddi_priv *bp = (skfddi_priv *) & smc->os;
+ int MaxFrameSize = bp->MaxFrameSize;
+
+ pci_unmap_single(&bp->pdev, rxd->rxd_os.dma_addr,
+ MaxFrameSize, PCI_DMA_FROMDEVICE);
+
dev_kfree_skb(skb);
rxd->rxd_os.skb = NULL;
}
@@ -2111,11 +2201,12 @@
len, la_len, (unsigned long) look_ahead);
return (0);
}
- skb = alloc_skb(len, GFP_ATOMIC);
+ skb = alloc_skb(len + 3, GFP_ATOMIC);
if (!skb) {
PRINTK("fddi: Local SMT: skb memory exhausted.\n");
return (0);
}
+ skb_reserve(skb, 3);
skb_put(skb, len);
memcpy(skb->data, look_ahead, len);
@@ -2162,7 +2253,40 @@
************************/
void ring_status_indication(struct s_smc *smc, u_long status)
{
- PRINTK("ring_status_indication(%08lXh)\n", (unsigned long) status);
+ PRINTK("ring_status_indication( ");
+ if (status & RS_RES15)
+ PRINTK("RS_RES15 ");
+ if (status & RS_HARDERROR)
+ PRINTK("RS_HARDERROR ");
+ if (status & RS_SOFTERROR)
+ PRINTK("RS_SOFTERROR ");
+ if (status & RS_BEACON)
+ PRINTK("RS_BEACON ");
+ if (status & RS_PATHTEST)
+ PRINTK("RS_PATHTEST ");
+ if (status & RS_SELFTEST)
+ PRINTK("RS_SELFTEST ");
+ if (status & RS_RES9)
+ PRINTK("RS_RES9 ");
+ if (status & RS_DISCONNECT)
+ PRINTK("RS_DISCONNECT ");
+ if (status & RS_RES7)
+ PRINTK("RS_RES7 ");
+ if (status & RS_DUPADDR)
+ PRINTK("RS_DUPADDR ");
+ if (status & RS_NORINGOP)
+ PRINTK("RS_NORINGOP ");
+ if (status & RS_VERSION)
+ PRINTK("RS_VERSION ");
+ if (status & RS_STUCKBYPASSS)
+ PRINTK("RS_STUCKBYPASSS ");
+ if (status & RS_EVENT)
+ PRINTK("RS_EVENT ");
+ if (status & RS_RINGOPCHANGE)
+ PRINTK("RS_RINGOPCHANGE ");
+ if (status & RS_RES0)
+ PRINTK("RS_RES0 ");
+ PRINTK("]\n");
} // ring_status_indication
@@ -2261,9 +2385,18 @@
case SC7_WRAP_S:
s = "SC7_WRAP_S";
break;
- default:
- s = "unknown";
+ case SC9_C_WRAP_A:
+ s = "SC9_C_WRAP_A";
+ break;
+ case SC10_C_WRAP_B:
+ s = "SC10_C_WRAP_B";
+ break;
+ case SC11_C_WRAP_S:
+ s = "SC11_C_WRAP_S";
break;
+ default:
+ PRINTK(KERN_INFO "cfm_state_change: unknown %d\n", c_state);
+ return;
}
PRINTK(KERN_INFO "cfm_state_change: %s\n", s);
#endif // DRIVERDEBUG
@@ -2478,7 +2611,18 @@
next = lp->os.next_module;
if (lp->os.SharedMemAddr) {
- kfree(lp->os.SharedMemAddr);
+ pci_free_consistent(&lp->os.pdev,
+ lp->os.SharedMemSize,
+ lp->os.SharedMemAddr,
+ lp->os.SharedMemDMA);
+ lp->os.SharedMemAddr = NULL;
+ }
+ if (lp->os.LocalRxBuffer) {
+ pci_free_consistent(&lp->os.pdev,
+ MAX_FRAME_SIZE,
+ lp->os.LocalRxBuffer,
+ lp->os.LocalRxBufferDMA);
+ lp->os.LocalRxBuffer = NULL;
}
release_region(p->base_addr,
(lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0));
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)