1 #include <stdint.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <gpxe/if_ether.h>
5 #include <gpxe/netdevice.h>
6 #include <gpxe/ethernet.h>
7 #include <gpxe/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 );
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 /* Mark as link up; legacy devices don't handle link state */
118 netdev_link_up ( netdev );
119
120 if ( ( rc = register_netdev ( netdev ) ) != 0 )
121 goto err_register;
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