1 #include <stdint.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <ipxe/if_ether.h>
5 #include <ipxe/netdevice.h>
6 #include <ipxe/ethernet.h>
7 #include <ipxe/iobuf.h>
8 #include <nic.h>
9 
10 /*
11  * Quick and dirty compatibility layer
12  *
13  * This should allow old-API PCI drivers to at least function until
14  * they are updated.  It will not help non-PCI drivers.
15  *
16  * No drivers should rely on this code.  It will be removed asap.
17  *
18  */
19 
20 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
21 
22 struct nic nic;
23 
24 static int legacy_registered = 0;
25 
legacy_transmit(struct net_device * netdev,struct io_buffer * iobuf)26 static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
27 	struct nic *nic = netdev->priv;
28 	struct ethhdr *ethhdr;
29 
30 	DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) );
31 	iob_pad ( iobuf, ETH_ZLEN );
32 	ethhdr = iobuf->data;
33 	iob_pull ( iobuf, sizeof ( *ethhdr ) );
34 	nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest,
35 				ntohs ( ethhdr->h_protocol ),
36 				iob_len ( iobuf ), iobuf->data );
37 	netdev_tx_complete ( netdev, iobuf );
38 	return 0;
39 }
40 
legacy_poll(struct net_device * netdev)41 static void legacy_poll ( struct net_device *netdev ) {
42 	struct nic *nic = netdev->priv;
43 	struct io_buffer *iobuf;
44 
45 	iobuf = alloc_iob ( ETH_FRAME_LEN );
46 	if ( ! iobuf )
47 		return;
48 
49 	nic->packet = iobuf->data;
50 	if ( nic->nic_op->poll ( nic, 1 ) ) {
51 		DBG ( "Received %d bytes\n", nic->packetlen );
52 		iob_put ( iobuf, nic->packetlen );
53 		netdev_rx ( netdev, iobuf );
54 	} else {
55 		free_iob ( iobuf );
56 	}
57 }
58 
legacy_open(struct net_device * netdev __unused)59 static int legacy_open ( struct net_device *netdev __unused ) {
60 	/* Nothing to do */
61 	return 0;
62 }
63 
legacy_close(struct net_device * netdev __unused)64 static void legacy_close ( struct net_device *netdev __unused ) {
65 	/* Nothing to do */
66 }
67 
legacy_irq(struct net_device * netdev __unused,int enable)68 static void legacy_irq ( struct net_device *netdev __unused, int enable ) {
69 	struct nic *nic = netdev->priv;
70 
71 	nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) );
72 }
73 
74 static struct net_device_operations legacy_operations = {
75 	.open		= legacy_open,
76 	.close		= legacy_close,
77 	.transmit	= legacy_transmit,
78 	.poll		= legacy_poll,
79 	.irq   		= legacy_irq,
80 };
81 
legacy_probe(void * hwdev,void (* set_drvdata)(void * hwdev,void * priv),struct device * dev,int (* probe)(struct nic * nic,void * hwdev),void (* disable)(struct nic * nic,void * hwdev))82 int legacy_probe ( void *hwdev,
83 		   void ( * set_drvdata ) ( void *hwdev, void *priv ),
84 		   struct device *dev,
85 		   int ( * probe ) ( struct nic *nic, void *hwdev ),
86 		   void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
87 	struct net_device *netdev;
88 	int rc;
89 
90 	if ( legacy_registered )
91 		return -EBUSY;
92 
93 	netdev = alloc_etherdev ( 0 );
94 	if ( ! netdev )
95 		return -ENOMEM;
96 	netdev_init ( netdev, &legacy_operations );
97 	netdev->priv = &nic;
98 	memset ( &nic, 0, sizeof ( nic ) );
99 	set_drvdata ( hwdev, netdev );
100 	netdev->dev = dev;
101 
102 	nic.node_addr = netdev->hw_addr;
103 	nic.irqno = dev->desc.irq;
104 
105 	if ( ! probe ( &nic, hwdev ) ) {
106 		rc = -ENODEV;
107 		goto err_probe;
108 	}
109 
110 	/* Overwrite the IRQ number.  Some legacy devices set
111 	 * nic->irqno to 0 in the probe routine to indicate that they
112 	 * don't support interrupts; doing this allows the timer
113 	 * interrupt to be used instead.
114 	 */
115 	dev->desc.irq = nic.irqno;
116 
117 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
118 		goto err_register;
119 
120 	/* Mark as link up; legacy devices don't handle link state */
121 	netdev_link_up ( netdev );
122 
123 	/* Do not remove this message */
124 	printf ( "WARNING: Using legacy NIC wrapper on %s\n",
125 		 netdev->ll_protocol->ntoa ( nic.node_addr ) );
126 
127 	legacy_registered = 1;
128 	return 0;
129 
130  err_register:
131 	disable ( &nic, hwdev );
132  err_probe:
133 	netdev_nullify ( netdev );
134 	netdev_put ( netdev );
135 	return rc;
136 }
137 
legacy_remove(void * hwdev,void * (* get_drvdata)(void * hwdev),void (* disable)(struct nic * nic,void * hwdev))138 void legacy_remove ( void *hwdev,
139 		     void * ( * get_drvdata ) ( void *hwdev ),
140 		     void ( * disable ) ( struct nic *nic, void *hwdev ) ) {
141 	struct net_device *netdev = get_drvdata ( hwdev );
142 	struct nic *nic = netdev->priv;
143 
144 	unregister_netdev ( netdev );
145 	disable ( nic, hwdev );
146 	netdev_nullify ( netdev );
147 	netdev_put ( netdev );
148 	legacy_registered = 0;
149 }
150 
dummy_connect(struct nic * nic __unused)151 int dummy_connect ( struct nic *nic __unused ) {
152 	return 1;
153 }
154 
dummy_irq(struct nic * nic __unused,irq_action_t irq_action __unused)155 void dummy_irq ( struct nic *nic __unused, irq_action_t irq_action __unused ) {
156 	return;
157 }
158